Browse Source

Se corrigio el problema de la firma vacia

master
mramirezg 3 months ago
commit
579e384fcd
74 changed files with 24469 additions and 0 deletions
  1. +22
    -0
      .gitignore
  2. +118
    -0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. +18
    -0
      .mvn/wrapper/maven-wrapper.properties
  5. +24
    -0
      LICENSE.md
  6. +45
    -0
      README.md
  7. +316
    -0
      mvnw
  8. +188
    -0
      mvnw.cmd
  9. +16716
    -0
      package-lock.json
  10. +113
    -0
      package.json
  11. +295
    -0
      pom.xml
  12. +32
    -0
      src/main/bundles/README.md
  13. BIN
      src/main/bundles/dev.bundle
  14. BIN
      src/main/bundles/prod.bundle
  15. +23
    -0
      src/main/frontend/index.html
  16. +20
    -0
      src/main/frontend/themes/sistema-mantenimiento/main-layout.css
  17. +294
    -0
      src/main/frontend/themes/sistema-mantenimiento/styles.css
  18. +3
    -0
      src/main/frontend/themes/sistema-mantenimiento/theme.json
  19. +28
    -0
      src/main/java/mx/gob/jumapacelaya/Application.java
  20. +337
    -0
      src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java
  21. +1
    -0
      src/main/java/mx/gob/jumapacelaya/api/SecurityService.java
  22. +13
    -0
      src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java
  23. +94
    -0
      src/main/java/mx/gob/jumapacelaya/controller/SecurityConfiguration.java
  24. +31
    -0
      src/main/java/mx/gob/jumapacelaya/datasource/MysqlDataSource.java
  25. +27
    -0
      src/main/java/mx/gob/jumapacelaya/datasource/OracleDataSource.java
  26. +87
    -0
      src/main/java/mx/gob/jumapacelaya/models/ActividadDiaria.java
  27. +27
    -0
      src/main/java/mx/gob/jumapacelaya/models/ActualizacioneSeguridadModel.java
  28. +84
    -0
      src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java
  29. +33
    -0
      src/main/java/mx/gob/jumapacelaya/models/DepartamentosModel.java
  30. +66
    -0
      src/main/java/mx/gob/jumapacelaya/models/DetalleMantenimientoModel.java
  31. +35
    -0
      src/main/java/mx/gob/jumapacelaya/models/HardwareDetalle.java
  32. +91
    -0
      src/main/java/mx/gob/jumapacelaya/models/MantCorrectivosModel.java
  33. +145
    -0
      src/main/java/mx/gob/jumapacelaya/models/PlanAnual.java
  34. +72
    -0
      src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java
  35. +1
    -0
      src/main/java/mx/gob/jumapacelaya/models/SignaturePad.java
  36. +153
    -0
      src/main/java/mx/gob/jumapacelaya/models/Ticket.java
  37. +34
    -0
      src/main/java/mx/gob/jumapacelaya/models/TiposHardware.java
  38. +32
    -0
      src/main/java/mx/gob/jumapacelaya/models/TiposMantenimiento.java
  39. +43
    -0
      src/main/java/mx/gob/jumapacelaya/models/Usuario.java
  40. +899
    -0
      src/main/java/mx/gob/jumapacelaya/services/DatabaseService.java
  41. +48
    -0
      src/main/java/mx/gob/jumapacelaya/services/EmailService.java
  42. +46
    -0
      src/main/java/mx/gob/jumapacelaya/services/LdapService.java
  43. +41
    -0
      src/main/java/mx/gob/jumapacelaya/services/ReportService.java
  44. +30
    -0
      src/main/java/mx/gob/jumapacelaya/services/SecurityService.java
  45. +89
    -0
      src/main/java/mx/gob/jumapacelaya/services/UserService.java
  46. +223
    -0
      src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java
  47. +607
    -0
      src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java
  48. +109
    -0
      src/main/java/mx/gob/jumapacelaya/ui/MainLayout.java
  49. +693
    -0
      src/main/java/mx/gob/jumapacelaya/ui/MantCorrectivoView.java
  50. +853
    -0
      src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java
  51. +950
    -0
      src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java
  52. +106
    -0
      src/main/java/mx/gob/jumapacelaya/ui/login/LoginView.java
  53. BIN
      src/main/resources/META-INF/resources/icons/icon.png
  54. BIN
      src/main/resources/META-INF/resources/images/1024x768.png
  55. BIN
      src/main/resources/META-INF/resources/images/900x160.png
  56. BIN
      src/main/resources/META-INF/resources/images/960X960_Nvo.png
  57. BIN
      src/main/resources/META-INF/resources/images/FirmaGerenteTI.png
  58. BIN
      src/main/resources/META-INF/resources/images/LOGO_1080X1024.png
  59. BIN
      src/main/resources/META-INF/resources/images/LOGO_24'27.png
  60. BIN
      src/main/resources/META-INF/resources/images/LOGO_900X160.png
  61. BIN
      src/main/resources/META-INF/resources/images/NVO_JUMAPA.png
  62. BIN
      src/main/resources/META-INF/resources/images/bckgndNvo.png
  63. BIN
      src/main/resources/META-INF/resources/images/empty-plant.png
  64. BIN
      src/main/resources/META-INF/resources/images/imgCorreo/correoMantt.png
  65. BIN
      src/main/resources/META-INF/resources/reportes/listadoMantenimientos.jasper
  66. BIN
      src/main/resources/META-INF/resources/reportes/mantenimientoFechas.jasper
  67. BIN
      src/main/resources/META-INF/resources/reportes/mantenimientoReport.jasper
  68. +4
    -0
      src/main/resources/application-dev.properties
  69. +5
    -0
      src/main/resources/application-prod.properties
  70. +34
    -0
      src/main/resources/application.properties
  71. +6
    -0
      src/main/resources/banner.txt
  72. +39
    -0
      tsconfig.json
  73. +17
    -0
      types.d.ts
  74. +9
    -0
      vite.config.ts

+ 22
- 0
.gitignore View File

@ -0,0 +1,22 @@
/target/
.idea/
.vscode/
.settings
.project
.classpath
*.iml
.DS_Store
# The following files are generated/updated by vaadin-maven-plugin
node_modules/
src/main/frontend/generated/
pnpmfile.js
vite.generated.ts
# Browser drivers for local integration tests
drivers/
# Error screenshots generated by TestBench for failed integration tests
error-screenshots/
webpack.generated.js
/bin/

+ 118
- 0
.mvn/wrapper/MavenWrapperDownloader.java View File

@ -0,0 +1,118 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.*;
import java.net.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is
* provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl
* property to use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download
* url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a
// custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if (mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if (mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if (!outputFile.getParentFile().exists()) {
if (!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

BIN
.mvn/wrapper/maven-wrapper.jar View File


+ 18
- 0
.mvn/wrapper/maven-wrapper.properties View File

@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

+ 24
- 0
LICENSE.md View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>

+ 45
- 0
README.md View File

@ -0,0 +1,45 @@
# Sistema de Mantenimiento
This project can be used as a starting point to create your own Vaadin application with Spring Boot.
It contains all the necessary configuration and some placeholder files to get you started.
## Running the application
The project is a standard Maven project. To run it from the command line,
type `mvnw` (Windows), or `./mvnw` (Mac & Linux), then open
http://localhost:8080 in your browser.
You can also import the project to your IDE of choice as you would with any
Maven project. Read more on [how to import Vaadin projects to different IDEs](https://vaadin.com/docs/latest/guide/step-by-step/importing) (Eclipse, IntelliJ IDEA, NetBeans, and VS Code).
## Deploying to Production
To create a production build, call `mvnw clean package -Pproduction` (Windows),
or `./mvnw clean package -Pproduction` (Mac & Linux).
This will build a JAR file with all the dependencies and front-end resources,
ready to be deployed. The file can be found in the `target` folder after the build completes.
Once the JAR file is built, you can run it using
`java -jar target/sistema-mantenimiento-1.0-SNAPSHOT.jar`
## Project structure
- `MainLayout.java` in `src/main/java` contains the navigation setup (i.e., the
side/top bar and the main menu). This setup uses
[App Layout](https://vaadin.com/docs/components/app-layout).
- `views` package in `src/main/java` contains the server-side Java views of your application.
- `views` folder in `src/main/frontend` contains the client-side JavaScript views of your application.
- `themes` folder in `src/main/frontend` contains the custom CSS styles.
## Useful links
- Read the documentation at [vaadin.com/docs](https://vaadin.com/docs).
- Follow the tutorial at [vaadin.com/docs/latest/tutorial/overview](https://vaadin.com/docs/latest/tutorial/overview).
- Create new projects at [start.vaadin.com](https://start.vaadin.com/).
- Search UI components and their usage examples at [vaadin.com/docs/latest/components](https://vaadin.com/docs/latest/components).
- View use case applications that demonstrate Vaadin capabilities at [vaadin.com/examples-and-demos](https://vaadin.com/examples-and-demos).
- Build any UI without custom CSS by discovering Vaadin's set of [CSS utility classes](https://vaadin.com/docs/styling/lumo/utility-classes).
- Find a collection of solutions to common use cases at [cookbook.vaadin.com](https://cookbook.vaadin.com/).
- Find add-ons at [vaadin.com/directory](https://vaadin.com/directory).
- Ask questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/vaadin) or join our [Discord channel](https://discord.gg/MYFq5RTbBn).
- Report issues, create pull requests in [GitHub](https://github.com/vaadin).

+ 316
- 0
mvnw View File

@ -0,0 +1,316 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 188
- 0
mvnw.cmd View File

@ -0,0 +1,188 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

+ 16716
- 0
package-lock.json
File diff suppressed because it is too large
View File


+ 113
- 0
package.json View File

@ -0,0 +1,113 @@
{
"name": "no-name",
"license": "UNLICENSED",
"type": "module",
"dependencies": {
"@polymer/polymer": "3.5.2",
"@vaadin/bundles": "24.5.5",
"@vaadin/common-frontend": "0.0.19",
"@vaadin/polymer-legacy-adapter": "24.5.5",
"@vaadin/react-components": "24.5.5",
"@vaadin/react-components-pro": "24.5.5",
"@vaadin/vaadin-development-mode-detector": "2.0.7",
"@vaadin/vaadin-lumo-styles": "24.5.5",
"@vaadin/vaadin-material-styles": "24.5.5",
"@vaadin/vaadin-themable-mixin": "24.5.5",
"@vaadin/vaadin-usage-statistics": "2.1.3",
"construct-style-sheets-polyfill": "3.1.0",
"date-fns": "2.29.3",
"lit": "3.2.1",
"proj4": "2.12.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-router-dom": "6.28.0",
"signature_pad": "4.1.5"
},
"devDependencies": {
"@babel/preset-react": "7.26.3",
"@preact/signals-react-transform": "0.4.0",
"@rollup/plugin-replace": "6.0.1",
"@rollup/pluginutils": "5.1.3",
"@types/react": "18.3.13",
"@types/react-dom": "18.3.1",
"@vitejs/plugin-react": "4.3.3",
"async": "3.2.6",
"glob": "10.4.5",
"rollup-plugin-brotli": "3.1.0",
"rollup-plugin-visualizer": "5.12.0",
"strip-css-comments": "5.0.0",
"transform-ast": "2.4.4",
"typescript": "5.6.3",
"vite": "5.4.11",
"vite-plugin-checker": "0.8.0",
"workbox-build": "7.3.0",
"workbox-core": "7.3.0",
"workbox-precaching": "7.3.0"
},
"vaadin": {
"dependencies": {
"@polymer/polymer": "3.5.2",
"@vaadin/bundles": "24.5.5",
"@vaadin/common-frontend": "0.0.19",
"@vaadin/polymer-legacy-adapter": "24.5.5",
"@vaadin/react-components": "24.5.5",
"@vaadin/react-components-pro": "24.5.5",
"@vaadin/vaadin-development-mode-detector": "2.0.7",
"@vaadin/vaadin-lumo-styles": "24.5.5",
"@vaadin/vaadin-material-styles": "24.5.5",
"@vaadin/vaadin-themable-mixin": "24.5.5",
"@vaadin/vaadin-usage-statistics": "2.1.3",
"construct-style-sheets-polyfill": "3.1.0",
"date-fns": "2.29.3",
"lit": "3.2.1",
"proj4": "2.12.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-router-dom": "6.28.0",
"signature_pad": "4.1.5"
},
"devDependencies": {
"@babel/preset-react": "7.26.3",
"@preact/signals-react-transform": "0.4.0",
"@rollup/plugin-replace": "6.0.1",
"@rollup/pluginutils": "5.1.3",
"@types/react": "18.3.13",
"@types/react-dom": "18.3.1",
"@vitejs/plugin-react": "4.3.3",
"async": "3.2.6",
"glob": "10.4.5",
"rollup-plugin-brotli": "3.1.0",
"rollup-plugin-visualizer": "5.12.0",
"strip-css-comments": "5.0.0",
"transform-ast": "2.4.4",
"typescript": "5.6.3",
"vite": "5.4.11",
"vite-plugin-checker": "0.8.0",
"workbox-build": "7.3.0",
"workbox-core": "7.3.0",
"workbox-precaching": "7.3.0"
},
"hash": "6126bd412c2a8696938f50edd1abae217c30c0119a0496af47b9d6ba1762921f"
},
"overrides": {
"@vaadin/bundles": "$@vaadin/bundles",
"@vaadin/polymer-legacy-adapter": "$@vaadin/polymer-legacy-adapter",
"@vaadin/vaadin-development-mode-detector": "$@vaadin/vaadin-development-mode-detector",
"@vaadin/vaadin-usage-statistics": "$@vaadin/vaadin-usage-statistics",
"@vaadin/react-components": "$@vaadin/react-components",
"@vaadin/react-components-pro": "$@vaadin/react-components-pro",
"@vaadin/common-frontend": "$@vaadin/common-frontend",
"react-dom": "$react-dom",
"construct-style-sheets-polyfill": "$construct-style-sheets-polyfill",
"react-router-dom": "$react-router-dom",
"lit": "$lit",
"@polymer/polymer": "$@polymer/polymer",
"react": "$react",
"date-fns": "$date-fns",
"proj4": "$proj4",
"@vaadin/vaadin-themable-mixin": "$@vaadin/vaadin-themable-mixin",
"@vaadin/vaadin-lumo-styles": "$@vaadin/vaadin-lumo-styles",
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
"signature_pad": "$signature_pad"
}
}

+ 295
- 0
pom.xml View File

@ -0,0 +1,295 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Project from https://start.vaadin.com/project/d0aaac74-a0be-4584-96f9-8bc2489b2c80 -->
<groupId>mx.gob.jumapacelaya</groupId>
<artifactId>sistema-mantenimiento</artifactId>
<name>sistema-mantenimiento</name>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<vaadin.version>24.5.8</vaadin.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.8</version>
</parent>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>Vaadin Directory</id>
<url>https://maven.vaadin.com/vaadin-addons</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>oracle-public</id>
<url>https://maven.oracle.com/public</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>${vaadin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<!-- Replace artifactId with vaadin-core to use only free components -->
<artifactId>vaadin</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.parttio</groupId>
<artifactId>line-awesome</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<!-- Dependencia para utilizar JDBC en la Base de Datos -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<!-- Conector a base de datos Oracle-->
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<!-- Dependencia para poder enviar correos -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-testbench-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.f0rce.signaturepad</groupId>
<artifactId>signature-widget</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>7.0.3</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-pdf</artifactId>
<version>7.0.3</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<build>
<defaultGoal>spring-boot:run</defaultGoal>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-frontend</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<!-- Production mode is activated using -Pproduction -->
<id>production</id>
<dependencies>
<!-- Exclude development dependencies from production -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-dev</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<goals>
<goal>build-frontend</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>it</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>start-spring-boot</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-spring-boot</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Runs the integration tests (*IT) after the server is started -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<trimStackTrace>false</trimStackTrace>
<enableAssertions>true</enableAssertions>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

+ 32
- 0
src/main/bundles/README.md View File

@ -0,0 +1,32 @@
This directory is automatically generated by Vaadin and contains the pre-compiled
frontend files/resources for your project (frontend development bundle).
It should be added to Version Control System and committed, so that other developers
do not have to compile it again.
Frontend development bundle is automatically updated when needed:
- an npm/pnpm package is added with @NpmPackage or directly into package.json
- CSS, JavaScript or TypeScript files are added with @CssImport, @JsModule or @JavaScript
- Vaadin add-on with front-end customizations is added
- Custom theme imports/assets added into 'theme.json' file
- Exported web component is added.
If your project development needs a hot deployment of the frontend changes,
you can switch Flow to use Vite development server (default in Vaadin 23.3 and earlier versions):
- set `vaadin.frontend.hotdeploy=true` in `application.properties`
- configure `vaadin-maven-plugin`:
```
<configuration>
<frontendHotdeploy>true</frontendHotdeploy>
</configuration>
```
- configure `jetty-maven-plugin`:
```
<configuration>
<systemProperties>
<vaadin.frontend.hotdeploy>true</vaadin.frontend.hotdeploy>
</systemProperties>
</configuration>
```
Read more [about Vaadin development mode](https://vaadin.com/docs/next/flow/configuration/development-mode#precompiled-bundle).

BIN
src/main/bundles/dev.bundle View File


BIN
src/main/bundles/prod.bundle View File


+ 23
- 0
src/main/frontend/index.html View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<!--
This file is auto-generated by Vaadin.
-->
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body, #outlet {
height: 100vh;
width: 100%;
margin: 0;
}
</style>
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
</head>
<body>
<!-- This outlet div is where the views are rendered -->
<div id="outlet"></div>
</body>
</html>

+ 20
- 0
src/main/frontend/themes/sistema-mantenimiento/main-layout.css View File

@ -0,0 +1,20 @@
vaadin-scroller[slot="drawer"] {
padding: var(--lumo-space-s);
}
vaadin-side-nav-item vaadin-icon {
padding: 0;
}
[slot="drawer"]:is(header, footer) {
display: flex;
align-items: center;
gap: var(--lumo-space-s);
padding: var(--lumo-space-s) var(--lumo-space-m);
min-height: var(--lumo-size-xl);
box-sizing: border-box;
}
[slot="drawer"]:is(header, footer):is(:empty) {
display: none;
}

+ 294
- 0
src/main/frontend/themes/sistema-mantenimiento/styles.css View File

@ -0,0 +1,294 @@
@import url('./main-layout.css');
/* ----------- Estilos para el MainLayout.java ----------- */
/* Estilos para el DrawerToggle*/
.drawer-toggle {
background-color: #bc955b;
}
/* Estilos para el encabezado */
.header-content {
height: 64px;
display: flex;
align-items: center;
width: 100%;
}
/* Estilo para el boton de cerrar sesion */
.logout-button {
margin-right: 30px;
}
/* Estilos para el drawer */
.drawer-logo {
width: 300px;
}
/* Estilos para el fondo de la aplicacion */
.app-layout {
background-image: url('/images/bckgndNvo.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* ------------------ FIN -------------------------------------- */
/*
/*
*/
/*!--------------------- Estilos para MantenimientosView.java ------------------- */
/* Estilo para el fondo del header */
.plan-anual-header {
background-color: #a02142;
padding: 0;
}
/* Estilo para el titulo */
.plan-anual-titulo {
text-align: center;
font-size: 24px;
color: #ddc9a3;
}
/* Estilo para el subtitulo */
.plan-anual-titulo1 {
text-align: center;
font-size: 18px;
color: #ddc9a3;
}
/* Estilo para el campo de texto nomenclatura */
.nomenclatura-txt {
margin-top: 15px;
margin-right: 15px;
}
/* Estilo para el logo CELAYA */
.celaya-logo {
width: 100px;
margin-left: 15px;
margin-top: 15px;
}
/* ------------------------ FIN -------------------------- */
/*
/*
*/
/* --------------- Estilos para la vista de ActDiaria.java -------------- */
/* Estilo para el header */
.act-diaria-header {
background-color: #3E8BEA;
padding: 10px;
}
/* Estilo para el titulo */
.act-diaria-titulo {
color: white;
font-size: 24px;
text-align: center;
}
/* Estilo para el grid */
.act-diaria-grid {
margin-top: 20px;
}
/* ---------------------------- FIN------------------------ */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* Estilos especificos para el TextField, TextArea y Fecha*/
vaadin-text-field::part(label), vaadin-text-area::part(label), vaadin-date-picker::part(label) {
color: #691b31; /* Color de la etiqueta */
}
vaadin-text-field::part(input-field), vaadin-text-area::part(input-field), vaadin-password-field::part(input-field),
vaadin-number-field::part(input-field), vaadin-date-picker::part(input-field) {
border: 1px solid #691b31; /* Color del borde */
color: #691b31; /* Color del texto */
}
vaadin-month-calendar::part(date) {
color: #691b31; /* Color para los dias del calendario */
}
vaadin-month-calendar::part(date):hover /* Estilos para cuando se posiciona el puntero sobre el dia */{
background-color: #a02142;
opacity: 50%;
border-radius: 5px;
}
vaadin-month-calendar::part(date focused) {
background-color: #ddc9a3; /* Color de la fecha seleccionada */
}
vaadin-date-picker-overlay-content > vaadin-button, vaadin-date-picker-year::part(year-number) {
color: #691b31;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* Estilos específicos para el Upload */
vaadin-upload > vaadin-button {
color: #691b31;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* Estilos específicos para el ComboBox */
vaadin-combo-box::part(input-field) {
background-color: #ddc9a3; /* Color de fondo */
color: #691b31; /* Color del texto */
border: 1px solid #691b31; /* Color del borde */
}
vaadin-combo-box::part(label) {
color: #691b31; /* Color de las etiquetas */
}
vaadin-combo-box::part(dropdown) {
background-color: rgba(221, 201, 163, 1); /* Color del fondo del dropdown */
}
vaadin-combo-box-item::part(checkmark)::before, vaadin-combo-box-item:hover
{
color: #691b31;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) INDICADOR DE CARGA DE LA APLICACION (*)(*) (*)(*) */
.v-loading-indicator { /* Cambiar el color de la barra de carga que sale cuando la aplicacion esta cargando */
background: #691b31 !important;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) ESTILOS PARA LA SIDEBAR (*)(*) (*)(*) */
vaadin-side-nav-item[aria-current="page"]::part(content) {
color: #691b31; /* Color de texto seleccionado */
}
vaadin-side-nav-item:hover::part(content) {
background-color: #ddc9a3; /* Color de fondo al hacer hover*/
fill-opacity: 50%;
border-radius: 5px;
}
vaadin-side-nav-item::part(content) {
color: #a02142; /* Color del texto deseado */
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/*Estilos especificos para el Grid */
vaadin-grid::part(selected-row-cell) {
background-color: #ddc9a3;
opacity: 100%;
}
vaadin-grid::part(selected-row) {
color: #691b31;
font-weight: bold;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/*Estilos especificos para los botones */
vaadin-button[theme~="primary"] {
background-color: #691b31;
}
vaadin-button:not([theme]) {
color: #a02142;
}
vaadin-button[theme~="tertiary-inline"], vaadin-button[theme~="icon"] {
color: #a02142;
}
/* Estilos para el theme personalizado 'subir-archivo' */
vaadin-button[theme~="subir-archivo"] {
background-color: #691b31;
color: #ffffff;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/*Estilos especificos para los CheckBox y RadioButtons */
vaadin-checkbox[checked]::part(checkbox) {
background-color: #691b31; /* Cambia el color del CheckBox */
}
vaadin-checkbox-group::part(label), vaadin-radio-group::part(label) {
color: #691b31;
}
vaadin-radio-button[checked]::part(radio) {
background-color: #691b31;
}
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) (*)(*) */
/* Estilo especificos para el login form */
vaadin-login-form.special, vaadin-login-form.special::part(container) {
background-color: rgba(105, 27, 49, 0.8);
border-radius: 30px;
}
vaadin-login-form-wrapper {
background-color: rgba(221, 201, 163, 1);
border-radius: 30px;
}
/*letras de los label*/
vaadin-login-form-wrapper ::part(label) {
color: #6f7271;
/*transform: scale(1.2);*/
}
vaadin-login-form vaadin-button[theme~="submit"] {
background-color: #691b31;
}
vaadin-login-form-wrapper::part(form-title) {
color: #691b31;
}
vaadin-login-form-wrapper::part(error-message) {
color: #a02142;
}
vaadin-popover-overlay::part(overlay) {
border-radius: 12px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
@media (max-width: 900px) {
.v-horizontallayout {
flex-direction: column !important;
align-items: stretch !important;
}
.mantenimiento-text-field,
.mantenimiento-combo,
vaadin-text-field,
vaadin-combo-box {
min-width: 0;
width: 100% !important;
box-sizing: border-box;
}
}

+ 3
- 0
src/main/frontend/themes/sistema-mantenimiento/theme.json View File

@ -0,0 +1,3 @@
{
"lumoImports" : [ "typography", "color", "spacing", "badge", "utility" ]
}

+ 28
- 0
src/main/java/mx/gob/jumapacelaya/Application.java View File

@ -0,0 +1,28 @@
package mx.gob.jumapacelaya;
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.server.PWA;
import com.vaadin.flow.theme.Theme;
import mx.gob.jumapacelaya.services.DatabaseService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
/**
* The entry point of the Spring Boot application.
*
* Use the @PWA annotation make the application installable on phones, tablets
* and some desktop browsers.
*
*/
@SpringBootApplication
@Theme(value = "sistema-mantenimiento")
@PWA(name = "Aplicacion de Mantenimiento de Equipo de Computo", shortName = "Mantenimiento de Computo", iconPath = "icons/icon.png")
public class Application implements AppShellConfigurator {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

+ 337
- 0
src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java View File

@ -0,0 +1,337 @@
package mx.gob.jumapacelaya.api;
import com.google.gson.*;
import mx.gob.jumapacelaya.models.RedmineUser;
import mx.gob.jumapacelaya.models.Ticket;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class RedmineClient {
private static final int PAGE_SIZE = 25;
static String REDMINE_URL;
static String API_KEY;
public static final Gson GSON = new Gson();
public RedmineClient(@Value("${redmine.url}") String redmineUrl, @Value("${redmine.api_key}") String apiKey) {
REDMINE_URL = redmineUrl;
API_KEY = apiKey;
}
//AQUI OBTENGO LOS TICKETS DESDE REDMINE
public List<Ticket> getTickets(RedmineUser user, boolean includeClosed) {
List<Ticket> tickets = new ArrayList<>();
HttpClient client = HttpClient.newHttpClient();
int offset = 0;
// Si includeClose es true, incluira todos los tikets si no, incluira solo los que estan abiertos
String statusFilter = includeClosed ? "&status_id=*" : "&status_id=open";
while (true) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + statusFilter + "&offset=" + offset))
.header("Content-Type", "application/json")
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String responseBody = response.body();
List<Ticket> pageTickets = parseTickets(responseBody);
tickets.addAll(pageTickets);
if (pageTickets.size() < PAGE_SIZE) {
break;
}
offset += PAGE_SIZE;
} else {
System.err.println("Error en la respuesta: " + response.statusCode());
break;
}
} catch (Exception e) {
e.printStackTrace();
break;
}
}
System.out.println("Total tickets obtenidos: " + tickets.size());
return tickets;
}
//AQUI OBTENGO LOS TICKETS DESDE REDMINE
public List<Ticket> getTicketsAuthor(RedmineUser user, boolean includeClosed) {
List<Ticket> tickets = new ArrayList<>();
HttpClient client = HttpClient.newHttpClient();
int offset = 0;
// Si includeClose es true, incluira todos los tikets si no, incluira solo los que estan abiertos
String statusFilter = includeClosed ? "&status_id=*" : "&status_id=open";
while (true) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + "&author_id=" + user.getId() + statusFilter + "&offset=" + offset))
.header("Content-Type", "application/json")
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String responseBody = response.body();
List<Ticket> pageTickets = parseTickets(responseBody);
tickets.addAll(pageTickets);
if (pageTickets.size() < PAGE_SIZE) {
break;
}
offset += PAGE_SIZE;
} else {
System.err.println("Error en la respuesta: " + response.statusCode());
break;
}
} catch (Exception e) {
e.printStackTrace();
break;
}
}
System.out.println("Total tickets obtenidos: " + tickets.size());
return tickets;
}
// Aquí se parsean todos los tickets que existen y se les da un formato con los campos a mostrarse
private List<Ticket> parseTickets(String json) {
List<Ticket> tickets = new ArrayList<>();
try {
JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
JsonArray issues = jsonObject.getAsJsonArray("issues");
if (issues != null) {
for (JsonElement issueElement : issues) {
JsonObject issue = issueElement.getAsJsonObject();
// Verifica y obtiene el ID
int id = issue.has("id") && !issue.get("id").isJsonNull() ? issue.get("id").getAsInt() : 0;
// Verifica y obtiene el subject
String subject = issue.has("subject") && !issue.get("subject").isJsonNull() ? issue.get("subject").getAsString() : "";
// Verifica y obtiene la descripción
String description = issue.has("description") && !issue.get("description").isJsonNull() ? issue.get("description").getAsString() : "";
// Verifica y obtiene el status
String status = "Unknown";
if (issue.has("status") && !issue.get("status").isJsonNull()) {
JsonObject statusObject = issue.getAsJsonObject("status");
if (statusObject.has("name") && !statusObject.get("name").isJsonNull()) {
status = statusObject.get("name").getAsString();
}
}
// Verifica y obtiene la fecha de creación
String dateString = issue.has("created_on") && !issue.get("created_on").isJsonNull() ? issue.get("created_on").getAsString() : "";
LocalDate dateCreate = null;
if (!dateString.isEmpty()) {
try {
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
dateCreate = LocalDate.parse(dateString, formatter);
} catch (DateTimeParseException e) {
System.err.println("Error al parsear la fecha: " + dateString);
e.printStackTrace();
}
}
// Verifica y obtiene la fecha de cierre
String closeDateString = issue.has("closed_on") && !issue.get("closed_on").isJsonNull() ? issue.get("closed_on").getAsString() : "";
LocalDate dateClose = null;
if (!closeDateString.isEmpty()) {
try {
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
dateClose = LocalDate.parse(closeDateString, formatter);
} catch (DateTimeParseException e) {
System.err.println("Error al parsear la fecha de cierre: " + closeDateString);
e.printStackTrace();
}
}
//Verifica y obtiene el ID del tipo de ticket
Integer trackerId = null;
if (issue.has("tracker") && !issue.get("tracker").isJsonNull()) {
JsonObject trackerObject = issue.getAsJsonObject("tracker");
if (trackerObject.has("id") && !trackerObject.get("id").isJsonNull()) {
trackerId = trackerObject.get("id").getAsInt();
}
}
// Agrega el ticket a la lista
tickets.add(new Ticket(id, subject, description, status,
dateCreate != null ? dateCreate.toString() : "",
dateClose != null ? dateClose.toString() : "",
trackerId, "Tipo Desconocido"));
}
} else {
System.out.println("La respuesta JSON no contiene la clave 'issues'");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Ocurrió un error al parsear los tickets: " + e.getMessage());
}
return tickets;
}
public RedmineUser getMyAccount(String username) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/my/account.json"))
.header("Content-Type", "application/json")
.header("X-Redmine-Switch-User", username)
.header("X-Redmine-API-Key", API_KEY)
.GET()
.build();
try {
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject();
JsonObject userJson = jsonObject.get("user").getAsJsonObject();
RedmineUser user = new RedmineUser();
user.setId(userJson.get("id").getAsInt());
user.setLogin(userJson.get("login").getAsString());
user.setFirstname(userJson.get("firstname").getAsString());
user.setLastname(userJson.get("lastname").getAsString());
user.setMail(userJson.get("mail").getAsString());
user.setKey(userJson.get("api_key").getAsString());
return user;
//return response.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return null;
}
}
public static RedmineUser createRedmineUser(String username, String firstname, String lastname, String mail) {
HttpClient client = HttpClient.newHttpClient();
Map<String, Object> user = new HashMap<>();
user.put("login", username);
user.put("firstname", firstname);
user.put("lastname", lastname);
user.put("mail", mail);
user.put("auth_source_id", "1");
Map<String, Object> payload = new HashMap<>();
payload.put("user", user);
String jsonPayload = new Gson().toJson(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/users.json"))
.header("Content-Type", "application/json")
.header("X-Redmine-API-Key", API_KEY)
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject();
JsonObject userJson = jsonObject.get("user").getAsJsonObject();
RedmineUser newUser = new RedmineUser();
newUser.setId(userJson.get("id").getAsInt());
newUser.setLogin(userJson.get("login").getAsString());
newUser.setFirstname(userJson.get("firstname").getAsString());
newUser.setLastname(userJson.get("lastname").getAsString());
newUser.setMail(userJson.get("mail").getAsString());
return newUser;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//AQUI OBTENGO A LOS USUARIOS
//Se devuelven en formato Json
public RedmineUser getUserByUsername(String username) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/users.json?name=" + username ))
.header("Content-Type", "application/json")
.header("X-Redmine-API-Key", API_KEY)
.build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
String responseBody = response.body();
System.out.println("Datos del usuario " + responseBody);
return parseUser(responseBody);
} else {
System.err.println("Error en la respuesta: " + response.statusCode());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//Aqui se parsean a los usuarios y se les da un formato con los campos a mostrarse
private RedmineUser parseUser(String json) {
JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
JsonObject userJson = jsonObject.getAsJsonArray("users").get(0).getAsJsonObject();
RedmineUser user = new RedmineUser();
user.setId(userJson.get("id").getAsInt());
user.setLogin(userJson.get("login").getAsString());
user.setFirstname(userJson.get("firstname").getAsString());
user.setLastname(userJson.get("lastname").getAsString());
user.setMail(userJson.get("mail").getAsString());
//user.setKey(userJson.get("key").getAsString());
return user;
}
/*Este metodo sirve para actualizar el estatus de los tickets
en este caso se actualiza al estatus TERMINADO */
public void closeTicket(int ticketId, RedmineUser user) throws IOException, InterruptedException {
int closedStatusId = 5; //este es el ID del estado TERMINADO, se debe poner el id a según corresponda
Map<String, Object> payload = new HashMap<>();
Map<String, Object> issue = new HashMap<>();
issue.put("status_id", closedStatusId);
payload.put("issue", issue);
String jsonPayload = GSON.toJson(payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(REDMINE_URL + "/issues/" + ticketId + ".json?key=" + user.getKey()))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 204) {
String responseBody = response.body();
System.out.println("Ticket " + ticketId + " cerrado correctamente.");
} else {
System.err.println("Error al cerrar el ticket: " + response.statusCode());
System.err.println(response.body());
}
}
}

+ 1
- 0
src/main/java/mx/gob/jumapacelaya/api/SecurityService.java View File

@ -0,0 +1 @@
package mx.gob.jumapacelaya.api;

+ 13
- 0
src/main/java/mx/gob/jumapacelaya/api/ServerProperties.java View File

@ -0,0 +1,13 @@
package mx.gob.jumapacelaya.api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ServerProperties {
@Value("${redmine.url}")
public String REDMINE_URL;
@Value("${redmine.api_key}")
public String API_KEY;
}

+ 94
- 0
src/main/java/mx/gob/jumapacelaya/controller/SecurityConfiguration.java View File

@ -0,0 +1,94 @@
package mx.gob.jumapacelaya.controller;
import com.vaadin.flow.spring.security.VaadinWebSecurity;
import mx.gob.jumapacelaya.ui.login.LoginView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.ldap.core.support.LdapContextSource;
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends VaadinWebSecurity {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(
AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/icons/*.png"),
AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/images/*.png")
).permitAll()
.requestMatchers(
AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/login*")
).permitAll()
);
super.configure(http);
setLoginView(http, LoginView.class);
}
// !Esta es la real autenticacion con ldap
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider("JUMAPACELAYA.GOB.MX", "ldap://172.16.0.1");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
auth.authenticationProvider(provider);
}
// !Autenticacion local solo para que lo vea el departamento de calidad
/*@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// Configura la autenticación en memoria con un usuario local
auth.inMemoryAuthentication()
.withUser("admin")
.password("{noop}admin") // {noop} indica que la contraseña no está cifrada (solo para pruebas)
.roles("ADMIN")
.and()
.withUser("jlermal")
.password("{noop}Temporal1")
.roles("USER")
.and()
.withUser("mramirezg")
.password("{noop}Temporal1")
.roles("ADMIN");
}*/
@Value("${spring.ldap.urls}")
private String ldapUrls;
@Value("${spring.ldap.base}")
private String ldapBase;
@Value("${spring.ldap.password}")
private String ldapPassword;
@Bean
public LdapContextSource ldapContextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(ldapUrls);
contextSource.setBase(ldapBase);
contextSource.setUserDn("administrator");
contextSource.setPassword(ldapPassword);
contextSource.setPooled(true);
contextSource.setReferral("follow");
return contextSource;
}
}

+ 31
- 0
src/main/java/mx/gob/jumapacelaya/datasource/MysqlDataSource.java View File

@ -0,0 +1,31 @@
package mx.gob.jumapacelaya.datasource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
public class MysqlDataSource {
@Bean(name= "mysqlDB")
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "mysqlJdbcTemplate")
@Autowired
public JdbcTemplate mysqlTemplate(@Qualifier("mysqlDB") DataSource mysqlDB) {
return new JdbcTemplate(mysqlDB);
}
}

+ 27
- 0
src/main/java/mx/gob/jumapacelaya/datasource/OracleDataSource.java View File

@ -0,0 +1,27 @@
package mx.gob.jumapacelaya.datasource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configuration
public class OracleDataSource {
@Bean(name = "oracleDB")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "oracleTemplate")
@Autowired
public JdbcTemplate oracleJdbcTemplate(@Qualifier("oracleDB") DataSource oracleDB) {
return new JdbcTemplate(oracleDB);
}
}

+ 87
- 0
src/main/java/mx/gob/jumapacelaya/models/ActividadDiaria.java View File

@ -0,0 +1,87 @@
package mx.gob.jumapacelaya.models;
import org.springframework.stereotype.Service;
import java.util.Date;
public class ActividadDiaria {
private int numero;
private String proyecto;
private String tipo;
private String estado;
private String asunto;
private Date fechaInicial;
private Date fechaCierre;
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
public String getProyecto() {
return proyecto;
}
public void setProyecto(String proyecto) {
this.proyecto = proyecto;
}
public String getTipo() {
return tipo;
}
public void setTipo(String tipo) {
this.tipo = tipo;
}
public String getEstado() {
return estado;
}
public void setEstado(String estado) {
this.estado = estado;
}
public String getAsunto() {
return asunto;
}
public void setAsunto(String asunto) {
this.asunto = asunto;
}
public Date getFechaInicial() {
return fechaInicial;
}
public void setFechaInicial(Date fechaInicial) {
this.fechaInicial = fechaInicial;
}
public Date getFechaCierre() {
return fechaCierre;
}
public void setFechaCierre(Date fechaCierre) {
this.fechaCierre = fechaCierre;
}
public ActividadDiaria(int numero, String proyecto, String estado, String tipo, String asunto, Date fechaInicial, Date fechaCierre) {
this.numero = numero;
this.proyecto = proyecto;
this.estado = estado;
this.tipo = tipo;
this.asunto = asunto;
this.fechaInicial = fechaInicial;
this.fechaCierre = fechaCierre;
}
public ActividadDiaria() {
}
}

+ 27
- 0
src/main/java/mx/gob/jumapacelaya/models/ActualizacioneSeguridadModel.java View File

@ -0,0 +1,27 @@
package mx.gob.jumapacelaya.models;
public class ActualizacioneSeguridadModel {
private int actualizacionsegId;
private String descripcion;
private String otrasactualizaciones;
private int mantenimientoId;
public ActualizacioneSeguridadModel(int actualizacionsegId, String descripcion, String otrasactualizaciones, int mantenimientoId) {
this.actualizacionsegId = actualizacionsegId;
this.descripcion = descripcion;
this.otrasactualizaciones = otrasactualizaciones;
this.mantenimientoId = mantenimientoId;
}
public int getActualizacionsegId() { return actualizacionsegId; }
public String getDescripcion() { return descripcion; }
public String getOtrasactualizaciones() { return otrasactualizaciones; }
public int getMantenimientoId() { return mantenimientoId; }
public void setActualizacionsegId(int actualizacionsegId) { this.actualizacionsegId = actualizacionsegId; }
public void setDescripcion(String descripcion) { this.descripcion = descripcion; }
public void setOtrasactualizaciones(String otrasactualizaciones) { this.otrasactualizaciones = otrasactualizaciones; }
public void setMantenimientoId(int mantenimientoId) { this.mantenimientoId = mantenimientoId;}
}

+ 84
- 0
src/main/java/mx/gob/jumapacelaya/models/CustomUserDetails.java View File

@ -0,0 +1,84 @@
package mx.gob.jumapacelaya.models;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class CustomUserDetails implements UserDetails {
private String username;
private String firstName;
private String lastName;
private String email;
private Collection<? extends GrantedAuthority> authorities;
private String password;
public CustomUserDetails(String username, String firstName, String lastName, String email, Collection<? extends GrantedAuthority> authorities, String password) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.authorities = authorities;
this.password = password;
}
// Getters and setters
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

+ 33
- 0
src/main/java/mx/gob/jumapacelaya/models/DepartamentosModel.java View File

@ -0,0 +1,33 @@
package mx.gob.jumapacelaya.models;
public class DepartamentosModel {
private String departamentoId;
private String nombre;
public DepartamentosModel(String departamentoId, String nombre) {
this.departamentoId = departamentoId;
this.nombre = nombre;
}
public String getDepartamentoId() {
return departamentoId;
}
public void setDepartamentoId(String departamentoId) {
this.departamentoId = departamentoId;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
@Override
public String toString() {
return nombre;
}
}

+ 66
- 0
src/main/java/mx/gob/jumapacelaya/models/DetalleMantenimientoModel.java View File

@ -0,0 +1,66 @@
package mx.gob.jumapacelaya.models;
import java.time.LocalDate;
public class DetalleMantenimientoModel {
private int id;
private int planAnualId;
private String tipo;
private String departamento;
private String usuario;
private LocalDate fechaprog;
private LocalDate fecha;
private String nombreEquipo;
private String formaMant;
private String firmaUser;
private String firmaSmt;
private String firmaGcia;
private String situacion;
public DetalleMantenimientoModel(int id, int planAnualId, String tipo, String departamento,
String usuario, LocalDate fechaprog, LocalDate fecha, String nombreEquipo, String formaMant,
String firmaUser, String firmaSmt, String firmaGcia, String situacion) {
this.id = id;
this.planAnualId = planAnualId;
this.tipo = tipo;
this.departamento = departamento;
this.usuario = usuario;
this.fechaprog = fechaprog;
this.fecha = fecha;
this.nombreEquipo = nombreEquipo;
this.formaMant = formaMant;
this.firmaUser = firmaUser;
this.firmaSmt = firmaSmt;
this.firmaGcia = firmaGcia;
this.situacion = situacion;
}
public int getId() { return id; }
public int getPlanAnualId() { return planAnualId; }
public String getTipo() { return tipo; }
public String getDepartamento() { return departamento; }
public String getUsuario() { return usuario; }
public LocalDate getFechaprog() { return fechaprog; }
public LocalDate getFecha() { return fecha; }
public String getNombreEquipo() { return nombreEquipo; }
public String getFormaMant() { return formaMant; }
public String getFirmaUser() { return firmaUser; }
public String getFirmaSmt() { return firmaSmt; }
public String getFirmaGcia() { return firmaGcia; }
public String getSituacion() { return situacion; }
public void setId(int id) { this.id = id; }
public void setPlanAnualId(int planAnualId) { this.planAnualId = planAnualId; }
public void setTipo(String tipo) { this.tipo = tipo; }
public void setDepartamento(String departamento) { this.departamento = departamento; }
public void setUsuario(String usuario) { this.usuario = usuario; }
public void setFechaprog(LocalDate fechaprog) { this.fechaprog = fechaprog; }
public void setFecha(LocalDate fecha) { this.fecha = fecha; }
public void setNombreEquipo(String nombreEquipo) { this.nombreEquipo = nombreEquipo; }
public void setFormaMant(String formaMant) { this.formaMant = formaMant; }
public void setFirmaUser(String firmaUser) { this.firmaUser = firmaUser; }
public void setFirmaSmt(String firmaSmt) { this.firmaSmt = firmaSmt; }
public void setFirmaGcia(String firmaGcia) { this.firmaGcia = firmaGcia; }
public void setSituacion(String situacion) { this.situacion = situacion; }
}

+ 35
- 0
src/main/java/mx/gob/jumapacelaya/models/HardwareDetalle.java View File

@ -0,0 +1,35 @@
package mx.gob.jumapacelaya.models;
public class HardwareDetalle {
private int mantenimientoId;
private int hardwareDetId;
private String descripcion;
private String modelo;
private String numSerie;
private String placa;
public HardwareDetalle(int mantenimientoId, int hardwareDetId, String descripcion,
String modelo, String numSerie, String placa) {
this.mantenimientoId = mantenimientoId;
this.hardwareDetId = hardwareDetId;
this.descripcion = descripcion;
this.modelo = modelo;
this.numSerie = numSerie;
this.placa = placa;
}
public int getMantenimientoId() { return mantenimientoId; }
public int getHardwareDetId() { return hardwareDetId; }
public String getDescripcion() { return descripcion; }
public String getModelo() { return modelo; }
public String getNumSerie() { return numSerie; }
public String getPlaca() { return placa; }
public void setMantenimientoId(int mantenimientoId) { this.mantenimientoId = mantenimientoId; }
public void setHardwareDetId(int hardwareDetId) { this.hardwareDetId = hardwareDetId; }
public void setDescripcion(String descripcion) { this.descripcion = descripcion; }
public void setModelo(String modelo) { this.modelo = modelo; }
public void setNumSerie(String numSerie) { this.numSerie = numSerie; }
public void setPlaca(String placa) { this.placa = placa; }
}

+ 91
- 0
src/main/java/mx/gob/jumapacelaya/models/MantCorrectivosModel.java View File

@ -0,0 +1,91 @@
package mx.gob.jumapacelaya.models;
import java.time.LocalDate;
public class MantCorrectivosModel {
private int mantenimientoId;
private LocalDate fecha;
private String tipo;
private String area;
private String nombre;
private String forma;
private String nomequipo;
private String reparacion;
public MantCorrectivosModel(int mantenimientoId, LocalDate fecha, String tipo,
String area, String nombre, String forma, String nomequipo, String reparacion) {
this.mantenimientoId = mantenimientoId;
this.fecha = fecha;
this.tipo = tipo;
this.area = area;
this.nombre = nombre;
this.forma = forma;
this.nomequipo = nomequipo;
this.reparacion = reparacion;
}
public int getMantenimientoId() {
return mantenimientoId;
}
public void setMantenimientoId(int mantenimientoId) {
this.mantenimientoId = mantenimientoId;
}
public LocalDate getFecha() {
return fecha;
}
public void setFecha(LocalDate fecha) {
this.fecha = fecha;
}
public String getTipo() {
return tipo;
}
public void setTipo(String tipo) {
this.tipo = tipo;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getForma() {
return forma;
}
public void setForma(String forma) {
this.forma = forma;
}
public String getNomequipo() {
return nomequipo;
}
public void setNomequipo(String nomequipo) {
this.nomequipo = nomequipo;
}
public String getReparacion() {
return reparacion;
}
public void setReparacion(String reparacion) {
this.reparacion = reparacion;
}
}

+ 145
- 0
src/main/java/mx/gob/jumapacelaya/models/PlanAnual.java View File

@ -0,0 +1,145 @@
package mx.gob.jumapacelaya.models;
import java.time.LocalDate;
public class PlanAnual {
private int numero;
private String nomEquipo;
private String departamento;
private boolean monitor; // Cambiado a boolean
private boolean teclado; // Cambiado a boolean
private boolean mouse; // Cambiado a boolean
private boolean regulador; // Cambiado a boolean
private boolean cpu; // Cambiado a boolean
private boolean impresora; // Cambiado a boolean
private boolean miniPrint; // Cambiado a boolean
private boolean laptop; // Cambiado a boolean
private boolean escaner; // Cambiado a boolean
private LocalDate fechaProgramada;
private LocalDate fechaMantenimiento;
private String mesplaneado;
private String smt;
private String estado;
private String situacion;
// Constructor
public PlanAnual(int numero, String nomEquipo, String departamento, boolean monitor,
boolean teclado, boolean mouse, boolean regulador,
boolean cpu, boolean impresora, boolean miniPrint,
boolean laptop, boolean escaner, LocalDate fechaProgramada,
LocalDate fechaMantenimiento, String mesplaneado, String smt, String estado, String situacion) {
this.numero = numero;
this.nomEquipo = nomEquipo;
this.departamento = departamento;
this.monitor = monitor;
this.teclado = teclado;
this.mouse = mouse;
this.regulador = regulador;
this.cpu = cpu;
this.impresora = impresora;
this.miniPrint = miniPrint;
this.laptop = laptop;
this.escaner = escaner;
this.fechaProgramada = fechaProgramada;
this.fechaMantenimiento = fechaMantenimiento;
this.mesplaneado = mesplaneado;
this.smt = smt;
this.estado = estado;
this.situacion = situacion;
}
// Getters
public int getNumero() {
return numero;
}
public String getNomEquipo() {
return nomEquipo;
}
public String getDepartamento() {
return departamento;
}
public boolean isMonitor() {
return monitor;
}
public boolean isTeclado() {
return teclado;
}
public boolean isMouse() {
return mouse;
}
public boolean isRegulador() {
return regulador;
}
public boolean isCpu() {
return cpu;
}
public boolean isImpresora() {
return impresora;
}
public boolean isMiniPrint() {
return miniPrint;
}
public boolean isLaptop() {
return laptop;
}
public boolean isEscaner() {
return escaner;
}
public String getSmt() {
return smt;
}
public String getEstado() {
return estado;
}
public void setNumero(int numero) {
this.numero = numero;
}
public LocalDate getFechaMantenimiento() {
return fechaMantenimiento;
}
public void setFechaMantenimiento(LocalDate fechaMantenimiento) {
this.fechaMantenimiento = fechaMantenimiento;
}
public LocalDate getFechaProgramada() {
return fechaProgramada;
}
public void setFechaProgramada(LocalDate fechaProgramada) {
this.fechaProgramada = fechaProgramada;
}
public String getMesplaneado() {
return mesplaneado;
}
public void setMesplaneado(String mesplaneado) {
this.mesplaneado = mesplaneado;
}
public String getSituacion() {
return situacion;
}
public void setSituacion(String situacion) {
this.situacion = situacion;
}
}

+ 72
- 0
src/main/java/mx/gob/jumapacelaya/models/RedmineUser.java View File

@ -0,0 +1,72 @@
package mx.gob.jumapacelaya.models;
public class RedmineUser {
private int id;
private String login;
private String firstname;
private String lastname;
private String mail;
private String key;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public String toString() {
return "RedmineUser{" +
"id=" + id +
", login='" + login + '\'' +
", firstname='" + firstname + '\'' +
", lastname='" + lastname + '\'' +
", mail='" + mail + '\'' +
", key='" + key + '\'' +
'}';
}
}

+ 1
- 0
src/main/java/mx/gob/jumapacelaya/models/SignaturePad.java View File

@ -0,0 +1 @@
package mx.gob.jumapacelaya.models;

+ 153
- 0
src/main/java/mx/gob/jumapacelaya/models/Ticket.java View File

@ -0,0 +1,153 @@
package mx.gob.jumapacelaya.models;
import java.sql.Date;
import java.time.LocalDate;
public class Ticket {
private final int id;
private final String subject;
private final String description;
private final String status;
private final LocalDate dateCreate;
private LocalDate dateClose;
private User author;
private Integer trackerId;
private String type;
public Ticket(int id, String subject, String description, String status, String dateCreate, String dateClose, Integer trackerId, String type) {
this.id = id;
this.subject = subject;
this.description = description;
this.status = status;
// Manejo de la fecha de creación
if (dateCreate != null && !dateCreate.isEmpty()) {
this.dateCreate = LocalDate.parse(dateCreate); // Solo se parsea si no está vacío
} else {
this.dateCreate = null; // Si está vacío, asignar null
}
// Manejo de la fecha de cierre
if (dateClose != null && !dateClose.isEmpty()) {
this.dateClose = LocalDate.parse(dateClose); // Solo se parsea si no está vacío
} else {
this.dateClose = null; // Si está vacío, asignar null
}
this.author = author;
this.trackerId = trackerId;
this.type = type;
}
public int getId() {
return id;
}
public String getSubject() {
return subject;
}
public String getDescription() {
return description;
}
public String getStatus() {
return status;
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public Date getDateCreate() {
return java.sql.Date.valueOf(this.dateCreate);
}
public Integer getTrackerId() {
return trackerId;
}
public void setTrackerId(Integer tipoId) {
this.trackerId = tipoId;
}
public LocalDate getDateClose() {
return dateClose;
}
public void setDateClose(LocalDate dateClose) {
this.dateClose = dateClose;
}
public void setType(String type) {
this.type = type;
}
public static class User {
private String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
public String tiempoEst(Integer trackerId) {
if (trackerId == null) {
return "Desconocido";
}
switch (trackerId) {
case 1,3,4,7:
return "1-2 dias Max";
case 2,12:
return "2 hrs Max";
case 5:
return "5 dias aprox.";
case 8,11:
return "2-6 hrs Max";
case 9,10:
return "2 hrs Max";
default:
return "N/A";
}
}
public String getType() {
if (trackerId == null) {
return "Desconocido";
}
return switch (trackerId) {
case 5 -> "Acceso/Permiso/Bajas";
case 6 -> "Soporte de Software";
case 7 -> "Capacitacion de Software";
case 8 -> "Configuracion de Software";
case 9 -> "Desarrollo de Software";
case 10 -> "Digitalizacion GIS";
case 11 -> "Documento";
case 12 -> "Reporte";
case 13 -> "Mantenimiento Correctivo";
case 14 -> "Actividad";
case 15 -> "Entrega de Consumibles";
case 16 -> "Instalacion/Configuracion GIS";
//case 17 -> "DDL";
//case 18 -> "DCL";
//case 19 -> "DML";
default -> "N/A";
};
}
}

+ 34
- 0
src/main/java/mx/gob/jumapacelaya/models/TiposHardware.java View File

@ -0,0 +1,34 @@
package mx.gob.jumapacelaya.models;
public class TiposHardware {
private String tipoHardwareId;
private String nombreHardware;
public TiposHardware(String tipoHardwareId, String nombreHardware) {
this.tipoHardwareId = tipoHardwareId;
this.nombreHardware = nombreHardware;
}
public String getTipoHardwareId() {
return tipoHardwareId;
}
public void setTipoHardwareId(String tipoHardwareId) {
this.tipoHardwareId = tipoHardwareId;
}
public String getNombreHardware() {
return nombreHardware;
}
public void setNombreHardware(String nombreHardware) {
this.nombreHardware = nombreHardware;
}
@Override
public String toString() {
return nombreHardware;
}
}

+ 32
- 0
src/main/java/mx/gob/jumapacelaya/models/TiposMantenimiento.java View File

@ -0,0 +1,32 @@
package mx.gob.jumapacelaya.models;
public class TiposMantenimiento {
private String tipomantId;
private String nombre;
public TiposMantenimiento(String tipomantId, String nombre) {
this.tipomantId = tipomantId;
this.nombre = nombre;
}
public String getTipomantId() {
return tipomantId;
}
public void setTipomantId(String tipomantId) {
this.tipomantId = tipomantId;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
@Override
public String toString() {
return nombre;
}
}

+ 43
- 0
src/main/java/mx/gob/jumapacelaya/models/Usuario.java View File

@ -0,0 +1,43 @@
package mx.gob.jumapacelaya.models;
public class Usuario {
private String empleadoId;
private String nombre;
private String email;
public Usuario(String empleadoId, String nombre, String email) {
this.empleadoId = empleadoId;
this.nombre = nombre;
this.email = email;
}
public String getEmpleadoId() {
return empleadoId;
}
public void setEmpleadoId(String empleadoId) {
this.empleadoId = empleadoId;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return nombre;
}
}

+ 899
- 0
src/main/java/mx/gob/jumapacelaya/services/DatabaseService.java View File

@ -0,0 +1,899 @@
package mx.gob.jumapacelaya.services;
import mx.gob.jumapacelaya.models.*;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OraclePreparedStatement;
import oracle.sql.CLOB;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.interfaces.RSAKey;
import java.sql.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@Service
public class DatabaseService {
@Value("${db.url}")
private String dbUrl;
@Value("${db.user}")
private String dbUser;
@Value("${db.pass}")
private String dbPass;
private Connection getMysqlConnection() throws SQLException {
return DriverManager.getConnection(dbUrl, dbUser, dbPass);
}
/*private Connection getOracleConnection() throws SQLException {
String url = "jdbc:oracle:thin:@//svradminfinan:1521/admfinpdb.JUMAPACELAYA.GOB.MX";
String user = "Finanzas";
String pass = "finanzas";
return DriverManager.getConnection(url, user, pass);
}*/
// Método para obtener los tipos de mantenimientos
public List<TiposMantenimiento> getTiposDeMantenimientos() {
List<TiposMantenimiento> tiposDeMantenimientos = new ArrayList<>();
String query = "SELECT tipomantid, nombre FROM TIPOMANT";
try (Connection connection = getMysqlConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
TiposMantenimiento tipo = new TiposMantenimiento(
resultSet.getString("tipomantid"),
resultSet.getString("nombre")
);
tiposDeMantenimientos.add(tipo);
}
} catch (SQLException e) {
e.printStackTrace();
}
return tiposDeMantenimientos;
}
// Método para obtener las nomenclaturas
public String getNomenclatura(String tipoMantenimiento) {
String nomenclatura = "";
String query = "SELECT nomenclatura FROM TIPOMANT where TIPOMANTID = ?";
try (Connection connection = getMysqlConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, tipoMantenimiento);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
if (resultSet.next()) {
nomenclatura = resultSet.getString("nomenclatura");
}
}
} catch (SQLException e) {
e.printStackTrace();
System.err.println("Error al obtener nomenclatura: " + e.getMessage());
}
return nomenclatura;
}
/* -------------- Metodo para obtener a los usuarios ---------------- */
public List<Usuario> getUsuarios() {
List<Usuario> usuarios = new ArrayList<>();
String query = "SELECT u.* \n" +
"FROM USUARIOS u";
try (Connection connection = getMysqlConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
Usuario usuario = new Usuario(
resultSet.getString("empleadoid"),
resultSet.getString("nombre"),
resultSet.getString("email")
);
usuarios.add(usuario);
}
} catch (SQLException e) {
e.printStackTrace();
}
return usuarios;
}
/* -------------- Metodo para obtener los departamentos ---------------- */
public List<DepartamentosModel> getDepartamentos() {
List<DepartamentosModel> departamentos = new ArrayList<>();
String query = "select DEPARTAMENTOID, DESCRIPCION from DEPARTAMENTOS";
try (Connection connection = getMysqlConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
DepartamentosModel departamentosModel = new DepartamentosModel(
resultSet.getString("departamentoid"),
resultSet.getString("descripcion")
);
departamentos.add(departamentosModel);
}
} catch (SQLException e) {
e.printStackTrace();
}
return departamentos;
}
/* -------------- Metodo para obtener los tipos de hardware ---------------- */
public List<TiposHardware> getTiposHardware() {
List<TiposHardware> tiposHardware = new ArrayList<>();
String query = "select TIPOHARDWAREID, DESCRIPCION from TIPOSHARDWARE";
try (Connection connection = getMysqlConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
TiposHardware tiposHardwareModel = new TiposHardware(
resultSet.getString("tipohardwareid"),
resultSet.getString("descripcion")
);
tiposHardware.add(tiposHardwareModel);
}
} catch (SQLException e) {
e.printStackTrace();
}
return tiposHardware;
}
/* ----------------Obtener el Plan Anual de Mantenimiento ---------------- */
public List<PlanAnual> getPlanAnual() {
List<PlanAnual> planAnualList = new ArrayList<>();
String query = "SELECT p.plananualid, p.nomEquipo, p.area,\n" +
" p.monitor, p.teclado, p.mouse, p.regulador,\n" +
" p.cpu, p.impresora, p.miniPrint, p.laptop, p.escaner,\n" +
" p.fechaprog, m.fecha AS fechaMantenimiento,\n" +
" me.NOMBRE AS MESPLANEADO, p.tecnicosmt, p.estado,\n" +
" COALESCE(v.SITUACION, 'NO REALIZADO') AS SITUACION\n" +
" FROM PLANANUAL p\n" +
" LEFT JOIN MANTENIMIENTOS m ON p.plananualid = m.plananualid\n" +
" LEFT JOIN MESES me ON p.MESID = me.MESID\n" +
" LEFT JOIN VW_SITUACION_MANTENIMIENTO v ON v.PLANANUALID = p.PLANANUALID\n" +
" ORDER BY p.FECHAPROG ASC";
try (Connection connection = getMysqlConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
while (resultSet.next()) {
PlanAnual planAnual = new PlanAnual(
resultSet.getInt("plananualid"),
resultSet.getString("nomEquipo"),
resultSet.getString("area"),
resultSet.getBoolean("monitor"),
resultSet.getBoolean("teclado"),
resultSet.getBoolean("mouse"),
resultSet.getBoolean("regulador"),
resultSet.getBoolean("cpu"),
resultSet.getBoolean("impresora"),
resultSet.getBoolean("miniPrint"),
resultSet.getBoolean("laptop"),
resultSet.getBoolean("escaner"),
resultSet.getDate("fechaprog").toLocalDate(), // Cambiado a LocalDate
resultSet.getDate("fechaMantenimiento") != null ? resultSet.getDate("fechaMantenimiento").toLocalDate() : null, // Cambiado a LocalDate
resultSet.getString("mesplaneado"),
resultSet.getString("tecnicosmt"),
resultSet.getString("estado"),
resultSet.getString("SITUACION")
);
planAnualList.add(planAnual);
}
System.out.println("Registros obtenidos: " + planAnualList.size());
} catch (SQLException e) {
e.printStackTrace();
}
return planAnualList;
}
/* ----------------Obtener el Plan Anual de Mantenimiento por ID ---------------- */
public PlanAnual getPlanAnualPorId(int id) {
String query = "SELECT p.plananualid, p.nomEquipo, p.area,\n" +
" p.monitor, p.teclado, p.mouse, p.regulador,\n" +
" p.cpu, p.impresora, p.miniPrint, p.laptop, p.escaner,\n" +
" p.fechaprog, m.fecha AS fechaMantenimiento,\n" +
" me.NOMBRE AS MESPLANEADO, p.tecnicosmt, p.estado,\n" +
" COALESCE(v.SITUACION, 'NO REALIZADO') AS SITUACION\n" +
" FROM PLANANUAL p\n" +
" LEFT JOIN MANTENIMIENTOS m ON p.plananualid = m.plananualid\n" +
" LEFT JOIN MESES me ON p.MESID = me.MESID\n" +
" LEFT JOIN VW_SITUACION_MANTENIMIENTO v ON v.PLANANUALID = p.PLANANUALID\n" +
" where p.plananualid = ?";
try (Connection connection = getMysqlConnection();
PreparedStatement statement = connection.prepareStatement(query)) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return new PlanAnual(
resultSet.getInt("plananualid"),
resultSet.getString("nomEquipo"),
resultSet.getString("area"),
resultSet.getBoolean("monitor"),
resultSet.getBoolean("teclado"),
resultSet.getBoolean("mouse"),
resultSet.getBoolean("regulador"),
resultSet.getBoolean("cpu"),
resultSet.getBoolean("impresora"),
resultSet.getBoolean("miniPrint"),
resultSet.getBoolean("laptop"),
resultSet.getBoolean("escaner"),
resultSet.getDate("fechaprog").toLocalDate(), // Cambiado a LocalDate
resultSet.getDate("fechaMantenimiento") != null ? resultSet.getDate("fechaMantenimiento").toLocalDate() : null, // Cambiado a LocalDate
resultSet.getString("mesplaneado"),
resultSet.getString("tecnicosmt"),
resultSet.getString("estado"),
resultSet.getString("SITUACION")
);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/* ----------------Obtener detalles del mantenimiento ---------------- */
public DetalleMantenimientoModel getDetalleMantenimientoPorPlanAnualId(int planAnualId) {
String query = "SELECT\n" +
" m.MANTENIMIENTOID AS ID,\n" +
" p.PLANANUALID,\n" +
" t.NOMBRE AS TIPO,\n" +
" d.DESCRIPCION AS DEPARTAMENTO,\n" +
" u.NOMBRE AS USUARIO,\n" +
" v.FECHAPROG,\n" +
" v.FECHAREALIZADO,\n" +
" NOMBREEQUIPO,\n" +
" FORMAMANT,\n" +
" FIRMAUSUARIO,\n" +
" FIRMASMT,\n" +
" FIRMAGCIA,\n" +
" v.SITUACION\n" +
"FROM MANTENIMIENTOS m\n" +
"INNER JOIN TIPOMANT t ON m.TIPOMANTID = t.TIPOMANTID\n" +
"INNER JOIN DEPARTAMENTOS d ON m.DEPARTAMENTOID = d.DEPARTAMENTOID\n" +
"INNER JOIN USUARIOS u ON u.EMPLEADOID = m.EMPLEADOID\n" +
"INNER JOIN PLANANUAL p ON m.PLANANUALID = p.PLANANUALID\n" +
"INNER JOIN PLANANUAL pa ON m.PLANANUALID = pa.PLANANUALID\n" +
"INNER JOIN VW_SITUACION_MANTENIMIENTO v ON v.MANTENIMIENTOID = m.MANTENIMIENTOID\n" +
"WHERE p.PLANANUALID = ?";
try (Connection connection = getMysqlConnection();
PreparedStatement statement = connection.prepareStatement(query)) {
statement.setInt(1, planAnualId);
try (ResultSet rs = statement.executeQuery()) {
if (rs.next()) {
return new DetalleMantenimientoModel(
rs.getInt("ID"),
rs.getInt("PLANANUALID"),
rs.getString("TIPO"),
rs.getString("DEPARTAMENTO"),
rs.getString("USUARIO"),
rs.getDate("FECHAPROG").toLocalDate(),
rs.getDate("FECHAREALIZADO").toLocalDate(),
rs.getString("NOMBREEQUIPO"),
rs.getString("FORMAMANT"),
rs.getString("FIRMAUSUARIO"),
rs.getString("FIRMASMT"),
rs.getString("FIRMAGCIA"),
rs.getString("SITUACION")
);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/* ----------------Obtener detalles del hardaware por ID ---------------- */
public List<HardwareDetalle> getHardwaredetallePorMantId(int mantenimientoId) {
List<HardwareDetalle> detalles = new ArrayList<>();
String query = "SELECT h.MANTENIMIENTOID, h.HARDWAREDETID, t.DESCRIPCION, h.MODELO, h.NUMSERIE, h.PLACA\r\n" + //
"FROM HARDWAREDET h\r\n" + //
"INNER JOIN TIPOSHARDWARE t ON h.TIPOHARDWAREID = t.TIPOHARDWAREID \r\n" + //
"WHERE h.MANTENIMIENTOID = ?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setInt(1, mantenimientoId);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
HardwareDetalle detalle = new HardwareDetalle(
rs.getInt("MANTENIMIENTOID"),
rs.getInt("HARDWAREDETID"),
rs.getString("DESCRIPCION"),
rs.getString("MODELO"),
rs.getString("NUMSERIE"),
rs.getString("PLACA")
);
detalles.add(detalle);
}
} catch (SQLException e) {
e.printStackTrace();
}
return detalles;
}
/* ---------------- Obtener las actualizaciones de seguridad ---------------- */
public List<ActualizacioneSeguridadModel> getActualizacionesSeg(int mantenimientoId) {
List<ActualizacioneSeguridadModel> actualizaciones = new ArrayList<>();
String query = "SELECT *\r\n" + //
"FROM ACTUALIZACIONESSEG a\r\n" + //
"WHERE a.MANTENIMIENTOID = ?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setInt(1, mantenimientoId);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
ActualizacioneSeguridadModel actualizacion = new ActualizacioneSeguridadModel(
rs.getInt("ACTUALIZACIONSEGID"),
rs.getString("DESCRIPCION"),
rs.getString("OTRASACTUALIZACIONES"),
rs.getInt("MANTENIMIENTOID")
);
actualizaciones.add(actualizacion);
}
} catch (SQLException e) {
e.printStackTrace();
}
return actualizaciones;
}
/* ---------------- Obtener los mantenimientos correctivos ---------------- */
public List<MantCorrectivosModel> getMantenimientosCorrectivos(int tipomantId) {
List<MantCorrectivosModel> mantCorrectivos = new ArrayList<>();
String query = "select\n" +
"\tm.MANTENIMIENTOID,\n" +
"\tm.FECHA,\n" +
"\tt.NOMBRE TIPO,\n" +
"\td.DESCRIPCION AREA,\n" +
"\tu.NOMBRE,\n" +
"\tCASE\n" +
"\t\tWHEN formamant = 'M' then 'MANUAL'\n" +
"\t\tELSE 'REMOTO'\n" +
"\tEND as FORMA,\n" +
"\tm.NOMBREEQUIPO,\n" +
"\tm.REPARACION\n" +
"from MANTENIMIENTOS m\n" +
"inner join TIPOMANT t on t.TIPOMANTID = m.TIPOMANTID\n" +
"inner join DEPARTAMENTOS d on d.DEPARTAMENTOID = m.DEPARTAMENTOID\n" +
"inner join USUARIOS u on u.EMPLEADOID = m.EMPLEADOID\n" +
"where m.TIPOMANTID = ?";
try (Connection conn = getMysqlConnection();
PreparedStatement statement = conn.prepareStatement(query)) {
statement.setInt(1, tipomantId);
try (ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
MantCorrectivosModel model = new MantCorrectivosModel(
rs.getInt("MANTENIMIENTOID"),
rs.getDate("FECHA").toLocalDate(),
rs.getString("TIPO"),
rs.getString("AREA"),
rs.getString("NOMBRE"),
rs.getString("FORMA"),
rs.getString("NOMBREEQUIPO"),
rs.getString("REPARACION")
);
mantCorrectivos.add(model);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return mantCorrectivos;
}
/*-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<()*/
/*-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<()*/
/*-=iii=<() *-=iii=<() *-=iii=<() *-=iii=<()*/
/*-=iii=<() *-=iii=<() *-=iii=<()*/
/*-=iii=<() *-=iii=<()*/
/* ( ͡° ͜ʖ ͡°) Metodos para insetar en la BD ( ͡° ͜ʖ ͡°) ( ͡° ͜ʖ ͡°) Metodos para insetar en la BD ( ͡° ͜ʖ ͡°) ( ͡° ͜ʖ ͡°) Metodos para insetar en la BD ( ͡° ͜ʖ ͡°) */
// INSERTAR EN TABLA: MANTENIMINETOS
public int insertarMantenimiento(LocalDate fecha, String tipoMantId, String departamentoId, String empleadoId,
String formaMant, String equipoId, String userSignatureBase64,
String smtSignatureBase64, String planAnualId, String justificacion, String reparacion) {
String query = "INSERT INTO MANTENIMIENTOS (fecha, tipoMantId, departamentoId, empleadoId, formaMant, nombreequipo," +
" firmaUsuario, firmaSmt, planAnualId, justificacion, reparacion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
String updateStatusQuery = "UPDATE PLANANUAL SET estado = 'REALIZADO' WHERE planAnualId = ?";
int nuevoId = -1;
Connection connection = null;
try {
connection = getMysqlConnection();
if (connection == null) {
throw new SQLException("No se pudo establecer la conexion con la base de datos.");
}
connection.setAutoCommit(false);
// Paso 1: primero inserta el mantenimiento
try (PreparedStatement preparedStatement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) {
preparedStatement.setDate(1, Date.valueOf(fecha));
preparedStatement.setLong(2, Long.parseLong(tipoMantId));
preparedStatement.setString(3, departamentoId);
preparedStatement.setLong(4, Long.parseLong(empleadoId));
preparedStatement.setString(5, formaMant);
preparedStatement.setString(6, equipoId);
if (userSignatureBase64 != null) {
preparedStatement.setString(7, userSignatureBase64);
} else {
preparedStatement.setNull(7, Types.VARCHAR);
}
if (smtSignatureBase64 != null) {
preparedStatement.setString(8, smtSignatureBase64);
} else {
preparedStatement.setNull(8, Types.VARCHAR);
}
if (planAnualId != null && !planAnualId.isEmpty()) {
preparedStatement.setLong(9, Long.parseLong(planAnualId));
} else {
preparedStatement.setNull(9, Types.BIGINT);
}
preparedStatement.setString(10, justificacion);
preparedStatement.setString(11, reparacion);
preparedStatement.executeUpdate();
try (ResultSet rs = preparedStatement.getGeneratedKeys()) {
if (rs.next()) {
nuevoId = rs.getInt(1);
}
}
}
// Paso 2: Si se inserto el mantenimiento, se actualiza el estado en MTTOPROGRAMADOS
if (nuevoId != -1) {
try (PreparedStatement updateStatement = connection.prepareStatement(updateStatusQuery)) {
updateStatement.setString(1, planAnualId);
updateStatement.executeUpdate();
}
}
// Confirmar la transaccion si ambos pasos son exitosos
connection.commit();
} catch (SQLException e) {
System.err.println("Error al insertar mantenimiento: " + e.getMessage());
e.printStackTrace();
// En caso de error, se hace rollback
if (connection != null) {
try {
connection.rollback();
} catch (SQLException rollbackEx) {
System.err.println("Error al hacer rollback: " + rollbackEx.getMessage());
}
}
} finally {
// Cerrar la conexion
if (connection != null) {
try {
connection.close();
} catch (SQLException closeEx) {
System.err.println("Error al cerrar la conexion: " + closeEx.getMessage());
}
}
}
return nuevoId;
}
/*( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■)( •_•)>⌐■-■ (⌐■_■) */
/* ˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀˁ˚ᴥ˚ˀ */
// INSERTAR EN LA TABLA: HARDWAREDET
public boolean insertarHardware(String tipoHardwareId, String numSerie, String modelo, String placa, int mantenimientoId) {
String query = "INSERT INTO HARDWAREDET (tipoHardwareId, numSerie, modelo, placa, mantenimientoId) VALUES (?, ?, ?, ?, ?)";
boolean isInserted = false;
try (Connection connection = getMysqlConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setInt(1, Integer.parseInt(tipoHardwareId));
preparedStatement.setString(2, numSerie);
preparedStatement.setString(3, modelo);
preparedStatement.setString(4, placa);
preparedStatement.setInt(5, mantenimientoId);
int rowsAffected = preparedStatement.executeUpdate();
isInserted = rowsAffected > 0;
} catch (SQLException e) {
e.printStackTrace();
}
return isInserted;
}
public int getUltimoMantenimientoId() {
int ultimoId = -1;
try (Connection connection = getMysqlConnection()) {
String query = "SELECT MAX(mantenimientoid) FROM MANTENIMIENTOS";
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
ultimoId = resultSet.getInt(1);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return ultimoId;
}
// INSERTAR EN LA TABLA: ACTUALIZACIONESSEG
public boolean insertActualizacionSeg(String descripcion, String otras, int mantenimientoId) {
String query = "INSERT INTO ACTUALIZACIONESSEG (descripcion, otrasactualizaciones, mantenimientoid) VALUES (?, ?, ?)";
try (Connection connection = getMysqlConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, descripcion);
preparedStatement.setString(2, otras);
preparedStatement.setInt(3, mantenimientoId);
int rowsInserted = preparedStatement.executeUpdate();
return rowsInserted > 0;
} catch (SQLException e) {
System.err.println("Error al insertar actualizacionSeg: " + e.getMessage());
return false;
}
}
// INSERTAR ARCHIVO EXCEL EN LA TABLA: PLANANUAL
public void insertarDesdeExcel(InputStream inputStream) {
String query = "INSERT INTO PLANANUAL (NOMEQUIPO, AREA, MONITOR, TECLADO, MOUSE, " +
"REGULADOR, CPU, IMPRESORA, MINIPRINT, LAPTOP, ESCANER, FECHAPROG, TECNICOSMT, ESTADO) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
try (Connection connection = getMysqlConnection();
//FileInputStream file = new FileInputStream(rutaArchivoExcel);
Workbook workbook = new XSSFWorkbook(inputStream)) {
Sheet sheet = workbook.getSheetAt(0); // Primera hoja del archivo Excel
for (Row row : sheet) {
if (row.getRowNum() == 0) continue; // Saltar la primera fila si contiene encabezados
try {
// Leer cada celda de la fila según el índice correcto
String nomequipo = getStringCellValue(row.getCell(0)); // Columna 1
String area = getStringCellValue(row.getCell(1)); // Columna 2
boolean monitor = getBooleanCellValue(row.getCell(2)); // Columna 3
boolean teclado = getBooleanCellValue(row.getCell(3)); // Columna 4
boolean mouse = getBooleanCellValue(row.getCell(4)); // Columna 5
boolean regulador = getBooleanCellValue(row.getCell(5)); // Columna 6
boolean cpu = getBooleanCellValue(row.getCell(6)); // Columna 7
boolean impresora = getBooleanCellValue(row.getCell(7)); // Columna 8
boolean miniprint = getBooleanCellValue(row.getCell(8)); // Columna 9
boolean laptop = getBooleanCellValue(row.getCell(9)); // Columna 10
boolean escaner = getBooleanCellValue(row.getCell(10)); // Columna 11
// Leer la fecha de la columna correcta
Date fechaprog = getDateCellValue(row.getCell(11)); // Columna 12
String tecnicosmt = getStringCellValue(row.getCell(12)); // Columna 13
String estado = getStringCellValue(row.getCell(13)); // Columna 14
Date fecharealizado = getDateCellValue(row.getCell(14)); // Columna 15
// Insertar datos en la base de datos
try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, nomequipo);
preparedStatement.setString(2, area);
preparedStatement.setBoolean(3, monitor);
preparedStatement.setBoolean(4, teclado);
preparedStatement.setBoolean(5, mouse);
preparedStatement.setBoolean(6, regulador);
preparedStatement.setBoolean(7, cpu);
preparedStatement.setBoolean(8, impresora);
preparedStatement.setBoolean(9, miniprint);
preparedStatement.setBoolean(10, laptop);
preparedStatement.setBoolean(11, escaner);
// Manejo de fechas
if (fechaprog != null) {
preparedStatement.setDate(12, new java.sql.Date(fechaprog.getTime()));
} else {
preparedStatement.setNull(12, java.sql.Types.DATE); // Manejo de valor nulo
}
preparedStatement.setString(13, tecnicosmt);
preparedStatement.setString(14, estado);
preparedStatement.executeUpdate();
}
} catch (Exception e) {
System.err.println("Error procesando la fila " + row.getRowNum() + ": " + e.getMessage());
}
}
System.out.println("Datos insertados desde Excel con éxito en PLANANUAL.");
} catch (IOException e) {
System.err.println("Error al leer el archivo Excel: " + e.getMessage());
} catch (SQLException e) {
System.err.println("Error al insertar datos en la BD: " + e.getMessage());
}
}
// INSERTAR NUEVO EQUIPO INDIVIDUAL EN PLANANUAL
public void insertarNuevoEquipo(String nomequipo, String area, boolean monitor, boolean teclado,
boolean mouse, boolean regulador, boolean cpu, boolean impresora,
boolean miniprint, boolean laptop, boolean escaner, Date fechaprog,
String tecnicosmt, String estado, Integer mesId) {
String query = "INSERT INTO PLANANUAL (NOMEQUIPO, AREA, MONITOR, TECLADO,MOUSE, REGULADOR,\n" +
"CPU, IMPRESORA, MINIPRINT, LAPTOP, ESCANER, FECHAPROG,\n" +
"TECNICOSMT, ESTADO, MESID)\n" +
"VALUES (?, ?,\n" +
"?, ?, ?, ?, ?, ?, ?, ?, ?,\n" +
"?, ?, ?, ?)";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, nomequipo);
stmt.setString(2, area);
stmt.setBoolean(3, monitor);
stmt.setBoolean(4, teclado);
stmt.setBoolean(5, mouse);
stmt.setBoolean(6, regulador);
stmt.setBoolean(7, cpu);
stmt.setBoolean(8, impresora);
stmt.setBoolean(9, miniprint);
stmt.setBoolean(10, laptop);
stmt.setBoolean(11, escaner);
// Manejo de fechas
if (fechaprog != null) {
stmt.setDate(12, new java.sql.Date(fechaprog.getTime()));
} else {
stmt.setNull(12, java.sql.Types.DATE); // Manejo de valor nulo
}
stmt.setString(13, tecnicosmt);
stmt.setString(14, estado);
stmt.setInt(15, mesId);
stmt.executeUpdate();
} catch (SQLException e) {
System.err.println("Error al insertar nuevo equipo en PLANANUAL: " + e.getMessage());
}
}
// Método auxiliar para obtener un valor de tipo Date de una celda
private Date getDateCellValue(Cell cell) {
if (cell != null) {
switch (cell.getCellType()) {
case NUMERIC:
return new Date(cell.getDateCellValue().getTime()); // Retorna la fecha directamente
case STRING:
try {
return Date.valueOf(LocalDate.parse(cell.getStringCellValue().trim())); // Asume formato ISO
} catch (Exception e) {
System.err.println("No se puede convertir la cadena a fecha: " + cell.getStringCellValue());
}
break;
case BLANK:
return null; // Devuelve null si la celda está vacía
default:
System.err.println("Tipo de celda inesperado en la fila " + cell.getRowIndex());
break;
}
}
return null; // Retorna null si no se puede obtener una fecha
}
// Método auxiliar para obtener un valor de tipo String de una celda
private String getStringCellValue(Cell cell) {
if (cell != null) {
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue().trim();
case NUMERIC:
return String.valueOf((int) cell.getNumericCellValue()); // Convierte el número a cadena
default:
return ""; // Devuelve cadena vacía si la celda no es de tipo STRING o NUMERIC
}
}
return ""; // Devuelve cadena vacía si la celda es nula
}
// Método auxiliar para obtener un valor de tipo boolean de una celda
private boolean getBooleanCellValue(Cell cell) {
if (cell != null) {
switch (cell.getCellType()) {
case NUMERIC:
return cell.getNumericCellValue() != 0; // Considera 0 como false, cualquier otro número como true
case BOOLEAN:
return cell.getBooleanCellValue();
case STRING:
return Boolean.parseBoolean(cell.getStringCellValue().trim()); // Conversión de string a boolean
default:
return false; // Valor por defecto
}
}
return false; // Valor por defecto si la celda es nula
}
/* ----------------Actualizar los detalles del del mantenimiento por ID ---------------- */
public boolean actualizarPlanAnual(int planAnualId, String nombreEquipo) {
String sql = "UPDATE PLANANUAL SET NOMEQUIPO=? WHERE PLANANUALID=?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, nombreEquipo);
stmt.setInt(2, planAnualId);
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public boolean actualizarMantenimiento(int mantenimientoId, int tipoId, String departamentoId, int empleadoId, LocalDate fechaRealizado, String nombreEquipo, String firmausuario, String firmasmt) {
String sql = "UPDATE MANTENIMIENTOS SET TIPOMANTID=?, DEPARTAMENTOID=?, EMPLEADOID=?, FECHA=?, NOMBREEQUIPO=?, FIRMAUSUARIO=?, FIRMASMT=? WHERE MANTENIMIENTOID=?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tipoId); // tipoId es int
stmt.setString(2, departamentoId); // departamentoId es String
stmt.setInt(3, empleadoId); // empleadoId es int
stmt.setDate(4, fechaRealizado != null ? Date.valueOf(fechaRealizado) : null);
stmt.setString(5, nombreEquipo);
if (firmausuario != null) {
stmt.setString(6, firmausuario);
} else {
stmt.setNull(6, Types.VARCHAR);
}
if (firmasmt != null) {
stmt.setString(7, firmasmt);
} else {
stmt.setNull(7, Types.VARCHAR);
}
stmt.setInt(8, mantenimientoId);
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
/* ----------------Actualizar los detalles del hardaware por ID ---------------- */
public boolean actualizarHardwareDetalle(HardwareDetalle detalle) {
String sql = "UPDATE HARDWAREDET SET MODELO=?, NUMSERIE=?, PLACA=? WHERE HARDWAREDETID=?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, detalle.getModelo());
stmt.setString(2, detalle.getNumSerie());
stmt.setString(3, detalle.getPlaca());
stmt.setInt(4, detalle.getHardwareDetId());
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
/* ----------------Actualizar las actualizaciones de seguridad por ID ---------------- */
public boolean actualizarActualizacionSeg(ActualizacioneSeguridadModel actualizacion) {
String sql = "UPDATE ACTUALIZACIONESSEG SET OTRASACTUALIZACIONES=? WHERE ACTUALIZACIONSEGID=?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, actualizacion.getOtrasactualizaciones());
stmt.setInt(2, actualizacion.getActualizacionsegId());
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
/* ---------------- Insertar en bitacora ---------------- */
public boolean insertarBitacora(int mantenimientoid, String usuarioid, LocalDate fechora, String motivo) {
String query = "INSERT INTO BITACORACTUALIZACIONES (MANTENIMIENTOID, USUARIOID, FECHORA, MOTIVO) VALUES (?, ?, ?, ?)";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setInt(1, mantenimientoid);
stmt.setString(2, usuarioid);
stmt.setDate(3, fechora != null ? Date.valueOf(fechora) : null);
stmt.setString(4, motivo);
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
/* ---------------- Insertar en bitacora de eliminacion de equipos ---------------- */
public boolean insertarBitacoraEliminacion(int plananualid, String usuarioid, LocalDate fechora, String motivo) {
String query = "INSERT INTO BITACORAELIMINACIONES (PLANANUALID, USUARIOID, FECHAHORA, MOTIVO) VALUES (?, ?, ?, ?)";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setInt(1, plananualid);
stmt.setString(2, usuarioid);
stmt.setDate(3, fechora != null ? Date.valueOf(fechora) : null);
stmt.setString(4, motivo);
return stmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
/* ---------------- Eliminar equipo de PLAN ANUAL ---------------- */
public void eliminarEquipoPlanAnual(int planAnualId) {
String sql = "DELETE FROM PLANANUAL WHERE PLANANUALID = ?";
try (Connection conn = getMysqlConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, planAnualId);
int rowsAffected = stmt.executeUpdate();
if (rowsAffected > 0) {
System.out.println(planAnualId + " eliminado correctamente.");
} else {
System.out.println("No se encontró el equipo con ID: " + planAnualId);
}
} catch (SQLException e) {
System.err.println("Error al eliminar el equipo de PLANANUAL: " + e.getMessage());
e.printStackTrace();
}
}
}

+ 48
- 0
src/main/java/mx/gob/jumapacelaya/services/EmailService.java View File

@ -0,0 +1,48 @@
package mx.gob.jumapacelaya.services;
import com.vaadin.flow.component.notification.Notification;
import jakarta.activation.DataSource;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.util.ByteArrayDataSource;
import mx.gob.jumapacelaya.models.Usuario;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMailMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.InputStream;
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
public void enviarCorreo(String destinatario, String asunto, String cuerpo, String imagePath) {
try {
MimeMessage mensaje = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mensaje, true);
helper.setTo(destinatario);
helper.setSubject(asunto);
helper.setFrom("noreply@jumapacelaya.gob.mx");
helper.setText(cuerpo, true);
ClassPathResource imgResource = new ClassPathResource(imagePath);
helper.addInline("image_id", imgResource);
mailSender.send(mensaje);
System.out.println("Correo enviado con imagen exitosamente");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error al enviar el correo: " + e.getMessage());
}
}
}

+ 46
- 0
src/main/java/mx/gob/jumapacelaya/services/LdapService.java View File

@ -0,0 +1,46 @@
package mx.gob.jumapacelaya.services;
import mx.gob.jumapacelaya.models.CustomUserDetails;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.stereotype.Service;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import java.util.List;
@Service
public class LdapService {
private final LdapTemplate ldapTemplate;
public LdapService(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public CustomUserDetails getUserDetails(String username) {
EqualsFilter filter = new EqualsFilter("sAMAccountName", username);
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchControls.setReturningAttributes(new String[]{"givenName", "sn", "mail"});
searchControls.setReturningObjFlag(true);
List<CustomUserDetails> result = ldapTemplate.search("", filter.encode(), searchControls, (Attributes attrs) -> {
String firstName = getAttribute(attrs, "givenName");
String lastName = getAttribute(attrs, "sn");
String email = getAttribute(attrs, "mail");
return new CustomUserDetails(username, firstName, lastName, email, null, null); // Ajustar los últimos dos parámetros si es necesario
});
return result.isEmpty() ? null : result.get(0);
}
private String getAttribute(Attributes attributes, String attributeName) {
try {
return attributes.get(attributeName) != null ? attributes.get(attributeName).get().toString(): null;
} catch (NamingException e) {
return null;
}
}
}

+ 41
- 0
src/main/java/mx/gob/jumapacelaya/services/ReportService.java View File

@ -0,0 +1,41 @@
package mx.gob.jumapacelaya.services;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Map;
@Service
public class ReportService {
@Value("${db.url}")
private String dbUrl;
@Value("${db.user}")
private String dbUser;
@Value("${db.pass}")
private String dbPass;
public byte[] generarReporte(String nombreReporte, Map<String, Object> parametros) throws Exception {
InputStream logo = getClass().getResourceAsStream("/META-INF/resources/images/LOGO_24'27.png");
parametros.put("logo", logo);
InputStream firmaGcia = getClass().getResourceAsStream("/META-INF/resources/images/FirmaGerenteTI.png");
parametros.put("firmaGcia", firmaGcia);
InputStream jasperStream = getClass().getResourceAsStream("/META-INF/resources/reportes/" + nombreReporte + ".jasper");
if (jasperStream == null) {
throw new IllegalArgumentException("No se encontro el archivo del reporte: " + nombreReporte);
}
try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPass)) {
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parametros, conn);
return JasperExportManager.exportReportToPdf(jasperPrint);
}
}
}

+ 30
- 0
src/main/java/mx/gob/jumapacelaya/services/SecurityService.java View File

@ -0,0 +1,30 @@
package mx.gob.jumapacelaya.services;
import com.vaadin.flow.spring.security.AuthenticationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Component
public class SecurityService {
private final AuthenticationContext authenticationContext;
public SecurityService(AuthenticationContext authenticationContext) {
this.authenticationContext = authenticationContext;
}
public String getAuthenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
return authentication.getName();
}
return null;
}
public void logout() {
authenticationContext.logout();
}
}

+ 89
- 0
src/main/java/mx/gob/jumapacelaya/services/UserService.java View File

@ -0,0 +1,89 @@
package mx.gob.jumapacelaya.services;
import com.vaadin.flow.server.VaadinService;
import mx.gob.jumapacelaya.api.RedmineClient;
import mx.gob.jumapacelaya.services.SecurityService;
import mx.gob.jumapacelaya.models.CustomUserDetails;
import mx.gob.jumapacelaya.models.RedmineUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final SecurityService securityService;
private final RedmineClient redmineClient;
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
private final LdapService ldpaService;
public UserService(SecurityService securityService, RedmineClient redmineClient, LdapService ldpaService) {
this.securityService = securityService;
this.redmineClient = redmineClient;
this.ldpaService = ldpaService;
}
public RedmineUser getAuthenticatedRedmineUser() {
try {
String username = securityService.getAuthenticatedUser();
logger.info("Usuario autenticado: " + username);
if (username != null) {
RedmineUser user = redmineClient.getUserByUsername(username);
if (user == null) {
CustomUserDetails userDetails = ldpaService.getUserDetails(username);
if (userDetails != null) {
if (userDetails.getEmail() == null || userDetails.getEmail().isEmpty()) {
logger.error("El usuario: " + username + " no tiene correo electronico.");
return null;
}
RedmineUser newUser = RedmineClient.createRedmineUser(
username,
userDetails.getFirstName(),
userDetails.getLastName(),
userDetails.getEmail()
);
if (newUser != null) {
logger.info("Usuario creado en Redmine: " + newUser);
return newUser;
} else {
logger.error("Error al crear el usuario en Redmine");
}
} else {
logger.error("No se encontraron detalles del usuario en LDAP");
}
} else {
logger.info("Usuario autenticado en Redmine: " + user);
}
return user;
}
} catch (Exception e) {
logger.error("Error al obtener al usuario autenticado en Redmine", e);
}
return null;
}
public RedmineUser getRedmineUser() {
RedmineUser userclient = (RedmineUser) VaadinService.getCurrentRequest().getWrappedSession().getAttribute("myaccount");
if (userclient == null) {
RedmineUser user = getAuthenticatedRedmineUser();
if (user != null) {
RedmineUser myAccount = redmineClient.getMyAccount(user.getLogin());
if (myAccount != null && !myAccount.getKey().isEmpty()) {
userclient = myAccount;
VaadinService.getCurrentRequest().getWrappedSession().setAttribute("myaccount", myAccount);
} else {
// Crear un nuevo usuario si no existe
myAccount = RedmineClient.createRedmineUser(user.getLogin(), user.getFirstname(), user.getLastname(), user.getMail());
if (myAccount != null && !myAccount.getKey().isEmpty()) {
userclient = myAccount;
VaadinService.getCurrentRequest().getWrappedSession().setAttribute("myaccount", myAccount);
}
}
}
}
return userclient;
}
}

+ 223
- 0
src/main/java/mx/gob/jumapacelaya/ui/ActDiariaView.java View File

@ -0,0 +1,223 @@
package mx.gob.jumapacelaya.ui;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.richtexteditor.RichTextEditor;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.api.RedmineClient;
import mx.gob.jumapacelaya.api.ServerProperties;
import mx.gob.jumapacelaya.models.ActividadDiaria;
import mx.gob.jumapacelaya.models.RedmineUser;
import mx.gob.jumapacelaya.models.Ticket;
import mx.gob.jumapacelaya.services.LdapService;
import mx.gob.jumapacelaya.services.UserService;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
@PermitAll
@PageTitle("Actividades Diarias")
@Route(value = "actdiaria", layout = MainLayout.class)
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class ActDiariaView extends VerticalLayout {
private final RedmineClient redmineClient;
private final UserService userService;
private final Grid<Ticket> grid;
public ActDiariaView(ServerProperties properties, RedmineClient redmineClient, UserService userService) {
this.userService = userService;
this.redmineClient = redmineClient;
this.grid = new Grid<>(Ticket.class, false);
// Configuración de columnas del grid
grid.addColumn(Ticket::getId).setHeader("No.")
.setAutoWidth(true).setFlexGrow(0).setSortable(true);
grid.addColumn(Ticket::getType)
.setHeader("Tipo")
.setAutoWidth(true);
grid.addColumn(Ticket::getSubject).setHeader("Asunto")
.setWidth("25em");
grid.addColumn(createStatusRender()).setHeader("Estado");
grid.addColumn(ticket -> {
Date date = ticket.getDateCreate();
if (date != null) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
return formatter.format(date);
} else {
return "";
}
}).setHeader("Fecha creacion").setAutoWidth(true);
grid.addColumn(ticket -> {
LocalDate fechaCierre = ticket.getDateClose();
if (fechaCierre != null) {
DateTimeFormatter formatterClose = DateTimeFormatter.ofPattern("dd/MM/yyyy");
return fechaCierre.format(formatterClose);
} else {
return "";
}
}).setHeader("Fecha cierre").setAutoWidth(true);
//grid.addColumn(ticket -> ticket.tiempoEst(ticket.getTrackerId())).setHeader("Tiempo estimado de atencion").setAutoWidth(false);
grid.addComponentColumn(ticket -> {
Button btnVer = new Button(new Icon(VaadinIcon.EYE));
btnVer.addClickListener(event -> showDescription(ticket));
btnVer.getStyle().set("color", "#A02142");
return btnVer;
}).setAutoWidth(true);
grid.addColumn(buttonTicketComponentRenderer()).setAutoWidth(true);
grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT);
grid.getStyle().set("opacity", "0.8");
grid.setAllRowsVisible(false);
grid.setSizeFull();
// Ajustar tamaño del Grid y Layout
grid.setSizeFull();
setSizeFull();
add(grid);
//expand(grid);
setMargin(false);
loadTickets();
}
private void loadTickets() {
try {
List<Ticket> tickets = redmineClient.getTickets(userService.getRedmineUser(), true);
List<Ticket> filteredTickets = tickets.stream()
.filter(ticket -> ticket.getTrackerId() == 13 || ticket.getTrackerId() == 14)
.toList();
grid.setItems(filteredTickets);
} catch (Exception e) {
e.printStackTrace();
// Manejo de error al cargar los tickets
}
}
private ComponentRenderer<Span, Ticket> createStatusRender() {
return new ComponentRenderer<>(ticket -> {
// Creamos un Span para mostrar el estado
Span span = new Span(ticket.getStatus());
// Estilos basados en el estado del ticket
switch (ticket.getStatus().toLowerCase()) {
case "análisis":
span.getElement().getStyle().set("color","orange");
break;
case "desarrollo":
span.getElement().getStyle().set("color","blue");
break;
case "rechazada":
span.getElement().getStyle().set("color","red");
break;
case "cerrada":
span.getElement().getStyle().set("color","grey");
break;
case "solicitado":
span.getElement().getStyle().set("color","purple");
break;
case "qa":
span.getElement().getStyle().set("color","#C21DF2");
break;
default:
span.getElement().getStyle().set("color","green");
break;
}
return span;
});
}
public ComponentRenderer<Button, Ticket> buttonTicketComponentRenderer() {
return new ComponentRenderer<>(ticket -> {
Button button = new Button(new Icon(VaadinIcon.EDIT) );
button.getStyle().set("color", "#A02142");
button.addClickListener(e -> {
RedmineUser currentUser = userService.getRedmineUser();
if (ticket.getTrackerId() == 13) {
UI.getCurrent().navigate("mantenimiento");
} else if (ticket.getTrackerId() == 14) {
cerrarTicket(ticket, currentUser);
} else {
Notification.show("El ticket no es de tipo Mantenimiento o Actividad.");
}
});
return button;
});
}
public void cerrarTicket(Ticket ticket, RedmineUser user) {
try {
//Llamar al metodo para cambiar el estado del ticket
redmineClient.closeTicket(ticket.getId(), user);
Notification.show("El ticket " + ticket.getId() + " se ha cerrado exitosamente.", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
UI.getCurrent().getPage().executeJs("setTimeout(() => { window.location.reload(); }, 3000);");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
Notification.show("Error al cerrar el ticket " + ticket.getId());
}
}
// Metodo para mostrar las descripciones en un componente Dialog
private void showDescription(Ticket ticket) {
Dialog dialog = new Dialog();
dialog.getElement().setAttribute("arial-label", "Add note");
dialog.setMaxHeight("500px");
dialog.setMaxWidth("1100px");
RichTextEditor textEditor = new RichTextEditor();
textEditor.setValue(ticket.getDescription());
textEditor.setReadOnly(true);
Button closeButton = new Button("Cerrar", new Icon(VaadinIcon.CLOSE));
closeButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
closeButton.addClickListener(e -> dialog.close());
HorizontalLayout buttonLayout = new HorizontalLayout(closeButton);
buttonLayout.setWidthFull();
buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
buttonLayout.add(closeButton);
dialog.add(textEditor, buttonLayout);
dialog.open();
}
}

+ 607
- 0
src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java View File

@ -0,0 +1,607 @@
package mx.gob.jumapacelaya.ui;
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.server.StreamRegistration;
import com.vaadin.flow.server.StreamResource;
import mx.gob.jumapacelaya.services.ReportService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.vaadin.lineawesome.LineAwesomeIcon;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.gridpro.GridPro;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.f0rce.signaturepad.SignaturePad;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.models.ActualizacioneSeguridadModel;
import mx.gob.jumapacelaya.models.DepartamentosModel;
import mx.gob.jumapacelaya.models.DetalleMantenimientoModel;
import mx.gob.jumapacelaya.models.HardwareDetalle;
import mx.gob.jumapacelaya.models.TiposMantenimiento;
import mx.gob.jumapacelaya.models.Usuario;
import mx.gob.jumapacelaya.services.DatabaseService;
import mx.gob.jumapacelaya.services.SecurityService;
@PageTitle("Detalles del mantenimiento")
@Route(value = "detalles", layout = MainLayout.class)
@PermitAll
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class DetallesMantView extends VerticalLayout implements BeforeEnterObserver {
private H3 id;
private VerticalLayout mainLayout;
private HorizontalLayout headerLayout;
private HorizontalLayout layout2;
private HorizontalLayout layout3;
private HorizontalLayout botonesLayout;
private HorizontalLayout fechasLayout;
private TextField txtId;
private TextField txtEquipo;
private ComboBox<TiposMantenimiento> cbTipo;
private TextField txtFecha;
private TextField txtFechaProgramada;
private TextField txtSituacion;
private ComboBox<Usuario> cbUsuario;
private ComboBox<DepartamentosModel> cbDepartamento;
private GridPro<HardwareDetalle> gridHardware;
private GridPro<ActualizacioneSeguridadModel> gridActualizaciones;
private Button btnEditar;
private Button btnEditarFirmas;
private Button btnImprimirRepo;
private Button btnCancelar;
private Button btnGuardar;
private int planAnualIdActual;
private int mantenimientoIdActual;
private Dialog confirmDialog;
private SignaturePad userSignPad;
private SignaturePad smtSignPad;
private SignaturePad gciaSignPad;
private final HorizontalLayout firmasLAyout = new HorizontalLayout();
private Image firmaUsuarioImg;
private Image firmaSmtImg;
private Image firmaGciaImg;
private VerticalLayout userSignLayout;
private VerticalLayout smtSignLayout;
private VerticalLayout gciaSignLayout;
private final SecurityService securityService;
private final DatabaseService service;
private final ReportService reportService;
public DetallesMantView(SecurityService securityService, DatabaseService service, ReportService reportService) {
this.service = service;
this.securityService = securityService;
this.reportService = reportService;
setPadding(true);
mainLayout = new VerticalLayout();
mainLayout.setHeightFull();
mainLayout.getStyle()
.set("box-shadow","0 4px 8px rgba(0,0,0,0.2)")
.set("border-radius", "12px")
.set("background-color", "white")
.set("padding", "1rem")
.set("margin", "1rem auto");
id = new H3();
headerLayout = new HorizontalLayout();
headerLayout.setWidthFull();
headerLayout.add(id);
cbTipo = new ComboBox<>("Tipo:");
cbTipo.setItems(service.getTiposDeMantenimientos());
cbTipo.setItemLabelGenerator(TiposMantenimiento::getNombre);
cbUsuario = new ComboBox<>("Usuario:");
cbUsuario.setItems(service.getUsuarios());
cbUsuario.setItemLabelGenerator(Usuario::getNombre);
cbDepartamento = new ComboBox<>("Area:");
cbDepartamento.setItems(service.getDepartamentos());
cbDepartamento.setItemLabelGenerator(DepartamentosModel::getNombre);
layout2 = new HorizontalLayout();
layout2.setWidthFull();
txtEquipo = new TextField("Equipo:");
txtEquipo.setReadOnly(true);
cbTipo.setReadOnly(true);
layout2.add(txtEquipo,cbTipo);
fechasLayout = new HorizontalLayout();
fechasLayout.setWidthFull();
txtFecha = new TextField("Fecha realización:");
txtFechaProgramada = new TextField("Fecha programada:");
txtSituacion = new TextField("Situación:");
txtFecha.setReadOnly(true);
txtFechaProgramada.setReadOnly(true);
txtSituacion.setReadOnly(true);
fechasLayout.add(txtFechaProgramada,txtFecha,txtSituacion);
layout3 = new HorizontalLayout();
layout3.setWidthFull();
cbUsuario.setReadOnly(true);
cbDepartamento.setReadOnly(true);
cbUsuario.setWidthFull();
cbDepartamento.setWidthFull();
layout3.add(cbUsuario,cbDepartamento);
// Grid que muestra los detalles del hardware
gridHardware = new GridPro<>();
gridHardware.addColumn(item -> item.getDescripcion())
.setHeader("Descripción");
gridHardware.addEditColumn(HardwareDetalle::getNumSerie)
.text((item, newValue) -> item.setNumSerie(newValue))
.setHeader("No. Serie")
.setEditorComponent(new TextField());
gridHardware.addEditColumn(HardwareDetalle::getModelo)
.text((item, newValue) -> item.setModelo(newValue))
.setHeader("Modelo")
.setEditorComponent(new TextField());
gridHardware.addEditColumn(HardwareDetalle::getPlaca)
.text((item, newValue) -> item.setPlaca(newValue))
.setHeader("Placa")
.setEditorComponent(new TextField());
gridHardware.setWidthFull();
gridHardware.setEditOnClick(false);
gridHardware.setHeight("250px");
gridHardware.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);
// Grid que muestra las actualizaciones de seguridad
gridActualizaciones = new GridPro<>();
gridActualizaciones.addEditColumn(ActualizacioneSeguridadModel::getDescripcion)
.text((item, newValue) -> item.setDescripcion(newValue))
.setHeader("Descripción")
.setEditorComponent(new TextField());
gridActualizaciones.addEditColumn(ActualizacioneSeguridadModel::getOtrasactualizaciones)
.text((item, newValue) -> item.setOtrasactualizaciones(newValue))
.setHeader("Otras Actualizaciones")
.setEditorComponent(new TextField());
gridActualizaciones.setWidthFull();
gridActualizaciones.setEditOnClick(false);
gridActualizaciones.setHeight("200px");
gridActualizaciones.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);
botonesLayout = new HorizontalLayout();
botonesLayout.setWidthFull();
botonesLayout.setJustifyContentMode(JustifyContentMode.CENTER);
btnEditar = new Button("Editar", new Icon(VaadinIcon.EDIT));
btnImprimirRepo = new Button("Imprimir Reporte", new Icon(VaadinIcon.PRINT));
btnEditarFirmas = new Button("Editar firmas", LineAwesomeIcon.SIGNATURE_SOLID.create());
btnGuardar = new Button("Guardar", LineAwesomeIcon.SAVE_SOLID.create());
btnCancelar = new Button("Cancelar", new Icon(VaadinIcon.CLOSE_CIRCLE_O));
botonesLayout.add(btnEditar,btnEditarFirmas,btnImprimirRepo,btnGuardar,btnCancelar);
btnGuardar.setVisible(false);
btnGuardar.getStyle().set("background-color", "#008000");
btnGuardar.getStyle().set("color", "white");
btnCancelar.setVisible(false);
btnCancelar.getStyle().set("background-color", "red");
btnCancelar.getStyle().set("color", "white");
btnEditar.addClickListener(e -> {
txtEquipo.setReadOnly(false);
cbTipo.setReadOnly(false);
txtFecha.setReadOnly(false);
cbUsuario.setReadOnly(false);
cbDepartamento.setReadOnly(false);
btnImprimirRepo.setVisible(false);
btnEditar.setVisible(false);
btnGuardar.setVisible(true);
btnCancelar.setVisible(true);
btnEditarFirmas.setVisible(false);
gridHardware.setEditOnClick(true);
gridActualizaciones.setEditOnClick(true);
});
btnEditarFirmas.addClickListener(e -> {
btnCancelar.setVisible(true);
btnGuardar.setVisible(true);
btnEditar.setVisible(false);
btnImprimirRepo.setVisible(false);
btnEditarFirmas.setVisible(false);
if (firmaUsuarioImg != null && firmaUsuarioImg.getParent().isPresent()) {
userSignLayout.replace(firmaUsuarioImg, userSignPad);
}
if (firmaSmtImg != null && firmaSmtImg.getParent().isPresent()) {
smtSignLayout.replace(firmaSmtImg, smtSignPad);
}
});
btnCancelar.addClickListener(e -> {
txtEquipo.setReadOnly(true);
cbTipo.setReadOnly(true);
txtFecha.setReadOnly(true);
cbUsuario.setReadOnly(true);
cbDepartamento.setReadOnly(true);
btnImprimirRepo.setVisible(true);
btnEditar.setVisible(true);
btnGuardar.setVisible(false);
btnCancelar.setVisible(false);
btnEditarFirmas.setVisible(true);
gridHardware.setEditOnClick(false);
gridHardware.getEditor().cancel();
gridActualizaciones.setEditOnClick(false);
gridActualizaciones.getEditor().cancel();
if (firmaUsuarioImg != null && userSignPad.getParent().isPresent()) {
userSignLayout.replace(userSignPad, firmaUsuarioImg);
}
if (firmaSmtImg != null && smtSignPad.getParent().isPresent()) {
smtSignLayout.replace(smtSignPad, firmaSmtImg);
}
});
btnImprimirRepo.addClickListener(e -> {
try {
// Prepara los parámetros para el reporte
Map<String, Object> parametros = new HashMap<>();
parametros.put("PLAN_ID", planAnualIdActual);
// Genera el PDF
byte[] pdf = reportService.generarReporte("mantenimientoReport", parametros);
// Se crea el recurso para descarga
StreamResource resource = new StreamResource("reporte.pdf", () -> new ByteArrayInputStream(pdf));
/*Anchor downloadLink = new Anchor(resource, "Descargar Reporte");
downloadLink.setTarget("_blank");
downloadLink.setId("descargar-reporte-link");
add(downloadLink);
getUI().ifPresent(ui ->
ui.getPage().executeJs("document.getElementById('descargar-reporte-link').click();")
);*/
StreamRegistration registration = UI.getCurrent().getSession().getResourceRegistry().registerResource(resource);
UI.getCurrent().getPage().executeJs("window.open('" + registration.getResourceUri().toString() + "','_blank')");
} catch (Exception ex) {
Notification.show("Error al generar el reporte: " + ex.getMessage(), 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
ex.printStackTrace();
}
});
// Se dispara el dialogo de confirmacion
btnGuardar.addClickListener(e -> confirmDialog.open());
// Dialogo de confirmación de actualización
confirmDialog = new Dialog();
confirmDialog.setHeaderTitle("Actualizar Mantenimiento");
TextField txtJustificacion = new TextField("Justificacion");
txtJustificacion.setWidthFull();
txtJustificacion.setRequired(true);
confirmDialog.add(
new VerticalLayout(
new Span("¿Estás seguro de que deseas actualizar el mantenimiento?"),
txtJustificacion
)
);
Button btnConfirmar = new Button("Actualizar", event -> {
String justificacion = txtJustificacion.getValue();
if (justificacion.isEmpty()) {
txtJustificacion.setErrorMessage("Por favor, ingresa una justificación.");
txtJustificacion.setInvalid(true);
return;
}
txtJustificacion.setInvalid(false);
confirmDialog.close();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String usuarioId = authentication != null ? authentication.getName().toUpperCase() : "DESCONOCIDO";
LocalDate fecha = LocalDate.now();
service.insertarBitacora(mantenimientoIdActual, usuarioId, fecha, justificacion);
realizarActualizacion();
txtJustificacion.clear();
});
Button btnCancelarDialog = new Button("Cancelar", event -> {
confirmDialog.close();
txtEquipo.setReadOnly(true);
cbTipo.setReadOnly(true);
txtFecha.setReadOnly(true);
cbUsuario.setReadOnly(true);
cbDepartamento.setReadOnly(true);
btnImprimirRepo.setVisible(true);
btnEditar.setVisible(true);
btnGuardar.setVisible(false);
btnCancelar.setVisible(false);
gridHardware.setEditOnClick(false);
gridHardware.getEditor().cancel();
if (firmaUsuarioImg != null && userSignPad.getParent().isPresent()) {
userSignLayout.replace(userSignPad, firmaUsuarioImg);
}
if (firmaSmtImg != null && smtSignPad.getParent().isPresent()) {
smtSignLayout.replace(smtSignPad, firmaSmtImg);
}
});
HorizontalLayout dialogButtons = new HorizontalLayout(btnConfirmar, btnCancelarDialog);
confirmDialog.getFooter().add(dialogButtons);
addSignatureSection();
mainLayout.add(headerLayout,layout2,fechasLayout,layout3,gridHardware,gridActualizaciones,firmasLAyout,botonesLayout);
add(mainLayout);
}
private void realizarActualizacion() {
boolean exito = true;
// Obtén los objetos seleccionados
TiposMantenimiento tipoSeleccionado = cbTipo.getValue();
Usuario usuarioSeleccionado = cbUsuario.getValue();
DepartamentosModel departamentoSeleccionado = cbDepartamento.getValue();
int tipoId = tipoSeleccionado != null ? Integer.parseInt(tipoSeleccionado.getTipomantId()) : 0;
int empleadoId = usuarioSeleccionado != null ? Integer.parseInt(usuarioSeleccionado.getEmpleadoId()) : 0;
String departamentoId = departamentoSeleccionado != null ? departamentoSeleccionado.getDepartamentoId() : null;
// Fechas (corrige el campo)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate fechaProg = !txtFechaProgramada.getValue().isEmpty() ? LocalDate.parse(txtFechaProgramada.getValue(), formatter) : null;
LocalDate fechaRealizado = !txtFecha.getValue().isEmpty() ? LocalDate.parse(txtFecha.getValue(), formatter) : null;
// Obtener las firmas como en MantenimientoView
byte[] userSignatureBytes = userSignPad.getImageBase64();
byte[] smtSignatureBytes = smtSignPad.getImageBase64();
String userSignatureBase64 = (userSignatureBytes != null) ? Base64.getEncoder().encodeToString(userSignatureBytes) : null;
String smtSignatureBase64 = (smtSignatureBytes != null) ? Base64.getEncoder().encodeToString(smtSignatureBytes) : null;
// Si la firma está vacía, conserva la anterior
if (userSignatureBase64 == null || esFirmaVacia(userSignatureBase64)) {
userSignatureBase64 = service.getDetalleMantenimientoPorPlanAnualId(planAnualIdActual).getFirmaUser();
}
if (smtSignatureBase64 == null || esFirmaVacia(smtSignatureBase64)) {
smtSignatureBase64 = service.getDetalleMantenimientoPorPlanAnualId(planAnualIdActual).getFirmaSmt();
}
// ACTUALIZA PLANANUAL (nombre del equipo y fecha programada)
if (!service.actualizarPlanAnual(planAnualIdActual, txtEquipo.getValue())) {
exito = false;
}
// ACTUALIZA MANTENIMIENTOS (tipo, departamento, usuario, fecha realizado)
if (!service.actualizarMantenimiento(
mantenimientoIdActual,
tipoId,
departamentoId,
empleadoId,
fechaRealizado,
txtEquipo.getValue(),
userSignatureBase64,
smtSignatureBase64
)) {
exito = false;
}
// ACTUALIZA HARDWARE (grid)
for (HardwareDetalle detalle : gridHardware.getListDataView().getItems().toList()) {
if (!service.actualizarHardwareDetalle(detalle)) {
exito = false;
}
}
// ACTUALIZA ACTUALIZACIONES DE SEGURIDAD (grid)
for (ActualizacioneSeguridadModel actualizacion : gridActualizaciones.getListDataView().getItems().toList()) {
if (!service.actualizarActualizacionSeg(actualizacion)) {
exito = false;
}
}
if (exito) {
Notification.show("Registros actualizados correctamente", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
} else {
Notification.show("Error al actualizar uno o más registros", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
}
// Opcional: volver a modo solo lectura
txtEquipo.setReadOnly(true);
cbTipo.setReadOnly(true);
txtFecha.setReadOnly(true);
cbUsuario.setReadOnly(true);
cbDepartamento.setReadOnly(true);
btnImprimirRepo.setVisible(true);
btnEditar.setVisible(true);
btnEditarFirmas.setVisible(true);
btnGuardar.setVisible(false);
btnCancelar.setVisible(false);
gridHardware.setEditOnClick(false);
gridHardware.getEditor().cancel();
if (firmaUsuarioImg != null && userSignPad.getParent().isPresent()) {
userSignLayout.replace(userSignPad, firmaUsuarioImg);
}
if (firmaSmtImg != null && smtSignPad.getParent().isPresent()) {
smtSignLayout.replace(smtSignPad, firmaSmtImg);
}
}
// Metodo para verificar si la firma corresponde a una cadena de firma vacia
private boolean esFirmaVacia(String firmaBase64) {
String firmaVacia = "iVBORw0KGgoAAAANSUhEUgAAAXkAAAD8CAYAAACSCdTiAAAIbElEQVR4Xu3UAQ0AIAwDQeZfNCPI+Nwc9Lp07rvjCBAgQCApMEY+2atQBAgQ+AJG3iMQIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBBYAuXtOkIWm1QAAAAASUVORK5CYII=";
return firmaBase64.equals(firmaVacia);
}
private void addSignatureSection() {
// Usa los atributos de clase, no variables locales
userSignLayout = new VerticalLayout();
userSignLayout.setWidthFull();
userSignLayout.setAlignItems(Alignment.CENTER);
userSignPad = new SignaturePad();
userSignPad.setHeight("200px");
userSignPad.setWidthFull();
userSignLayout.add(userSignPad, new Span("Usuario Interno"));
smtSignLayout = new VerticalLayout();
smtSignLayout.setWidthFull();
smtSignLayout.setAlignItems(Alignment.CENTER);
smtSignPad = new SignaturePad();
smtSignPad.setHeight("200px");
smtSignPad.setWidthFull();
smtSignLayout.add(smtSignPad, new Span("Responsable de Soporte"));
gciaSignLayout = new VerticalLayout();
gciaSignLayout.setWidthFull();
gciaSignLayout.setAlignItems(Alignment.CENTER);
gciaSignPad = new SignaturePad();
gciaSignPad.setHeight("200px");
gciaSignPad.setWidthFull();
gciaSignLayout.add(gciaSignPad, new Span("Gcia. de T.I"));
firmasLAyout.removeAll();
firmasLAyout.setWidthFull();
firmasLAyout.setSpacing(false);
firmasLAyout.setJustifyContentMode(JustifyContentMode.CENTER);
firmasLAyout.add(userSignLayout, smtSignLayout, gciaSignLayout);
}
@Override
public void beforeEnter(BeforeEnterEvent event) {
String idParam = event.getLocation().getQueryParameters().getParameters().get("id") != null
? event.getLocation().getQueryParameters().getParameters().get("id").stream().findFirst().orElse(null)
: null;
if (idParam != null) {
try {
int planId = Integer.parseInt(idParam);
DetalleMantenimientoModel detalle = service.getDetalleMantenimientoPorPlanAnualId(planId);
if (detalle != null) {
this.planAnualIdActual = detalle.getPlanAnualId();
this.mantenimientoIdActual = detalle.getId();
id.setText("Plan ID: " + idParam);
txtEquipo.setValue(String.valueOf(detalle.getNombreEquipo()));
cbTipo.setValue(
cbTipo.getListDataView().getItems()
.filter(t -> t.getNombre().equals(detalle.getTipo()))
.findFirst().orElse(null)
);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String fechaProg = detalle.getFechaprog() != null ? detalle.getFechaprog().format(formatter) : "";
String fechaReal = detalle.getFecha() != null ? detalle.getFecha().format(formatter) : "";
String situacion = detalle.getSituacion() != null ? detalle.getSituacion() : "";
txtFechaProgramada.setValue(fechaProg);
txtFecha.setValue(fechaReal);
txtSituacion.setValue(situacion);
cbUsuario.setValue(
cbUsuario.getListDataView().getItems()
.filter(u -> u.getNombre().equals(detalle.getUsuario()))
.findFirst().orElse(null)
);
cbDepartamento.setValue(
cbDepartamento.getListDataView().getItems()
.filter(d -> d.getNombre().equals(detalle.getDepartamento()))
.findFirst().orElse(null)
);
int mantId = detalle.getId();
List<HardwareDetalle> listaHardware = service.getHardwaredetallePorMantId(mantId);
gridHardware.setItems(listaHardware);
List<ActualizacioneSeguridadModel> listaActualizaciones = service.getActualizacionesSeg(mantId);
gridActualizaciones.setItems(listaActualizaciones);
gridActualizaciones.setVisible(!listaActualizaciones.isEmpty());
// --- Mostrar firmas como imagen si existen ---
// Firma usuario
if (detalle.getFirmaUser() != null && !detalle.getFirmaUser().isEmpty()) {
String firmaUser = detalle.getFirmaUser();
if (!firmaUser.startsWith("data:image")) {
firmaUser = "data:image/png;base64," + firmaUser;
}
firmaUsuarioImg = new Image(firmaUser, "Firma del usuario");
firmaUsuarioImg.setHeight("200px");
firmaUsuarioImg.setWidthFull();
userSignLayout.replace(userSignPad, firmaUsuarioImg);
}
// Firma soporte
if (detalle.getFirmaSmt() != null && !detalle.getFirmaSmt().isEmpty()) {
String firmaSmt = detalle.getFirmaSmt();
if (!firmaSmt.startsWith("data:image")) {
firmaSmt = "data:image/png;base64," + firmaSmt;
}
firmaSmtImg = new Image(firmaSmt, "Firma del usuario de soporte");
firmaSmtImg.setHeight("200px");
firmaSmtImg.setWidthFull();
smtSignLayout.replace(smtSignPad, firmaSmtImg);
}
Image firmaGcia = new Image("images/FirmaGerenteTI.png", "Firma de la Gcia. de T.I");
firmaGcia.setHeight("200px");
firmaGcia.setWidthFull();
gciaSignLayout.replace(gciaSignPad, firmaGcia);
} else {
id.setText("No se encontro informacion para el Plan ID: " + planId);
}
} catch (NumberFormatException e) {
id.setText("ID no valido");
}
}
}
}

+ 109
- 0
src/main/java/mx/gob/jumapacelaya/ui/MainLayout.java View File

@ -0,0 +1,109 @@
package mx.gob.jumapacelaya.ui;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.html.*;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.Scroller;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.sidenav.SideNav;
import com.vaadin.flow.component.sidenav.SideNavItem;
import com.vaadin.flow.theme.lumo.LumoUtility;
import mx.gob.jumapacelaya.services.SecurityService;
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class MainLayout extends AppLayout {
private H2 viewTitle;
private final SecurityService securityService;
public MainLayout(SecurityService securityService) {
this.securityService = securityService;
this.addClassName("app-layout");
setPrimarySection(Section.DRAWER);
addDrawerContent();
addHeaderContent();
}
private void addHeaderContent() {
DrawerToggle toggle = new DrawerToggle();
toggle.setAriaLabel("Menu toggle");
toggle.addClassName("drawer-toggle");
viewTitle = new H2();
viewTitle.addClassNames(LumoUtility.FontSize.LARGE, LumoUtility.Margin.NONE);
viewTitle.getStyle().set("font-weight", "bold");
viewTitle.getStyle().set("color", "#691B31");
viewTitle.getStyle().set("font-size", "25px");
String u = securityService.getAuthenticatedUser();
Span usrNameLabel = new Span(u);
usrNameLabel.getStyle().set("color", "#691b31");
usrNameLabel.getStyle().set("font-weight", "bold");
usrNameLabel.getStyle().set("font-size", "20px");
Button logoutButton = new Button("Cerrar sesión", VaadinIcon.SIGN_OUT.create(),event -> {
securityService.logout();
});
logoutButton.addClassName("logout-button");
logoutButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY ,ButtonVariant.LUMO_ERROR);
HorizontalLayout headerContent = new HorizontalLayout();
headerContent.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
headerContent.addClassName("header-content");
headerContent.add(viewTitle);
headerContent.setFlexGrow(1, viewTitle);
headerContent.add(usrNameLabel, logoutButton);
addToNavbar(false, toggle, headerContent);
}
private void addDrawerContent() {
VerticalLayout headerLayout = new VerticalLayout();
headerLayout.setPadding(true);
headerLayout.setSpacing(false);
headerLayout.setAlignItems(FlexComponent.Alignment.CENTER);
headerLayout.getStyle().set("background-color", "#DDC9A3");
Image imgLogo = new Image("images/LOGO_900X160.png", "Logo");
imgLogo.setWidthFull();
headerLayout.add(imgLogo);
Scroller scroller = new Scroller(createNavigation());
scroller.getStyle().set("background-color", "#691b31");
addToDrawer(headerLayout, scroller, createFooter());
}
private SideNav createNavigation() {
SideNav nav = new SideNav();
nav.addItem(new SideNavItem("Plan Anual", PlanAnualView.class, VaadinIcon.CALENDAR.create()));
nav.addItem(new SideNavItem("Listado de Actividades", ActDiariaView.class, VaadinIcon.EDIT.create()));
nav.addItem(new SideNavItem("Mantenimiento Correctivo", MantCorrectivoView.class, VaadinIcon.WRENCH.create()));
nav.getStyle().set("background-color", "white");
nav.getStyle().set("border-radius", "5px");
nav.getStyle().set("opacity", "0.9");
return nav;
}
private Footer createFooter() {
Footer layout = new Footer();
return layout;
}
@Override
protected void afterNavigation() {
super.afterNavigation();
viewTitle.setText("Mantenimiento de Hardware");
}
}

+ 693
- 0
src/main/java/mx/gob/jumapacelaya/ui/MantCorrectivoView.java View File

@ -0,0 +1,693 @@
package mx.gob.jumapacelaya.ui;
import com.vaadin.flow.component.Text;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.f0rce.signaturepad.SignaturePad;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.models.*;
import mx.gob.jumapacelaya.services.DatabaseService;
import mx.gob.jumapacelaya.services.EmailService;
import mx.gob.jumapacelaya.services.SecurityService;
import mx.gob.jumapacelaya.services.UserService;
import org.vaadin.lineawesome.LineAwesomeIcon;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
@PermitAll
@PageTitle("Correctivo")
@Route(value = "correctivo", layout = MainLayout.class)
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class MantCorrectivoView extends VerticalLayout {
private VerticalLayout mainLayout;
private final SecurityService securityService;
private final VerticalLayout controlsLayout;
private final DatabaseService databaseService;
private final VerticalLayout actualizacionesLayout;
//private final VerticalLayout etiquetaLayout;
private final HorizontalLayout firmasLayout;
private final DatePicker fecha;
private final ComboBox<TiposMantenimiento> tipoMantt;
private final ComboBox<DepartamentosModel> area;
private final ComboBox<Usuario> usuario;
private final TextField txtNombreEquipo;
private final UserService userService;
private final EmailService emailService;
private RadioButtonGroup<String> formaGroup;
private CheckboxGroup<String> actualizaciones;
private final HorizontalLayout botonesLayout;
private TextArea txtCuales;
private RadioButtonGroup<String> masActualizacionesGroup;
private SignaturePad userSignPad;
private SignaturePad smtSignPad;
private SignaturePad gciatiSignPad;
private PlanAnual planAnualActual;
private LocalDate fechaProgramada;
private LocalDate fechaSeleccionada;
private TextArea jsutificacion;
Span userSignSpan = new Span("Nombre Usuario");
private TextArea txtReparacion;
private HorizontalLayout headerLayout;
public MantCorrectivoView(UserService userService, SecurityService securityService, EmailService emailService, DatabaseService databaseService) {
this.databaseService = databaseService;
this.controlsLayout = new VerticalLayout();
this.actualizacionesLayout = new VerticalLayout();
//this.etiquetaLayout = new VerticalLayout();
this.firmasLayout = new HorizontalLayout();
this.botonesLayout = new HorizontalLayout();
this.securityService = securityService;
this.userService = userService;
this.emailService = emailService;
headerLayout = new HorizontalLayout();
headerLayout.setWidthFull();
headerLayout.setMargin(false);
headerLayout.getStyle()
.set("box-shadow", "0 4px 8px rgba(0,0,0,0.2)")
.set("border-radius", "10px")
.set("background-color", "white")
.set("padding", "1rem")
.set("margin", "1rem auto");
mainLayout = new VerticalLayout();
mainLayout.setHeightFull();
mainLayout.setMargin(false);
mainLayout.getStyle()
.set("box-shadow", "0 4px 8px rgba(0,0,0,0.2)")
.set("border-radius", "12px")
.set("background-color", "white")
.set("padding", "1rem")
.set("margin", "1rem auto");
TextField nomenclatura = new TextField("Nomenclatura");
nomenclatura.setReadOnly(true);
nomenclatura.addClassName("mantenimiento-text-field");
Button btnListado = new Button("Mantenimientos realizados", VaadinIcon.CLIPBOARD_CHECK.create());
btnListado.addClickListener(e -> verListadoMantenimientos());
fecha = new DatePicker("Fecha:");
fecha.setRequired(true);
fecha.setLocale(new Locale("es", "MX"));
DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n()
.setWeekdays(List.of("Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"))
.setWeekdaysShort(List.of("Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"))
.setMonthNames(List.of("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"))
.setFirstDayOfWeek(1)
.setToday("Hoy")
.setCancel("Cancelar")
.setDateFormat("dd/MM/yyyy");
fecha.setI18n(i18n);
tipoMantt = new ComboBox<>("Tipo de Mantenimiento");
List<TiposMantenimiento> tiposMantenimiento = databaseService.getTiposDeMantenimientos();
tipoMantt.setItems(tiposMantenimiento);
tipoMantt.addClassName("mantenimiento-combo");
// Listener para manejar el cambio en el tipo de mantenimiento
tipoMantt.addValueChangeListener(e -> {
TiposMantenimiento tipoSeleccionado = e.getValue();
if (tipoSeleccionado != null) {
String nomenclaturaValue = databaseService.getNomenclatura(tipoSeleccionado.getTipomantId());
nomenclatura.setValue(nomenclaturaValue);
fecha.setValue(LocalDate.now());
}
});
HorizontalLayout fechaLayout = new HorizontalLayout();
fechaLayout.add(fecha);
fechaLayout.addAndExpand(new HorizontalLayout());
fechaLayout.add(tipoMantt, nomenclatura);
fechaLayout.setWidthFull();
HorizontalLayout departamentoUsuarioLayout = new HorizontalLayout();
area = new ComboBox<>("Área o Departamento:");
area.setRequired(true);
List<DepartamentosModel> areas = databaseService.getDepartamentos();
area.setItems(areas);
usuario = new ComboBox<>("Usuario:");
List<Usuario> usuarios = databaseService.getUsuarios();
usuario.setItems(usuarios);
usuario.setItemLabelGenerator(Usuario::getNombre);
usuario.setRequired(true);
usuario.addValueChangeListener(e -> {
Usuario usuarioSeleccionado = e.getValue();
if (usuarioSeleccionado != null) {
String empleadoId = usuarioSeleccionado.getEmpleadoId();
String nombreUsuario = usuarioSeleccionado.getNombre();
//userSignSpan.setText(nombreUsuario);
} else {
//userSignSpan.setText("S.M.T Nombre");
}
});
txtNombreEquipo = new TextField("Nombre del Equipo:");
departamentoUsuarioLayout.add(area, usuario, txtNombreEquipo);
departamentoUsuarioLayout.setWidthFull();
createHardwareSection(databaseService);
addActualizacionesSection();
signLayout();
buttons();
headerLayout.add(btnListado);
mainLayout.add(fechaLayout, departamentoUsuarioLayout, controlsLayout, actualizacionesLayout, firmasLayout, botonesLayout);
add(headerLayout, mainLayout);
}
// Metodo para inicializar el formulario de hardware
private void createHardwareSection(DatabaseService databaseService) {
HorizontalLayout etiquetaLayout = new HorizontalLayout();
Span etiqueta = new Span("Limpieza de Equipo Realizada");
Button btnAgregarTipo = new Button(new Icon(VaadinIcon.PLUS));
btnAgregarTipo.addThemeVariants(ButtonVariant.LUMO_ICON);
btnAgregarTipo.setAriaLabel("Agregar Equipo");
btnAgregarTipo.addClickListener(e -> {
addNuevoTipo();
});
etiquetaLayout.add(etiqueta, btnAgregarTipo);
controlsLayout.add(etiquetaLayout);
controlsLayout.setSpacing(false);
addNuevoTipo();
}
// Método para crear el combo box y campos de texto para hardware en tiempo de ejecución
private List<HorizontalLayout> hardwareLayouts = new ArrayList<>();
private void addNuevoTipo() {
ComboBox<TiposHardware> tipoHardware = new ComboBox<>();
tipoHardware.setPlaceholder("Tipos de Hardware");
tipoHardware.setItemLabelGenerator(TiposHardware::getNombreHardware);
tipoHardware.setItems(databaseService.getTiposHardware());
tipoHardware.setSizeFull();
TextField noSerie = new TextField();
noSerie.setEnabled(false);
noSerie.setRequired(true);
noSerie.setPlaceholder("No. de Serie");
noSerie.setSizeFull();
noSerie.addValueChangeListener(e -> {
String upperCaseValue = e.getValue().toUpperCase();
noSerie.setValue(upperCaseValue);
});
TextField modelo = new TextField();
modelo.setEnabled(false);
modelo.setRequired(true);
modelo.setPlaceholder("Modelo");
modelo.setSizeFull();
modelo.addValueChangeListener(event -> {
String upperCaseValue = event.getValue().toUpperCase();
modelo.setValue(upperCaseValue);
});
TextField placa = new TextField();
placa.setEnabled(false);
placa.setRequired(true);
placa.setPlaceholder("Placa");
placa.setSizeFull();
// Validacion para que este campo solo acepte numeros
placa.getElement().executeJs(
"this.addEventListener('input', function(e) { " +
" e.target.value = e.target.value.replace(/[^0-9]/g, '');" + // Solo permite dígitos
"});"
);
tipoHardware.addValueChangeListener(event -> {
TiposHardware tipoSeleccionado = event.getValue();
if (tipoSeleccionado != null) {
String nombreTipo = tipoSeleccionado.getNombreHardware();
if ("TECLADO".equals(nombreTipo)) {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
} else if ("MOUSE".equals(nombreTipo)) {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
} else {
noSerie.setEnabled(true);
modelo.setEnabled(true);
placa.setEnabled(true);
}
} else {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
}
});
Button btnEliminar = new Button(new Icon(VaadinIcon.TRASH));
btnEliminar.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_ERROR);
btnEliminar.setAriaLabel("Eliminar Tipo");
//Crear nuevo layout horizontal con estos campos
HorizontalLayout hardwareDetailsLayout = new HorizontalLayout();
hardwareDetailsLayout.add(tipoHardware, noSerie, modelo, placa, btnEliminar);
hardwareDetailsLayout.setWidthFull();
hardwareLayouts.add(hardwareDetailsLayout);
controlsLayout.add(hardwareDetailsLayout);
//Listener para eliminar el tipo
btnEliminar.addClickListener(event -> {
controlsLayout.remove(hardwareDetailsLayout);
});
controlsLayout.add(hardwareDetailsLayout);
controlsLayout.setSizeFull();
}
private void addActualizacionesSection() {
VerticalLayout etiquetaLayout = new VerticalLayout();
Span Titulo = new Span("Actualizaciones de Seguridad Informatica:");
etiquetaLayout.add(Titulo);
actualizaciones = new CheckboxGroup<>();
actualizaciones.setLabel("Actualizaciones Necesarias");
actualizaciones.setItems("S.O", "Antivirus", "Firewall");
formaGroup = new RadioButtonGroup<>();
formaGroup.setLabel("Actividad Realizada de Forma:");
formaGroup.setRequired(true);
formaGroup.setItems("Remota", "Manual");
txtCuales = new TextArea();
txtCuales.setLabel("¿Cuáles?");
txtCuales.setEnabled(false);
txtCuales.setWidthFull();
masActualizacionesGroup = new RadioButtonGroup<>();
masActualizacionesGroup.setRequired(true);
masActualizacionesGroup.setLabel("¿Requiere más actualizaciones?");
masActualizacionesGroup.setItems("Si", "No");
masActualizacionesGroup.addValueChangeListener(e -> {
if ("Si".equals(e.getValue())) {
txtCuales.setEnabled(true);
txtCuales.setRequired(true);
txtCuales.clear();
} else {
txtCuales.setEnabled(false);
txtCuales.setRequired(false);
txtCuales.clear();
}
});
txtReparacion = new TextArea("Reparación Realizada:");
txtReparacion.setWidthFull();
txtReparacion.setHeight("100px");
HorizontalLayout formasLayout = new HorizontalLayout();
formasLayout.add(formaGroup, masActualizacionesGroup, txtCuales);
formasLayout.setSizeFull();
actualizacionesLayout.add(Titulo, actualizaciones, formasLayout, txtReparacion);
actualizacionesLayout.setSpacing(false);
}
private void signLayout() {
VerticalLayout userSignLayout = new VerticalLayout();
userSignPad = new SignaturePad();
userSignPad.setBackgroundColor("#FFFFFF");
userSignPad.setHeight("200px");
userSignPad.setPenColor("#000000");
userSignPad.getElement().getStyle().set("border", "1px solid black");
Span tituloUser = new Span("Usuario Interno");
userSignLayout.setSizeFull();
userSignLayout.setSpacing(true);
userSignLayout.setSpacing(false);
userSignLayout.setAlignItems(Alignment.CENTER);
userSignLayout.add(userSignPad, userSignSpan, tituloUser);
VerticalLayout smtSignLayout = new VerticalLayout();
smtSignPad = new SignaturePad();
smtSignPad.setHeight("200px");
smtSignPad.setBackgroundColor("#FFFFFF");
smtSignPad.setPenColor("#000000");
smtSignPad.getElement().getStyle().set("border", "1px solid black");
String u = securityService.getAuthenticatedUser();
Span smtSignSpan = new Span(u);
Span tituloSMT = new Span("Responsable de Soporte");
smtSignLayout.setSizeFull();
smtSignLayout.setSpacing(true);
smtSignLayout.setSpacing(false);
smtSignLayout.setAlignItems(Alignment.CENTER);
smtSignLayout.add(smtSignPad, smtSignSpan, tituloSMT);
VerticalLayout gcialSignLayout = new VerticalLayout();
Image firmaGcia = new Image("images/FirmaGerenteTI.png", "Firma Gerente de Sistemas");
firmaGcia.setHeight("200px");
firmaGcia.setWidthFull();
Span gciatiSignSpan = new Span("Ing. Javier Patiño Martinez");
Span tituloGerente = new Span("Gerente de T.I");
gcialSignLayout.setSizeFull();
gcialSignLayout.setSpacing(false);
gcialSignLayout.setAlignItems(Alignment.CENTER);
gcialSignLayout.add(firmaGcia, gciatiSignSpan, tituloGerente);
firmasLayout.add(userSignLayout, smtSignLayout, gcialSignLayout);
firmasLayout.setWidthFull();
firmasLayout.setSpacing(false);
firmasLayout.setJustifyContentMode(JustifyContentMode.CENTER);
}
// Metodo para verificar si la firma corresponde a una cadena de firma vacia
private boolean esFirmaVacia(String firmaBase64) {
String firmaVacia = "iVBORw0KGgoAAAANSUhEUgAAAXkAAAD8CAYAAACSCdTiAAAIbElEQVR4Xu3UAQ0AIAwDQeZfNCPI+Nwc9Lp07rvjCBAgQCApMEY+2atQBAgQ+AJG3iMQIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBBYAuXtOkIWm1QAAAAASUVORK5CYII=";
return firmaBase64.equals(firmaVacia);
}
private void buttons() {
VerticalLayout buttonsLayout = new VerticalLayout();
Button btnGuardar = new Button("Guardar", LineAwesomeIcon.SAVE.create());
btnGuardar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
btnGuardar.addThemeVariants(ButtonVariant.LUMO_LARGE);
btnGuardar.addClickListener(event -> {
fechaSeleccionada = fecha.getValue();
guardarMantenimiento();
});
buttonsLayout.setSizeFull();
buttonsLayout.add(btnGuardar);
buttonsLayout.setAlignItems(Alignment.CENTER);
botonesLayout.add(buttonsLayout);
botonesLayout.setSizeFull();
//botonesLayout.setAlignItems(Alignment.CENTER);
}
// METODO PARA ENVIAR CORREOS ELECTRONICOS
private void enviarCorreo() {
Usuario usuarioSeleccionado = usuario.getValue();
if (usuarioSeleccionado != null && usuarioSeleccionado.getEmail() != null) {
String destinatario = usuarioSeleccionado.getEmail();
String asunto = "MANTENIMIENTO DE EQUIPO DE COMPUTO REALIZADO";
String cuerpo = "<html>" +
"<body>" +
"<img src='cid:image_id'/>" +
"</body>" +
"</html>";
String imagePath = "META-INF/resources/images/imgCorreo/correoMantt.png";
emailService.enviarCorreo(destinatario, asunto, cuerpo, imagePath);
} else {
Notification.show("Por favor selecciona un usuario", 4000, Notification.Position.MIDDLE);
}
}
private void guardarMantenimiento() {
TiposMantenimiento tiposMantenimiento = tipoMantt.getValue();
String tipoMantId = tiposMantenimiento != null ? tiposMantenimiento.getTipomantId() : null;
String justificacionValue = jsutificacion != null ? jsutificacion.getValue() : null;
String reparacionValue = txtReparacion != null ? txtReparacion.getValue() : null;
DepartamentosModel departamentoSeleccionado = area.getValue();
String departamentoId = departamentoSeleccionado != null ? departamentoSeleccionado.getDepartamentoId().toString() : null;
Usuario usuarioSeleccionado = usuario.getValue();
String empleadoId = usuarioSeleccionado != null ? usuarioSeleccionado.getEmpleadoId().toString() : null;
String equipoId = txtNombreEquipo.getValue();
String formaSeleccionada = formaGroup.getValue();
String formaMantt = null;
if ("Remota".equals(formaSeleccionada)) {
formaMantt = "R";
} else if ("Manual".equals(formaSeleccionada)) {
formaMantt = "M";
}
// Validación de campos obligatorios
if (fechaSeleccionada == null || tipoMantId == null || departamentoId == null || empleadoId == null ||
equipoId == null || equipoId.trim().isEmpty() || formaMantt == null) {
Notification.show("Por favor, completa todos los campos requeridos", 4000, Notification.Position.MIDDLE);
return;
}
byte[] userSignatureBytes = userSignPad.getImageBase64();
byte[] smtSignatureBytes = smtSignPad.getImageBase64();
//byte[] gciaSignatureBytes = gciatiSignPad.getImageBase64();
String userSignatureBase64 = Base64.getEncoder().encodeToString(userSignatureBytes);
String smtSignatureBase64 = Base64.getEncoder().encodeToString(smtSignatureBytes);
//String gciaSignatureBase64 = Base64.getEncoder().encodeToString(gciaSignatureBytes);
if (esFirmaVacia(userSignatureBase64)) userSignatureBase64 = null;
if (esFirmaVacia(smtSignatureBase64)) smtSignatureBase64 = null;
//if (esFirmaVacia(gciaSignatureBase64)) gciaSignatureBase64 = null;
// Validación de campos de hardware
List<Map<String, String>> detallesHardware = new ArrayList<>();
for (HorizontalLayout layout : hardwareLayouts) {
ComboBox<TiposHardware> tipoHardware = (ComboBox<TiposHardware>) layout.getComponentAt(0);
TextField noSerie = (TextField) layout.getComponentAt(1);
TextField modelo = (TextField) layout.getComponentAt(2);
TextField placa = (TextField) layout.getComponentAt(3);
TiposHardware tipoSeleccionado = tipoHardware.getValue();
if (tipoSeleccionado == null) {
Notification.show("Por favor, selecciona un tipo de hardware", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
boolean esOpcional = Arrays.asList("TECLADO", "MOUSE").contains(tipoSeleccionado.getNombreHardware());
String numSerie = noSerie.getValue();
String modeloVal = modelo.getValue();
String placaVal = placa.getValue();
if (!esOpcional && (modeloVal == null || modeloVal.isEmpty() || numSerie == null || numSerie.isEmpty() || placaVal == null || placaVal.isEmpty())) {
Notification.show("Por favor, completa todos los campos de hardware.", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
Map<String, String> hw = new HashMap<>();
hw.put("tipoHardwareId", tipoSeleccionado.getTipoHardwareId());
hw.put("numSerie", numSerie);
hw.put("modelo", modeloVal);
hw.put("placa", placaVal);
detallesHardware.add(hw);
}
Set<String> actualizacionesSeleccionadas = actualizaciones.getSelectedItems();
String otrasActualizaciones = null;
if ("Si".equals(masActualizacionesGroup.getValue())) {
otrasActualizaciones = txtCuales.getValue();
if (otrasActualizaciones == null || otrasActualizaciones.trim().isEmpty()) {
Notification.show("Especifica las otras actualizaciones", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
}
// Una vez que validamos todos los campos del formulario, procedemos a insertar en BD
try {
int isInserted = databaseService.insertarMantenimiento(fechaSeleccionada, tipoMantId, departamentoId, empleadoId, formaMantt, equipoId, userSignatureBase64, smtSignatureBase64, null, justificacionValue, reparacionValue);
if (isInserted <= 0) {
Notification.show("Error al guardar el mantenimiento", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
int mantenimientoId = databaseService.getUltimoMantenimientoId();
for (Map<String, String> hw : detallesHardware) {
boolean ok = databaseService.insertarHardware(
hw.get("tipoHardwareId"),
hw.get("numSerie"),
hw.get("modelo"),
hw.get("placa"),
mantenimientoId
);
if (!ok) {
Notification.show("Error al insertar detalles del hardware: ", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
for (String act : actualizacionesSeleccionadas) {
boolean ok = databaseService.insertActualizacionSeg(act, null, mantenimientoId);
if (!ok) {
Notification.show("Error al insertar actualización de seguridad", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
if (otrasActualizaciones != null) {
boolean ok = databaseService.insertActualizacionSeg("Otras", otrasActualizaciones, mantenimientoId);
if (!ok) {
Notification.show("Error al insertar otras actualizaciones", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
// === EXITO ===
Notification.show("¡Mantenimiento guardado exitosamente!", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
try {
enviarCorreo();
} catch (Exception e) {
Notification.show("Error al enviar el correo", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
e.printStackTrace();
}
// Limpiar campos
fecha.clear();
tipoMantt.clear();
area.clear();
usuario.clear();
txtNombreEquipo.clear();
formaGroup.clear();
actualizaciones.clear();
masActualizacionesGroup.clear();
txtCuales.clear();
userSignPad.clear();
smtSignPad.clear();
//gciatiSignPad.clear();
txtReparacion.clear();
for (HorizontalLayout layout : hardwareLayouts) {
((ComboBox<?>) layout.getComponentAt(0)).clear();
((TextField) layout.getComponentAt(1)).clear();
((TextField) layout.getComponentAt(2)).clear();
((TextField) layout.getComponentAt(3)).clear();
}
UI.getCurrent().navigate("/");
} catch (Exception ex) {
Notification.show("Ocurrio un error inesperado: " + ex.getMessage(), 5000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
ex.printStackTrace();
}
}
// Muestra un dialogo con el listado de los mantenimientos correctivos realizados
private void verListadoMantenimientos() {
Dialog dialog = new Dialog();
dialog.setSizeFull();
dialog.setCloseOnEsc(true);
dialog.setCloseOnOutsideClick(true);
dialog.setHeaderTitle("Listado de Mantenimientos Correctivos");
Grid<MantCorrectivosModel> grid = new Grid<>(MantCorrectivosModel.class, false);
grid.addColumn(MantCorrectivosModel::getMantenimientoId)
.setHeader("No.").setAutoWidth(true);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
grid.addColumn(item -> item.getFecha() != null ? item.getFecha().format(formatter) : "N/A")
.setHeader("Fecha:").setAutoWidth(true);
grid.addColumn(MantCorrectivosModel::getTipo)
.setHeader("Tipo:").setAutoWidth(true);
grid.addColumn(MantCorrectivosModel::getArea)
.setHeader("Área:").setAutoWidth(true);
grid.addColumn(MantCorrectivosModel::getNombre)
.setHeader("Usuario:").setAutoWidth(true);
grid.addColumn(MantCorrectivosModel::getForma)
.setHeader("Forma:").setAutoWidth(true);
grid.addColumn(MantCorrectivosModel::getNomequipo)
.setHeader("Equipo:").setAutoWidth(true);
grid.setItems(databaseService.getMantenimientosCorrectivos(2));
grid.setItemDetailsRenderer(ReparacionDetails.createReparacionesDetails());
grid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);
Button closeButton = new Button("Cerrar", e -> dialog.close());
closeButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
dialog.add(grid, closeButton);
dialog.open();
}
private static class ReparacionDetails extends FormLayout {
private final TextArea txtReparacion = new TextArea("Reparación realizada:");
public ReparacionDetails() {
txtReparacion.setReadOnly(true);
add(txtReparacion);
setResponsiveSteps(new ResponsiveStep("0", 1));
setColspan(txtReparacion, 1);
}
public void setModel(MantCorrectivosModel model) {
txtReparacion.setValue(model.getReparacion() != null ? model.getReparacion() : "");
}
private static ComponentRenderer<ReparacionDetails, MantCorrectivosModel> createReparacionesDetails() {
return new ComponentRenderer<>(ReparacionDetails::new, ReparacionDetails::setModel);
}
}
}

+ 853
- 0
src/main/java/mx/gob/jumapacelaya/ui/MantenimientoView.java View File

@ -0,0 +1,853 @@
package mx.gob.jumapacelaya.ui;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.f0rce.signaturepad.SignaturePad;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.models.*;
import mx.gob.jumapacelaya.services.DatabaseService;
import mx.gob.jumapacelaya.services.EmailService;
import mx.gob.jumapacelaya.services.SecurityService;
import mx.gob.jumapacelaya.services.UserService;
import oracle.net.aso.h;
import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.lineawesome.LineAwesomeIcon;
import java.time.LocalDate;
import java.util.*;
@PermitAll
@PageTitle("Mantenimiento")
@Route(value = "mantenimiento", layout = MainLayout.class)
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class MantenimientoView extends VerticalLayout implements BeforeEnterObserver {
private final SecurityService securityService;
private final VerticalLayout controlsLayout;
private final DatabaseService databaseService;
private final VerticalLayout actualizacionesLayout;
private final VerticalLayout etiquetaLayout;
private final HorizontalLayout firmasLayout;
private final DatePicker fecha;
private final TextField txtPlananualID;
private final ComboBox<TiposMantenimiento> tipoMantt;
private final ComboBox<DepartamentosModel> area;
private final ComboBox<Usuario> usuario;
private final TextField txtNombreEquipo;
private final UserService userService;
private final EmailService emailService;
private RadioButtonGroup<String> formaGroup;
private CheckboxGroup<String> actualizaciones;
private final HorizontalLayout botonesLayout;
private TextArea txtCuales;
private RadioButtonGroup<String> masActualizacionesGroup;
private SignaturePad userSignPad;
private SignaturePad smtSignPad;
//private SignaturePad gciatiSignPad;
private PlanAnual planAnualActual;
private LocalDate fechaProgramada;
private LocalDate fechaSeleccionada;
private TextArea jsutificacion;
private VerticalLayout mainLayout;
Span userSignSpan = new Span("Nombre Usuario");
public MantenimientoView(UserService userService, SecurityService securityService, EmailService emailService, DatabaseService databaseService) {
this.databaseService = databaseService;
this.controlsLayout = new VerticalLayout();
this.actualizacionesLayout = new VerticalLayout();
this.etiquetaLayout = new VerticalLayout();
this.firmasLayout = new HorizontalLayout();
this.botonesLayout = new HorizontalLayout();
this.securityService = securityService;
this.userService = userService;
this.emailService = emailService;
mainLayout = new VerticalLayout();
mainLayout.setHeightFull();
mainLayout.getStyle()
.set("box-shadow","0 4px 8px rgba(0,0,0,0.2)")
.set("border-radius", "12px")
.set("background-color", "white")
.set("padding", "1rem")
.set("margin", "1rem auto");
HorizontalLayout fechaLayout = new HorizontalLayout();
//Componentes de texto
TextField nomenclatura = new TextField("Nomenclatura");
nomenclatura.setReadOnly(true);
nomenclatura.addClassName("mantenimiento-text-field");
TextArea otras = new TextArea("¿Cuales?");
otras.setEnabled(false);
otras.addClassName("mantenimiento-text-field");
//Selector de fecha
this.fecha = new DatePicker("Fecha");
fecha.setRequired(true);
fecha.setLocale(new Locale("es", "MX"));
DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n()
.setWeekdays(List.of("Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"))
.setWeekdaysShort(List.of("Dom","Lun","Mar","Mié","Jue","Vie","Sáb"))
.setMonthNames(List.of("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"))
.setFirstDayOfWeek(1)
.setToday("Hoy")
.setCancel("Cancelar")
.setDateFormat("dd/MM/yyyy");
fecha.setI18n(i18n);
// Campo de texto para el ID de MTTOPROGRAMADO
this.txtPlananualID = new TextField("Plan Anual ID");
txtPlananualID.setReadOnly(true);
txtPlananualID.addClassName("mantenimiento-text-field");
// ComboBox Tipo de Mantenimiento
this.tipoMantt = new ComboBox<>("Tipo de Mantenimiento");
List<TiposMantenimiento> tiposMantenimiento = databaseService.getTiposDeMantenimientos();
tipoMantt.setItems(tiposMantenimiento);
tipoMantt.addClassName("mantenimiento-combo");
// Listener para manejar el cambio en el tipo de mantenimiento
tipoMantt.addValueChangeListener(event -> {
TiposMantenimiento tipoSeleccionado = event.getValue();
if (tipoSeleccionado != null) {
// Actualizar nomenclatura dependiendo del tipo de mantenimiento
String nomenclaturaValue = databaseService.getNomenclatura(tipoSeleccionado.getTipomantId());
nomenclatura.setValue(nomenclaturaValue);
// Si el tipo es preventivo se establecerá la fecha automáticamente a la fecha del sistema
if ("1".equals(tipoSeleccionado.getTipomantId())) { // 1 es para PREVENTIVO
this.fecha.setValue(LocalDate.now());
etiquetaLayout.setVisible(false);
// Limpiar el layout de correctivo si es necesario
etiquetaLayout.removeAll();
} else if ("2".equals(tipoSeleccionado.getTipomantId())) { // 2 es para CORRECTIVO
this.fecha.clear();
etiquetaLayout.setVisible(true);
//correctivoLayout();
} else {
// Para otros tipos de mantenimiento
this.fecha.clear();
etiquetaLayout.setVisible(false);
etiquetaLayout.removeAll(); // Limpia el layout para otros tipos
}
} else {
nomenclatura.clear();
this.fecha.clear();
etiquetaLayout.setVisible(false);
etiquetaLayout.removeAll(); // Limpia el layout
}
});
fechaLayout.add(this.fecha/*, this.txtPlananualID*/);
fechaLayout.addAndExpand(new HorizontalLayout());
fechaLayout.add(tipoMantt, nomenclatura);
fechaLayout.setWidthFull();
HorizontalLayout departamentoLayout = new HorizontalLayout();
//ComboBox Area o Departamento
this.area = new ComboBox<>("Area o Departamento");
area.setRequired(true);
List<DepartamentosModel> areas = databaseService.getDepartamentos();
area.setItems(areas);
this.usuario = new ComboBox<>("Usuario");
List<Usuario> usuarios = databaseService.getUsuarios();
usuario.setItems(usuarios);
usuario.setItemLabelGenerator(Usuario::getNombre);
usuario.setRequired(true);
usuario.addValueChangeListener(event -> {
Usuario usuarioSeleccionado = event.getValue();
if (usuarioSeleccionado != null) {
String empleadoId = usuarioSeleccionado.getEmpleadoId();
String nombreUsuario = usuarioSeleccionado.getNombre();
userSignSpan.setText(nombreUsuario);
} else {
userSignSpan.setText("S.M.T Nombre");
}
});
// Boton auxiliar para probar el envio de los correos electronicos
Button btnEnviarCorreo = new Button("Enviar correo de prueba");
btnEnviarCorreo.addClickListener(event -> enviarCorreo());
this.txtNombreEquipo = new TextField("Nombre del Equipo");
txtNombreEquipo.setRequired(true);
//txtNombreEquipo.setReadOnly(true);
departamentoLayout.add(area, usuario/*, btnEnviarCorreo*/, txtNombreEquipo);
departamentoLayout.setWidthFull();
createHardwareSection(databaseService);
addActualizacionesSection();
//correctivoLayout();
signLayout();
buttons();
mainLayout.add(fechaLayout, departamentoLayout, controlsLayout, actualizacionesLayout, etiquetaLayout, firmasLayout, botonesLayout);
add(mainLayout);
}
private void createHardwareSection(DatabaseService databaseService) {
HorizontalLayout etiquetaLayout = new HorizontalLayout();
Span etiqueta = new Span("Limpieza de Equipo Realizada");
//Boton para agregar otro tipo de hardware
Button btnAgregarTipo = new Button(new Icon(VaadinIcon.PLUS));
btnAgregarTipo.addThemeVariants(ButtonVariant.LUMO_ICON);
btnAgregarTipo.setAriaLabel("Agregar Tipo");
//Listener del boton para agregar mas
btnAgregarTipo.addClickListener(event -> {
addNuevoTipo();
});
etiquetaLayout.add(etiqueta, btnAgregarTipo);
controlsLayout.add(etiquetaLayout);
controlsLayout.setSpacing(false);
addNuevoTipo();
}
//Metodo para agregar un nuevo ComboBox de tipo de hardware y campos de texto
private List<HorizontalLayout> hardwareLayouts = new ArrayList<>();
private void addNuevoTipo() {
ComboBox<TiposHardware> tipoHardware = new ComboBox<>();
tipoHardware.setPlaceholder("Tipo de hardware");
tipoHardware.setItemLabelGenerator(TiposHardware::getNombreHardware);
tipoHardware.setItems(databaseService.getTiposHardware());
tipoHardware.setSizeFull();
TextField noSerie = new TextField();
noSerie.setEnabled(false);
noSerie.setRequired(true);
noSerie.setPlaceholder("No. Serie");
noSerie.setSizeFull();
noSerie.addValueChangeListener(event -> {
String upperCaseValue = event.getValue().toUpperCase();
noSerie.setValue(upperCaseValue);
});
// Validacion para que este campo solo acepte numeros
/*noSerie.getElement().executeJs(
"this.addEventListener('input', function(e) { " +
" e.target.value = e.target.value.replace(/[^0-9]/g, '');" + // Solo permite dígitos
"});"
);*/
TextField modelo = new TextField();
modelo.setEnabled(false);
modelo.setRequired(true);
modelo.setPlaceholder("Modelo");
modelo.setSizeFull();
modelo.addValueChangeListener(event -> {
String upperCaseValue = event.getValue().toUpperCase();
modelo.setValue(upperCaseValue);
});
TextField placa = new TextField();
placa.setEnabled(false);
placa.setRequired(true);
placa.setPlaceholder("Placa");
placa.setSizeFull();
// Validacion para que este campo solo acepte numeros
placa.getElement().executeJs(
"this.addEventListener('input', function(e) { " +
" e.target.value = e.target.value.replace(/[^0-9]/g, '');" + // Solo permite dígitos
"});"
);
tipoHardware.addValueChangeListener(event -> {
TiposHardware tipoSeleccionado = event.getValue();
if (tipoSeleccionado != null) {
String nombreTipo = tipoSeleccionado.getNombreHardware();
if ("TECLADO".equals(nombreTipo)) {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
} else if ("MOUSE".equals(nombreTipo)) {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
} else {
noSerie.setEnabled(true);
modelo.setEnabled(true);
placa.setEnabled(true);
}
} else {
noSerie.setEnabled(false);
modelo.setEnabled(false);
placa.setEnabled(false);
}
});
//Boton para eliminar ese conjunto de hardware
Button btnEliminar = new Button(new Icon(VaadinIcon.TRASH));
btnEliminar.addThemeVariants(ButtonVariant.LUMO_ICON, ButtonVariant.LUMO_ERROR);
btnEliminar.setAriaLabel("Eliminar Tipo");
//Crear nuevo layout horizontal con estos campos
HorizontalLayout hardwareDetailsLayout = new HorizontalLayout();
hardwareDetailsLayout.add(tipoHardware, noSerie, modelo, placa, btnEliminar);
hardwareDetailsLayout.setWidthFull();
hardwareLayouts.add(hardwareDetailsLayout);
controlsLayout.add(hardwareDetailsLayout);
//Listener para eliminar el tipo
btnEliminar.addClickListener(event -> {
controlsLayout.remove(hardwareDetailsLayout);
});
controlsLayout.add(hardwareDetailsLayout);
controlsLayout.setSizeFull();
}
private void addActualizacionesSection() {
VerticalLayout etiquetaLayout = new VerticalLayout();
Span Titulo = new Span("Actualizaciones de Seguridad Informatica:");
etiquetaLayout.add(Titulo);
this.actualizaciones = new CheckboxGroup<>();
actualizaciones.setLabel("Actualizaciones Necesarias");
actualizaciones.setItems("S.O", "Antivirus", "Firewall");
this.formaGroup = new RadioButtonGroup<>();
formaGroup.setRequired(true);
formaGroup.setLabel("Actividad Realizada de Forma:");
formaGroup.setItems("Remota", "Manual");
this.txtCuales = new TextArea();
txtCuales.setLabel("¿Cuales?");
txtCuales.setEnabled(false);
txtCuales.setWidthFull();
this.masActualizacionesGroup= new RadioButtonGroup<>();
masActualizacionesGroup.setRequired(true);
masActualizacionesGroup.setLabel("¿Requiere Más Actualizaciones?");
masActualizacionesGroup.setItems("Si","No");
masActualizacionesGroup.addValueChangeListener(event -> {
if ("Si".equals(event.getValue())) {
txtCuales.setEnabled(true);
txtCuales.setRequired(true);
txtCuales.setMaxHeight("100px");
} else {
txtCuales.setEnabled(false);
txtCuales.setRequired(false);
txtCuales.clear();
}
});
/*VerticalLayout actualizacionesGroup = new VerticalLayout();
actualizacionesGroup.add(actualizaciones);*/
HorizontalLayout formasLayout = new HorizontalLayout();
formasLayout.add(formaGroup, masActualizacionesGroup, txtCuales);
formasLayout.setSizeFull();
actualizacionesLayout.add(Titulo, actualizaciones, formasLayout);
actualizacionesLayout.setSpacing(false);
}
/* Formulario para cuando el mnatenimiento es de tipo CORRECTIVO */
/*private void correctivoLayout() {
Span Titulo = new Span("Reparación Realizada al Equipo: ");
// Verificar el ID del tipo de mantenimiento
TiposMantenimiento tiposMantenimiento = tipoMantt.getValue();
if (tiposMantenimiento != null && "2".equals(tiposMantenimiento.getTipomantId())) { // Solo si el tipo es CORRECTIVO
TextField txtModelo = new TextField();
txtModelo.setPlaceholder("Modelo");
txtModelo.setWidth("240px");
NumberField txtSerie = new NumberField();
txtSerie.setPlaceholder("No. Serie");
txtSerie.setWidth("240px");
TextField txtSoft = new TextField();
txtSoft.setPlaceholder("Instalación de Software");
txtSoft.setWidth("500px");
TextField txtRepHard = new TextField();
txtRepHard.setPlaceholder("Reparación de Hardware");
txtRepHard.setWidth("500px");
TextField txtCamDisp = new TextField();
txtCamDisp.setPlaceholder("Cambio de Dispositivo");
txtCamDisp.setWidth("500px");
HorizontalLayout model = new HorizontalLayout();
model.add(txtModelo, txtSerie, txtSoft);
model.setSizeFull();
HorizontalLayout hard = new HorizontalLayout();
hard.add(txtRepHard, txtCamDisp);
hard.setSizeFull();
etiquetaLayout.add(Titulo, model, hard);
etiquetaLayout.setVisible(true); // Asegúrate de que el layout esté visible
} else {
etiquetaLayout.setVisible(false); // Ocultar si no es correctivo
}
}*/
private String emptySignature;
private void signLayout() {
VerticalLayout userSignLayout = new VerticalLayout();
userSignPad = new SignaturePad();
userSignPad.setBackgroundColor("#FFFFFF");
userSignPad.setHeight("200px");
userSignPad.setPenColor("#000000");
userSignPad.getElement().getStyle().set("border", "1px solid black");
Span tituloUser = new Span("Usuario Interno");
userSignLayout.setSizeFull();
userSignLayout.setSpacing(true);
userSignLayout.setSpacing(false);
userSignLayout.setAlignItems(Alignment.CENTER);
userSignLayout.add(userSignPad, userSignSpan, tituloUser);
VerticalLayout smtSignLayout = new VerticalLayout();
smtSignPad = new SignaturePad();
smtSignPad.setHeight("200px");
smtSignPad.setBackgroundColor("#FFFFFF");
smtSignPad.setPenColor("#000000");
smtSignPad.getElement().getStyle().set("border", "1px solid black");
String u = securityService.getAuthenticatedUser();
Span smtSignSpan = new Span(u);
Span tituloSMT = new Span("Responsable de Soporte");
smtSignLayout.setSizeFull();
smtSignLayout.setSpacing(true);
smtSignLayout.setSpacing(false);
smtSignLayout.setAlignItems(Alignment.CENTER);
smtSignLayout.add(smtSignPad, smtSignSpan, tituloSMT);
VerticalLayout gcialSignLayout = new VerticalLayout();
Image firmaGcia = new Image("images/FirmaGerenteTI.png", "Firma Gerente de Sistemas");
firmaGcia.setHeight("200px");
firmaGcia.setWidthFull();
Span gciatiSignSpan = new Span("Ing. Javier Patiño Martinez");
Span tituloGerente = new Span("Gerente de T.I");
gcialSignLayout.setSizeFull();
gcialSignLayout.setSpacing(false);
gcialSignLayout.setAlignItems(Alignment.CENTER);
gcialSignLayout.add(firmaGcia, gciatiSignSpan, tituloGerente);
firmasLayout.add(userSignLayout, smtSignLayout, gcialSignLayout);
firmasLayout.setWidthFull();
firmasLayout.setSpacing(false);
firmasLayout.setJustifyContentMode(JustifyContentMode.CENTER);
}
// Metodo para verificar si la firma corresponde a una cadena de firma vacia
private boolean esFirmaVacia(String firmaBase64) {
String firmaVacia = "iVBORw0KGgoAAAANSUhEUgAAAXkAAAD8CAYAAACSCdTiAAAIbElEQVR4Xu3UAQ0AIAwDQeZfNCPI+Nwc9Lp07rvjCBAgQCApMEY+2atQBAgQ+AJG3iMQIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBAw8n6AAAECYQEjHy5XNAIECBh5P0CAAIGwgJEPlysaAQIEjLwfIECAQFjAyIfLFY0AAQJG3g8QIEAgLGDkw+WKRoAAASPvBwgQIBAWMPLhckUjQICAkfcDBAgQCAsY+XC5ohEgQMDI+wECBAiEBYx8uFzRCBAgYOT9AAECBMICRj5crmgECBBYAuXtOkIWm1QAAAAASUVORK5CYII=";
return firmaBase64.equals(firmaVacia);
}
private void buttons() {
VerticalLayout buttonsLayout = new VerticalLayout();
Button btnGuardar = new Button("Guardar", LineAwesomeIcon.SAVE.create());
btnGuardar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
btnGuardar.addThemeVariants(ButtonVariant.LUMO_LARGE);
btnGuardar.addClickListener(event -> {
if (planAnualActual == null) {
Notification.show("No se pudo cargar el Plan Anual. Verifica el ID.", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
}
if (planAnualActual != null) {
fechaProgramada = planAnualActual.getFechaProgramada();
fechaSeleccionada = fecha.getValue();
boolean mismoMes = fechaSeleccionada != null &&
fechaSeleccionada.getMonthValue() == fechaProgramada.getMonthValue() &&
fechaSeleccionada.getYear() == fechaProgramada.getYear();
if (!mismoMes) {
Dialog confirmDialog = new Dialog();
Span aviso = new Span("El mantenimiento esta fuera de tiempo, justifique el motivo");
jsutificacion = new TextArea();
jsutificacion.setSizeFull();
Button btnSi = new Button("Guardar",LineAwesomeIcon.SAVE_SOLID.create(), e -> {
confirmDialog.close();
guardarMantenimiento();
});
btnSi.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
VerticalLayout layout = new VerticalLayout(aviso, jsutificacion, btnSi);
layout.setSizeFull();
layout.setAlignItems(Alignment.CENTER);
confirmDialog.add(layout);
confirmDialog.open();
} else {
guardarMantenimiento();
}
}
});
buttonsLayout.setSizeFull();
buttonsLayout.add(btnGuardar);
buttonsLayout.setAlignItems(Alignment.CENTER);
botonesLayout.add(buttonsLayout);
botonesLayout.setSizeFull();
//botonesLayout.setAlignItems(Alignment.CENTER);
}
// METODO PARA ENVIAR CORREOS ELECTRONICOS
private void enviarCorreo() {
Usuario usuarioSeleccionado = usuario.getValue();
if (usuarioSeleccionado != null && usuarioSeleccionado.getEmail() != null) {
String destinatario = usuarioSeleccionado.getEmail();
String asunto = "MANTENIMIENTO DE EQUIPO DE COMPUTO REALIZADO";
String cuerpo = "<html>" +
"<body>" +
"<img src='cid:image_id'/>"+
"</body>" +
"</html>";
String imagePath = "META-INF/resources/images/imgCorreo/correoMantt.png";
emailService.enviarCorreo(destinatario, asunto, cuerpo, imagePath);
} else {
Notification.show("Por favor selecciona un usuario", 4000, Notification.Position.MIDDLE);
}
}
private void guardarMantenimiento() {
TiposMantenimiento tiposMantenimiento = tipoMantt.getValue();
String tipoMantId = tiposMantenimiento != null ? tiposMantenimiento.getTipomantId() : null;
String planAnualValue = txtPlananualID.getValue();
String justificacionValue = jsutificacion != null ? jsutificacion.getValue() : null;
String reparacionValue = null;
DepartamentosModel departamentoSeleccionado = area.getValue();
String departamentoId = departamentoSeleccionado != null ? departamentoSeleccionado.getDepartamentoId().toString() : null;
Usuario usuarioSeleccionado = usuario.getValue();
String empleadoId = usuarioSeleccionado != null ? usuarioSeleccionado.getEmpleadoId().toString() : null;
String equipoId = txtNombreEquipo.getValue();
String formaSeleccionada = formaGroup.getValue();
String formaMantt = null;
if ("Remota".equals(formaSeleccionada)) {
formaMantt = "R";
} else if ("Manual".equals(formaSeleccionada)) {
formaMantt = "M";
}
// Validación de campos obligatorios
if (fechaSeleccionada == null || tipoMantId == null || departamentoId == null || empleadoId == null ||
equipoId == null || equipoId.trim().isEmpty() || formaMantt == null || planAnualValue == null || planAnualValue.trim().isEmpty()) {
Notification.show("Por favor, completa todos los campos requeridos", 4000, Notification.Position.MIDDLE);
return;
}
byte[] userSignatureBytes = userSignPad.getImageBase64();
byte[] smtSignatureBytes = smtSignPad.getImageBase64();
//byte[] gciaSignatureBytes = gciatiSignPad.getImageBase64();
String userSignatureBase64 = Base64.getEncoder().encodeToString(userSignatureBytes);
String smtSignatureBase64 = Base64.getEncoder().encodeToString(smtSignatureBytes);
//String gciaSignatureBase64 = Base64.getEncoder().encodeToString(gciaSignatureBytes);
if (esFirmaVacia(userSignatureBase64)) userSignatureBase64 = null;
if (esFirmaVacia(smtSignatureBase64)) smtSignatureBase64 = null;
//if (esFirmaVacia(gciaSignatureBase64)) gciaSignatureBase64 = null;
// Validación de campos de hardware
List<Map<String, String>> detallesHardware = new ArrayList<>();
for (HorizontalLayout layout : hardwareLayouts) {
ComboBox<TiposHardware> tipoHardware = (ComboBox<TiposHardware>) layout.getComponentAt(0);
TextField noSerie = (TextField) layout.getComponentAt(1);
TextField modelo = (TextField) layout.getComponentAt(2);
TextField placa = (TextField) layout.getComponentAt(3);
TiposHardware tipoSeleccionado = tipoHardware.getValue();
if (tipoSeleccionado == null) {
Notification.show("Por favor, selecciona un tipo de hardware", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
boolean esOpcional = Arrays.asList("TECLADO", "MOUSE").contains(tipoSeleccionado.getNombreHardware());
String numSerie = noSerie.getValue();
String modeloVal = modelo.getValue();
String placaVal = placa.getValue();
if (!esOpcional && (modeloVal == null || modeloVal.isEmpty() || numSerie == null || numSerie.isEmpty() || placaVal == null || placaVal.isEmpty())) {
Notification.show("Por favor, completa todos los campos de hardware.", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
Map<String, String> hw = new HashMap<>();
hw.put("tipoHardwareId", tipoSeleccionado.getTipoHardwareId());
hw.put("numSerie", numSerie);
hw.put("modelo", modeloVal);
hw.put("placa", placaVal);
detallesHardware.add(hw);
}
Set<String> actualizacionesSeleccionadas = actualizaciones.getSelectedItems();
String otrasActualizaciones = null;
if ("Si".equals(masActualizacionesGroup.getValue())) {
otrasActualizaciones = txtCuales.getValue();
if (otrasActualizaciones == null || otrasActualizaciones.trim().isEmpty()) {
Notification.show("Especifica las otras actualizaciones", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_WARNING);
return;
}
}
// Una vez que validamos todos los campos del formulario, procedemos a insertar en BD
try {
int isInserted = databaseService.insertarMantenimiento(fechaSeleccionada, tipoMantId, departamentoId, empleadoId, formaMantt, equipoId, userSignatureBase64, smtSignatureBase64, planAnualValue, justificacionValue, reparacionValue);
if (isInserted <= 0) {
Notification.show("Error al guardar el mantenimiento", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
int mantenimientoId = databaseService.getUltimoMantenimientoId();
for (Map<String, String> hw : detallesHardware) {
boolean ok = databaseService.insertarHardware(
hw.get("tipoHardwareId"),
hw.get("numSerie"),
hw.get("modelo"),
hw.get("placa"),
mantenimientoId
);
if (!ok) {
Notification.show("Error al insertar detalles del hardware: ", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
for (String act : actualizacionesSeleccionadas) {
boolean ok = databaseService.insertActualizacionSeg(act, null, mantenimientoId);
if (!ok) {
Notification.show("Error al insertar actualización de seguridad", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
if (otrasActualizaciones != null) {
boolean ok = databaseService.insertActualizacionSeg("Otras", otrasActualizaciones, mantenimientoId);
if (!ok) {
Notification.show("Error al insertar otras actualizaciones", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
}
// === EXITO ===
Notification.show("¡Mantenimiento guardado exitosamente!", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
try {
enviarCorreo();
} catch (Exception e) {
Notification.show("Error al enviar el correo", 4000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
e.printStackTrace();
}
// Limpiar campos
fecha.clear();
txtPlananualID.clear();
tipoMantt.clear();
area.clear();
usuario.clear();
txtNombreEquipo.clear();
formaGroup.clear();
actualizaciones.clear();
masActualizacionesGroup.clear();
txtCuales.clear();
userSignPad.clear();
smtSignPad.clear();
//gciatiSignPad.clear();
for (HorizontalLayout layout : hardwareLayouts) {
((ComboBox<?>) layout.getComponentAt(0)).clear();
((TextField) layout.getComponentAt(1)).clear();
((TextField) layout.getComponentAt(2)).clear();
((TextField) layout.getComponentAt(3)).clear();
}
UI.getCurrent().navigate("/");
} catch (Exception ex) {
Notification.show("Ocurrio un error inesperado: " + ex.getMessage(), 5000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
ex.printStackTrace();
}
}
@Override
public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
String fechaParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("fecha") != null
? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("fecha").stream().findFirst().orElse(null)
: null;
String tipoParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("tipo") != null
? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("tipo").stream().findFirst().orElse(null)
: null;
String idParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("id") != null
? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("id").stream().findFirst().orElse(null)
: null;
if (idParam != null) {
try {
int id = Integer.parseInt(idParam);
planAnualActual = databaseService.getPlanAnualPorId(id);
} catch (NumberFormatException e) {
planAnualActual = null;
}
}
String equipoParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("nomEquipo") != null
? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("nomEquipo").stream().findFirst().orElse(null)
: null;
String deptoParam = beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("departamento") != null
? beforeEnterEvent.getLocation().getQueryParameters().getParameters().get("departamento").stream().findFirst().orElse(null)
: null;
if (fechaParam != null) {
try {
LocalDate fechaActual = LocalDate.parse(fechaParam);
this.fecha.setValue(fechaActual); // Establece la fecha en el DatePicker
} catch (Exception e) {
Notification.show("Error al establecer la fecha: " + e.getMessage(), 3000, Notification.Position.MIDDLE);
}
}
// Cambiamos el valor por el ID
if ("1".equals(tipoParam)) { // 1 es para PREVENTIVO
TiposMantenimiento preventivo = tipoMantt.getDataProvider()
.fetch(new com.vaadin.flow.data.provider.Query<>())
.filter(tipo -> "1".equals(tipo.getTipomantId()))
.findFirst()
.orElse(null);
if (preventivo != null) {
tipoMantt.setValue(preventivo);
tipoMantt.setReadOnly(true);
}
} else if ("2".equals(tipoParam)) { // 2 es para CORRECTIVO
TiposMantenimiento correctivo = tipoMantt.getDataProvider()
.fetch(new com.vaadin.flow.data.provider.Query<>())
.filter(tipo -> "2".equals(tipo.getTipomantId()))
.findFirst()
.orElse(null);
if (correctivo != null) {
tipoMantt.setValue(correctivo);
tipoMantt.setReadOnly(true);
}
}
// Establecemos el ID desde el plan anual
if (idParam != null) {
txtPlananualID.setValue(idParam); // Establece el ID en el campo de texto
} else {
txtPlananualID.setValue("Sin ID"); // O un valor por defecto si no hay ID
}
// Establecemos el valor del campo de texto Nombre de Equipo con el parametro que viene en la url
if (equipoParam != null) {
txtNombreEquipo.setValue(equipoParam);
} else {
txtNombreEquipo.setValue("Sin nombre");
}
// Establecemos el campo del departamento con el departamento desde el plan anual
if (deptoParam != null) {
Optional<DepartamentosModel> departamentoSeleccionado = area.getDataProvider()
.fetch(new com.vaadin.flow.data.provider.Query<>())
.filter(departamento -> departamento.getNombre().equals(deptoParam))
.findFirst();
if (departamentoSeleccionado.isPresent()) {
area.setValue(departamentoSeleccionado.get());
area.setReadOnly(true);
} else {
area.setValue(null);
}
}
}
}

+ 950
- 0
src/main/java/mx/gob/jumapacelaya/ui/PlanAnualView.java View File

@ -0,0 +1,950 @@
package mx.gob.jumapacelaya.ui;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.grid.HeaderRow;
import com.vaadin.flow.component.grid.contextmenu.GridContextMenu;
import com.vaadin.flow.component.grid.contextmenu.GridMenuItem;
import com.vaadin.flow.component.grid.dataview.GridListDataView;
import com.vaadin.flow.component.html.*;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.popover.Popover;
import com.vaadin.flow.component.popover.PopoverPosition;
import com.vaadin.flow.component.radiobutton.RadioButtonGroup;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.StreamRegistration;
import com.vaadin.flow.server.StreamResource;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.models.PlanAnual;
import mx.gob.jumapacelaya.services.DatabaseService;
import mx.gob.jumapacelaya.services.ReportService;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.vaadin.lineawesome.LineAwesomeIcon;
import java.io.*;
import java.lang.reflect.Array;
import java.sql.Date;
import java.time.LocalDate;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;
@PermitAll
@PageTitle("Plan Anual de Mantenimiento")
@Route(value = "/", layout = MainLayout.class)
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class PlanAnualView extends VerticalLayout {
private final Environment env;
private final ReportService reportService;
H4 titulo = new H4();
H5 titulo1 = new H5();
Button btnInsertar;
private byte[] fileContent;
VerticalLayout gridLayout = new VerticalLayout();
HorizontalLayout uploadLayout = new HorizontalLayout();
HorizontalLayout filtrosLayout = new HorizontalLayout();
private final DatabaseService databaseService;
Grid<PlanAnual> planAnualGrid;
Button btnColumns;
Button btnImprimirRpt;
Button btnAddEquipo;
HorizontalLayout btnImprimirLayout;
private Popover reportePopover;
public PlanAnualView(DatabaseService databaseService, Environment env, ReportService reportService) {
this.databaseService = databaseService;
this.env = env;
this.reportService = reportService;
setupHeader();
Grid<PlanAnual> planAnualGrid = setupGrid();
// Notificación de conexión activa
String perfil = String.join(",", env.getActiveProfiles());
String url = env.getProperty("db.url");
Notification.show("Conectado a: " + perfil + "\nURL DB: " + url, 5000, Notification.Position.BOTTOM_START);
// Obtenemos la lista de items y establecemos un GridListDataView para gestionar
// los datos
List<PlanAnual> planAnualItems = databaseService.getPlanAnual();
GridListDataView<PlanAnual> dataView = planAnualGrid.setItems(planAnualItems);
// Se crea el filtro para el grid.
PlanAnualFilter planAnualFilter = new PlanAnualFilter(dataView);
planAnualFilter.setExcludeRealizado(true);
HeaderRow headerRow = planAnualGrid.appendHeaderRow();
/*headerRow.getCell(planAnualGrid.getColumnByKey("smtColumnKey"))
.setComponent(createFilterHeader("S.M.T", planAnualFilter::setSmt));*/
headerRow.getCell(planAnualGrid.getColumnByKey("equipo"))
.setComponent(createFilterHeader("Equipo", planAnualFilter::setEquipo));
headerRow.getCell(planAnualGrid.getColumnByKey("departamento"))
.setComponent(createFilterHeader("Departamento", planAnualFilter::setDepartamento));
headerRow.getCell(planAnualGrid.getColumnByKey("mesplaneado"))
.setComponent(createFilterHeader("Mes Planeado", planAnualFilter::setMesPlaneado));
// MENU CONTEXTUAL DEL GRID
PersonContextMenu contextMenu = new PersonContextMenu(planAnualGrid);
// Componente UPLOAD para subir archivos
MemoryBuffer buffer = new MemoryBuffer();
Upload upload = new Upload();
upload.setAcceptedFileTypes(".xls", ".xlsx");
upload.setMaxFiles(1);
upload.setDropLabel(new com.vaadin.flow.component.html.Span("Arrastra un archivo Excel aquí o selecciona uno"));
upload.addSucceededListener(event -> {
try {
// Almacena el contenido del archivo en un arreglo de bytes
try (InputStream inputStream = buffer.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
inputStream.transferTo(byteArrayOutputStream);
fileContent = byteArrayOutputStream.toByteArray();
}
// Validación del archivo cargado
List<String> errores = validarExcel(new ByteArrayInputStream(fileContent));
if (!errores.isEmpty()) {
// Crear notificación con mensaje de error y sin duración
final Notification ntfError = new Notification();
ntfError.setText("Errores en el archivo: " + String.join(", ", errores));
ntfError.setDuration(0); // La notificación no se cerrará automáticamente
ntfError.setPosition(Notification.Position.MIDDLE);
ntfError.addThemeVariants(NotificationVariant.LUMO_ERROR);
// Texto del mensaje de error
Span errorMessage = new Span("Errores en el archivo: " + String.join(", ", errores));
errorMessage.getStyle().set("margin-right", "10px");
// Crear botón de cierre
final Button closeButton = new Button(new Icon(VaadinIcon.CLOSE));
closeButton.addClickListener(e -> ntfError.close());
// Agregar el mensaje y el botón de cierre a la notificación
HorizontalLayout notificationLayout = new HorizontalLayout(errorMessage, closeButton);
ntfError.add(notificationLayout);
ntfError.open(); // Abrir la notificación en pantalla
// Ocultar el botón de insertar si hay errores
btnInsertar.setVisible(false);
} else {
btnInsertar.setVisible(true);
}
} catch (IOException e) {
Notification.show("Error al leer el archivo: " + e.getMessage())
.addThemeVariants(NotificationVariant.LUMO_ERROR);
}
});
btnInsertar = new Button("Insertar archivo", event -> insertarDatos());
btnInsertar.setVisible(false);
gridLayout.add(btnImprimirLayout,planAnualGrid);
gridLayout.setSizeFull();
uploadLayout.add(upload, btnInsertar);
toggleLayouts(dataView);
filtrosLayout.addClassNames("lumo-justify-content-center", "lumo-gap-m", "lumo-padding-s");
filtrosLayout.setWidthFull();
filtrosLayout.setJustifyContentMode(JustifyContentMode.CENTER);
Button btnPendientes = new Button("Pendientes", VaadinIcon.CLOCK.create());
Button btnRealizados = new Button("Realizados", VaadinIcon.CHECK_CIRCLE.create());
btnPendientes.addClassName("selected-tab");
btnPendientes.addClickListener(e -> {
planAnualFilter.setExcludeRealizado(true);
btnPendientes.addClassName("selected-tab");
btnRealizados.removeClassName("selected-tab");
});
btnRealizados.addClickListener(e -> {
planAnualFilter.setExcludeRealizado(false);
btnRealizados.addClassName("selected-tab");
btnPendientes.removeClassName("selected-tab");
});
filtrosLayout.add(btnPendientes, btnRealizados);
mostrarPopoverReportes();
this.setPadding(false);
this.setMargin(false);
this.setSpacing(false);
this.setSizeFull();
add(filtrosLayout, gridLayout, uploadLayout);
}
private void setupHeader() {
VerticalLayout headerLayout = new VerticalLayout();
headerLayout.addClassName("plan-anual-header");
titulo.addClassName("plan-anual-titulo");
titulo1.addClassName("plan-anual-titulo1");
titulo.setText("Plan Anual de Mantenimiento Preventivo de Equipo de Computo");
titulo1.setText(Year.now().toString());
TextField nomenclaturaTxt = new TextField();
nomenclaturaTxt.setValue("FR01-PA-7.1.3-02");
nomenclaturaTxt.setReadOnly(true);
nomenclaturaTxt.addClassName("nomenclatura-txt");
headerLayout.add(titulo, titulo1);
headerLayout.setAlignItems(Alignment.CENTER);
add(headerLayout);
}
private Grid<PlanAnual> setupGrid() {
planAnualGrid = new Grid<>(PlanAnual.class, false);
planAnualGrid.addColumn((ValueProvider<PlanAnual, Integer>) PlanAnual::getNumero)
.setHeader("No.").setSortable(true).setAutoWidth(true).setFrozen(true);
// Botón condicional
planAnualGrid.addComponentColumn(planAnual -> {
String estado = planAnual.getEstado();
Button btn;
if ("PENDIENTE".equalsIgnoreCase(estado)) {
btn = new Button(new Icon(VaadinIcon.EDIT));
btn.setTooltipText("Realizar mantenimiento");
btn.getStyle().set("color", "#A02142");
btn.addClickListener(event -> {
int idPlananual = planAnual.getNumero();
LocalDate fechaSistema = LocalDate.now();
String nomEquipo = planAnual.getNomEquipo();
String departamento = planAnual.getDepartamento();
btn.getUI().ifPresent(ui -> ui.navigate(
"mantenimiento?id=" + idPlananual +
"&fecha=" + fechaSistema +
"&tipo=1" +
"&nomEquipo=" + nomEquipo +
"&departamento=" + departamento));
});
} else if ("REALIZADO".equalsIgnoreCase(estado)) {
btn = new Button(new Icon(VaadinIcon.EYE));
btn.setTooltipText("Ver detalles");
btn.getStyle().set("color", "#A02142");
btn.addClickListener(event -> {
int idPlananual = planAnual.getNumero();
btn.getUI().ifPresent(ui -> ui.navigate(
"detalles?id=" + idPlananual));
});
} else {
btn = new Button("N/A");
btn.setEnabled(false);
}
return btn;
}).setAutoWidth(true).setFrozen(true);
planAnualGrid.addColumn((ValueProvider<PlanAnual, String>) PlanAnual::getNomEquipo)
.setHeader("Equipo").setAutoWidth(true).setKey("equipo");
planAnualGrid.addColumn((ValueProvider<PlanAnual, String>) PlanAnual::getDepartamento)
.setHeader("Departamento").setAutoWidth(true).setKey("departamento");
planAnualGrid.addColumn(planAnual -> {
String mesPlaneado = planAnual.getMesplaneado();
return mesPlaneado != null ? mesPlaneado.toUpperCase() : "N/A";
}).setHeader("Mes Planeado").setAutoWidth(true).setKey("mesplaneado");
// Fechas formateadas
planAnualGrid.addColumn(planAnual -> {
LocalDate fecha = planAnual.getFechaProgramada();
return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) : "No programada";
}).setHeader("Fecha Programada").setAutoWidth(true).setSortable(true).setKey("fechaProgramada");
planAnualGrid.addColumn(planAnual -> {
LocalDate fecha = planAnual.getFechaMantenimiento();
return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) : "";
}).setHeader("Fecha Realización").setAutoWidth(true).setSortable(true).setKey("fechaMantenimiento");
planAnualGrid.addColumn((ValueProvider<PlanAnual, String>) PlanAnual::getEstado)
.setHeader("Estado").setAutoWidth(true).setKey("estado");
planAnualGrid.addColumn((ValueProvider<PlanAnual, String>) PlanAnual::getSituacion)
.setHeader("Situación").setAutoWidth(true).setKey("situacion");
/*planAnualGrid.addColumn((ValueProvider<PlanAnual, String>) PlanAnual::getSmt)
.setHeader("S.M.T").setKey("smtColumnKey");*/
// Iconos en columnas booleanas
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isMonitor())).setHeader("Monitor").setKey("monitor");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isTeclado())).setHeader("Teclado").setKey("teclado");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isMouse())).setHeader("Mouse").setKey("mouse");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isRegulador())).setHeader("Regulador").setKey("regulador");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isCpu())).setHeader("CPU").setKey("cpu");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isImpresora())).setHeader("Impresora").setKey("impresora");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isMiniPrint())).setHeader("MiniPrint").setKey("miniprint");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isLaptop())).setHeader("Laptop").setKey("laptop");
planAnualGrid.addComponentColumn(planAnual -> getIcon(planAnual.isEscaner())).setHeader("Escáner").setKey("escaner");
planAnualGrid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT);
planAnualGrid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);
btnColumns = new Button(VaadinIcon.GRID_H.create());
btnColumns.addThemeVariants(ButtonVariant.LUMO_ICON);
btnColumns.setAriaLabel("Show/Hide Columns");
btnColumns.setTooltipText("Show/Hide Columns");
btnImprimirRpt = new Button(VaadinIcon.PRINT.create());
btnImprimirRpt.addClickListener(event -> reportePopover.open());
btnImprimirRpt.setTooltipText("Imprimir reporte");
btnAddEquipo = new Button(VaadinIcon.PLUS.create());
btnAddEquipo.addClickListener(event -> addNuevoEquipo());
btnAddEquipo.setTooltipText("Agregar nuevo equipo");
btnImprimirLayout = new HorizontalLayout(btnColumns, btnImprimirRpt, btnAddEquipo);
HorizontalLayout columnSelectorLayout = new HorizontalLayout();
columnSelectorLayout.setAlignItems(Alignment.END);
Popover popover = new Popover();
popover.setModal(true);
popover.setBackdropVisible(true);
popover.setPosition(PopoverPosition.BOTTOM_END);
popover.setTarget(btnColumns);
Div heading = new Div("Ver/Ocultar columnas");
heading.getStyle().set("font-weight", "600");
heading.getStyle().set("padding", "var(--lumo-space-xs)");
List<String> columns = List.of("equipo", "departamento", "mesplaneado", "fechaProgramada",
"fechaMantenimiento", "estado", "situacion", "monitor", "teclado", "mouse", "regulador",
"cpu", "impresora", "miniprint", "laptop", "escaner");
CheckboxGroup<String> chkColumns = new CheckboxGroup<>();
chkColumns.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
chkColumns.setItems(columns);
chkColumns.setItemLabelGenerator((item) -> {
String label = StringUtils
.join(StringUtils.splitByCharacterTypeCamelCase(item), " ");
return StringUtils.capitalize(label.toLowerCase());
});
chkColumns.addValueChangeListener((e) -> {
columns.forEach((key) -> {
Grid.Column<?> col = planAnualGrid.getColumnByKey(key);
if (col != null) {
col.setVisible(e.getValue().contains(key));
} else {
System.out.println("Columna no encontrada para key: " + key);
}
});
});
Set<String> defaultColumns = Set.of("equipo", "departamento", "mesplaneado",
"fechaProgramada", "fechaMantenimiento", "estado", "situacion");
chkColumns.setValue(defaultColumns);
popover.add(heading, chkColumns);
// Cargar datos
planAnualGrid.setItems(databaseService.getPlanAnual());
return planAnualGrid;
}
/*
* ( ͡° ͜ʖ ͡°). * SUSTITUIR VALORES BOOLEANOS POR UN ICONO ( ͡° ͜ʖ
* ͡°). *
*/
private Icon getIcon(boolean value) {
if (value) {
return new Icon(VaadinIcon.CHECK_CIRCLE);
} else {
return new Icon();
}
}
/*
* ( ͡° ͜ʖ ͡°). * METODO PARA VALIDAR QUE EL ARCHIOVO TENGA LA ESTRUCTURA
* CORRECTA ( ͡° ͜ʖ ͡°). *
*/
private List<String> validarExcel(InputStream inputStream) throws IOException {
List<String> errores = new ArrayList<>();
Workbook workbook = WorkbookFactory.create(inputStream);
Sheet sheet = workbook.getSheetAt(0);
// Lista de nombres de columnas esperados en el encabezado
List<String> columnas = Arrays.asList("NOMEQUIPO", "DEPARTAMENTO", "MONITOR", "TECLADO", "MOUSE", "REGULADOR",
"CPU", "IMPRESORA", "MINIPRINT", "LAPTOP", "ESCANER", "FECHAPROG", "TECNICO", "ESTADO");
// Obtener la primera fila como encabezado
Row headerRow = sheet.getRow(0);
if (headerRow != null) {
// Validar que cada celda en el encabezado tiene el nombre correcto
for (int i = 0; i < headerRow.getPhysicalNumberOfCells(); i++) {
Cell cell = headerRow.getCell(i);
if (cell != null) { // Verificar si la celda no es null antes de acceder a su valor
String columnName = cell.getStringCellValue();
if (!columnas.contains(columnName)) {
errores.add("Columna inesperada: " + columnName);
}
} else {
errores.add("Celda vacía en la columna de índice " + i);
}
}
} else {
errores.add("La hoja no contiene un encabezado en la primera fila.");
}
// Verificar si faltan columnas esperadas en el encabezado
for (String columnName : columnas) {
boolean found = false;
if (headerRow != null) {
for (int i = 0; i < headerRow.getPhysicalNumberOfCells(); i++) {
Cell cell = headerRow.getCell(i);
if (cell != null && cell.getStringCellValue().equals(columnName)) {
found = true;
break;
}
}
}
if (!found) {
errores.add("Falta la columna: " + columnName);
}
}
workbook.close();
return errores;
}
// Valida que haya un archivo cargado en el UPLOAD y si si, llama al metodo para
// insertar el archivo en la base de datos
private void insertarDatos() {
if (fileContent == null) {
Notification.show("Error: No hay archivo cargado.").addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
try (InputStream inputStream = new ByteArrayInputStream(fileContent)) {
databaseService.insertarDesdeExcel(inputStream);
Notification.show("Archivo insertado correctamente").addThemeVariants(NotificationVariant.LUMO_SUCCESS);
btnInsertar.setVisible(false); // Ocultar el botón después de la inserción
} catch (Exception e) {
Notification.show("Error al insertar el archivo: " + e.getMessage())
.addThemeVariants(NotificationVariant.LUMO_ERROR);
}
}
private static Component createFilterHeader(String labelText, Consumer<String> filterChangeConsumer) {
TextField textField = new TextField();
textField.setPlaceholder("Buscar...");
textField.setValueChangeMode(ValueChangeMode.EAGER);
textField.setClearButtonVisible(true);
textField.setWidthFull();
textField.addValueChangeListener(event -> filterChangeConsumer.accept(event.getValue()));
VerticalLayout layout = new VerticalLayout(textField);
layout.setSpacing(false);
layout.setPadding(false);
return layout;
}
private static class PlanAnualFilter {
private final GridListDataView<PlanAnual> dataView;
private String smt;
private String equipo;
private String departamento;
private String mesPlaneado;
private boolean excludeRealizado = true;
public PlanAnualFilter(GridListDataView<PlanAnual> dataView) {
this.dataView = dataView;
this.dataView.addFilter(this::test);
}
public void setSmt(String smt) {
this.smt = smt;
this.dataView.refreshAll();
}
public void setEquipo(String equipo) {
this.equipo = equipo;
this.dataView.refreshAll();
}
public void setDepartamento(String departamento) {
this.departamento = departamento;
this.dataView.refreshAll();
}
public void setMesPlaneado(String mesPlaneado) {
this.mesPlaneado = mesPlaneado;
this.dataView.refreshAll();
}
public void setExcludeRealizado(boolean excludeRealizado) {
this.excludeRealizado = excludeRealizado;
this.dataView.refreshAll();
}
public boolean test(PlanAnual planAnual) {
if (planAnual == null) {
return false; // Avoid NullPointerException
}
boolean matchesSmt = matches(planAnual.getSmt(), smt);
boolean matchesEquipo = matches(planAnual.getNomEquipo(), equipo);
boolean matchesDepartamento = matches(planAnual.getDepartamento(), departamento);
boolean matchesMesPlaneado = matches(planAnual.getMesplaneado(), mesPlaneado);
if (excludeRealizado) {
// Mostrar solo los pendientes
return matchesSmt && matchesEquipo && matchesDepartamento && matchesMesPlaneado
&& (planAnual.getEstado() == null || !"REALIZADO".equalsIgnoreCase(planAnual.getEstado()));
} else {
// Mostrar solo realizados
return matchesSmt && matchesEquipo && matchesDepartamento && matchesMesPlaneado
&& "REALIZADO".equalsIgnoreCase(planAnual.getEstado());
}
}
private boolean matches(String value, String searchTerm) {
return searchTerm == null || searchTerm.isEmpty()
|| value.toLowerCase().contains(searchTerm.toLowerCase());
}
}
// Aqui validamos que haya registros en el plan anual y si no hay muestra el
// upload para cargar un nuevo plan anual
private void toggleLayouts(GridListDataView<PlanAnual> dataView) {
boolean hasItems = dataView.getItemCount() > 0;
gridLayout.setVisible(hasItems);
uploadLayout.setVisible(!hasItems);
}
private void sacarReporte() {
Dialog dialog = new Dialog();
dialog.setHeaderTitle("Seleccione la fecha de inicio y fin");
DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n()
.setWeekdays(List.of("Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sabado"))
.setWeekdaysShort(List.of("Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"))
.setMonthNames(List.of("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"))
.setFirstDayOfWeek(1)
.setToday("Hoy")
.setCancel("Cancelar")
.setDateFormat("dd/MM/yyyy");
DatePicker fechaInicio = new DatePicker("Fecha de inicio:");
fechaInicio.setRequired(true);
fechaInicio.setI18n(i18n);
DatePicker fechaFin = new DatePicker("Fecha de fin:");
fechaFin.setRequired(true);
fechaFin.setI18n(i18n);
Button btnGenerar = new Button("Generar", VaadinIcon.PRINT.create());
btnGenerar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
btnGenerar.addClickListener(e -> {
if (fechaInicio.getValue() == null || fechaFin.getValue() == null) {
Notification.show("Por favor, seleccione ambas fechas.", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
LocalDate inicio = fechaInicio.getValue();
LocalDate fin = fechaFin.getValue();
try {
// Prepara los parámetros para el reporte
Map<String, Object> parametros = new HashMap<>();
parametros.put("FECHAINICIO", java.sql.Date.valueOf(inicio));
parametros.put("FECHAFIN", java.sql.Date.valueOf(fin));
// Genera el PDF
byte[] pdf = reportService.generarReporte("mantenimientoFechas", parametros);
// Creando el recurso de descarga
StreamResource resource = new StreamResource("reporte.pdf", () -> new ByteArrayInputStream(pdf));
/*Anchor downloadLink = new Anchor(resource, "Descargar Reporte");
downloadLink.setTarget("_blank");
downloadLink.setId("descargar-reporte-link");
add(downloadLink);
getUI().ifPresent(ui ->
ui.getPage().executeJs("document.getElementById('descargar-reporte-link').click();")
);*/
StreamRegistration registration = UI.getCurrent().getSession().getResourceRegistry().registerResource(resource);
UI.getCurrent().getPage().executeJs("window.open('" + registration.getResourceUri().toString() + "','_blank')");
} catch (Exception ex) {
Notification.show("Error al genrar el reporte: " + ex.getMessage(), 5000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
ex.printStackTrace();
}
});
Button btnCancelar = new Button("Cancelar", VaadinIcon.CLOSE_CIRCLE.create(), e -> dialog.close());
dialog.getFooter().add(btnCancelar);
dialog.getFooter().add(btnGenerar);
HorizontalLayout fechasLayout = new HorizontalLayout(fechaInicio, fechaFin);
dialog.add(fechasLayout);
dialog.open();
}
private void addNuevoEquipo() {
Dialog dialog = new Dialog();
dialog.setHeaderTitle("Agregar nuevo equipo");
TextField nombreEquipo = new TextField("Nombre equipo:");
TextField area = new TextField("Área:");
DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n()
.setWeekdays(List.of("Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sabado"))
.setWeekdaysShort(List.of("Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"))
.setMonthNames(List.of("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"))
.setFirstDayOfWeek(1)
.setToday("Hoy")
.setCancel("Cancelar")
.setDateFormat("dd/MM/yyyy");
DatePicker fechaProgramada = new DatePicker("Fecha programada:");
fechaProgramada.setI18n(i18n);
List<String> items = List.of("ENERO", "FEBRERO", "MARZO", "ABRIL", "MAYO", "JUNIO",
"JULIO", "AGOSTO", "SEPTIEMBRE", "OCTUBRE", "NOVIEMBRE", "DICIEMBRE");
ComboBox<String> cmbMes = new ComboBox<>("Mes Planeado:");
cmbMes.setItems(items);
CheckboxGroup<String> group1 = new CheckboxGroup<>();
group1.setLabel("Seleccione los componentes del equipo");
group1.setItems("MONITOR","TECLADO","MOUSE","REGULADOR");
CheckboxGroup<String> group2 = new CheckboxGroup<>();
group2.setItems("CPU","IMPRESORA","MINIPRINT","LAPTOP","ESCANER");
HorizontalLayout layout1 = new HorizontalLayout(nombreEquipo, area);
HorizontalLayout layout2 = new HorizontalLayout(fechaProgramada,cmbMes);
VerticalLayout layout3 = new VerticalLayout(group1,group2);
layout3.setSpacing(false);
Button btnGuardar = new Button("Guardar", LineAwesomeIcon.SAVE_SOLID.create());
btnGuardar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
btnGuardar.addClickListener(e -> {
if (nombreEquipo.getValue().isEmpty() || area.getValue().isEmpty() ||
fechaProgramada.getValue() == null || cmbMes.getValue() == null) {
Notification.show("Por favor, complete todos los campos.", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
final Map<String, Integer> MES_ID_MAP = new HashMap<>();
MES_ID_MAP.put("ENERO", 1);
MES_ID_MAP.put("FEBRERO", 2);
MES_ID_MAP.put("MARZO", 3);
MES_ID_MAP.put("ABRIL", 4);
MES_ID_MAP.put("MAYO", 5);
MES_ID_MAP.put("JUNIO", 6);
MES_ID_MAP.put("JULIO", 7);
MES_ID_MAP.put("AGOSTO", 8);
MES_ID_MAP.put("SEPTIEMBRE", 9);
MES_ID_MAP.put("OCTUBRE", 10);
MES_ID_MAP.put("NOVIEMBRE", 11);
MES_ID_MAP.put("DICIEMBRE", 12);
String mesSeleccionado = cmbMes.getValue();
Integer mesId = MES_ID_MAP.get(mesSeleccionado);
if (group1.getValue().isEmpty() && group2.getValue().isEmpty()) {
Notification.show("Debe seleccionar al menos un componente del equipo.", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
Set<String> seleccionados = new HashSet<>();
seleccionados.addAll(group1.getValue());
seleccionados.addAll(group2.getValue());
boolean monitor = seleccionados.contains("MONITOR");
boolean teclado = seleccionados.contains("TECLADO");
boolean mouse = seleccionados.contains("MOUSE");
boolean regulador = seleccionados.contains("REGULADOR");
boolean cpu = seleccionados.contains("CPU");
boolean impresora = seleccionados.contains("IMPRESORA");
boolean miniprint = seleccionados.contains("MINIPRINT");
boolean laptop = seleccionados.contains("LAPTOP");
boolean escaner = seleccionados.contains("ESCANER");
databaseService.insertarNuevoEquipo(
nombreEquipo.getValue().toUpperCase(),
area.getValue().toUpperCase(),
monitor,
teclado,
mouse,
regulador,
cpu,
impresora,
miniprint,
laptop,
escaner,
java.sql.Date.valueOf(fechaProgramada.getValue()),
"",
"PENDIENTE",
mesId
);
Notification.show("Equipo agregado correctamente", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
dialog.close();
// Recargar el grid para mostrar el nuevo equipo
planAnualGrid.setItems(databaseService.getPlanAnual());
});
Button btnCancelar = new Button("Cancelar", VaadinIcon.CLOSE_CIRCLE.create(), e -> dialog.close());
dialog.getFooter().add(btnGuardar);
dialog.getFooter().add(btnCancelar);
dialog.add(layout1,layout2,layout3);
dialog.open();
}
private void mostrarPopoverReportes() {
reportePopover = new Popover();
reportePopover.setModal(true);
reportePopover.setBackdropVisible(true);
reportePopover.setPosition(PopoverPosition.BOTTOM_END);
reportePopover.setTarget(btnImprimirRpt);
Div headding = new Div("Reportes disponibles");
headding.getStyle().set("font-weight", "600");
headding.getStyle().set("padding", "var(--lumo-space-xs)");
VerticalLayout listaRrportes = new VerticalLayout();
//listaRrportes.setSpacing(false);
listaRrportes.setPadding(false);
Button btnReporteFechas = new Button("Mantenimiento por fechas", VaadinIcon.STAR.create(), e -> {
reportePopover.close();
sacarReporte();
});
btnReporteFechas.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
Button btnListadoMant = new Button("Listado de mantenimientos", VaadinIcon.STAR.create(), e -> {
reportePopover.close();
obtenerListadoRpt();
});
btnListadoMant.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
listaRrportes.add(btnReporteFechas, btnListadoMant);
reportePopover.add(headding, listaRrportes);
}
private void obtenerListadoRpt() {
Dialog dialog = new Dialog();
dialog.setHeaderTitle("Ingresa el peridodo a consultar");
TextField txtMes = new TextField("Mes:");
txtMes.setRequired(true);
NumberField txtAnio = new NumberField("Año:");
txtAnio.setRequired(true);
HorizontalLayout layout = new HorizontalLayout(txtMes, txtAnio);
Button btnGenerar = new Button("Generar", VaadinIcon.PRINT.create());
btnGenerar.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
btnGenerar.addClickListener(e -> {
String mes = txtMes.getValue().toUpperCase();
Integer anio = txtAnio.getValue() != null ? txtAnio.getValue().intValue() : null;
if (mes.isEmpty() || anio == null) {
Notification.show("Por favor, completa todos los campos.", 2000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
return;
}
try {
// Preparando los parámetros para el reporte
Map<String, Object> parametros = new HashMap<>();
parametros.put("pMES", mes);
parametros.put("pANIO", anio);
// Generando el PDF
byte[] pdf = reportService.generarReporte("listadoMantenimientos", parametros);
// Creando el recurso de descarga
StreamResource resource = new StreamResource("listado_mantenimientos.pdf", () -> new ByteArrayInputStream(pdf));
/*Anchor downloadLink = new Anchor(resource, "Descargar Reporte");
downloadLink.setTarget("_blank");
downloadLink.setId("descargar-listado-link");
add(downloadLink);
getUI().ifPresent(ui ->
ui.getPage().executeJs("document.getElementById('descargar-listado-link').click();")
);*/
StreamRegistration registration = UI.getCurrent().getSession().getResourceRegistry().registerResource(resource);
UI.getCurrent().getPage().executeJs("window.open('" + registration.getResourceUri().toString() + "','_blank')");
} catch (Exception ex) {
Notification.show("Error al generar el reporte: " + ex.getMessage(), 5000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_ERROR);
ex.printStackTrace();
}
});
Button btnCancelar = new Button("Cancelar", VaadinIcon.CLOSE_CIRCLE.create(), e -> dialog.close());
dialog.getFooter().add(btnCancelar, btnGenerar);
dialog.add(layout);
dialog.open();
}
private class PersonContextMenu extends GridContextMenu<PlanAnual> {
public PersonContextMenu(Grid<PlanAnual> target) {
super(target);
addItem("Realizar", e -> e.getItem().ifPresent(planAnual -> {
int idPlananual = planAnual.getNumero();
LocalDate fechaSistema = LocalDate.now();
String nomEquipo = planAnual.getNomEquipo();
String departamento = planAnual.getDepartamento();
getUI().ifPresent(ui -> ui.navigate(
"mantenimiento?id=" + idPlananual +
"&fecha=" + fechaSistema +
"&tipo=1" +
"&nomEquipo=" + nomEquipo +
"&departamento=" + departamento));
}));
addItem("Borrar", e -> e.getItem().ifPresent(planAnual -> {
eliminarPlanAnual(planAnual);
}));
add(new Hr());
GridMenuItem<PlanAnual> nomEquipo = addItem("Equipo",
e -> e.getItem().ifPresent(planAnual -> {
planAnual.getNomEquipo();
}));
GridMenuItem<PlanAnual> depto = addItem("Departamento",
e -> e.getItem().ifPresent(planAnual -> {
planAnual.getDepartamento();
}));
setDynamicContentHandler(planAnual -> {
if (planAnual == null)
return false;
nomEquipo.setText(String.format("Equipo: %s", planAnual.getNomEquipo()));
depto.setText(String.format("Area: %s", planAnual.getDepartamento()));
return true;
});
}
}
private void eliminarPlanAnual(PlanAnual planAnual) {
Dialog dialog = new Dialog();
dialog.setHeaderTitle("Eliminar Mantenimiento");
TextField txtMotivo = new TextField("Justifica el motivo de la eliminación");
txtMotivo.setWidthFull();
txtMotivo.setRequired(true);
dialog.add(
new VerticalLayout(
new Span("¿Estás seguro de que deseas eliminar el mantenimiento del equipo: " + planAnual.getNomEquipo()),
txtMotivo
)
);
Button btnEliminar = new Button("Eliminar", VaadinIcon.TRASH.create(), event -> {
String motivo = txtMotivo.getValue();
if (motivo.isEmpty()) {
txtMotivo.setErrorMessage("El motivo es requerido.");
txtMotivo.setInvalid(true);
return;
}
txtMotivo.setInvalid(false);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String usuarioId = authentication != null ? authentication.getName().toUpperCase() : "DESCONOCIDO";
LocalDate fecha = LocalDate.now();
// Llamar al servicio para insertar la bitácora de eliminación
databaseService.insertarBitacoraEliminacion(planAnual.getNumero(), usuarioId, fecha, motivo);
// Llamar al servicio para eliminar el plan anual
databaseService.eliminarEquipoPlanAnual(planAnual.getNumero());
Notification.show("Equipo eliminado correctamente", 3000, Notification.Position.MIDDLE)
.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
dialog.close();
UI.getCurrent().getPage().executeJs("setTimeout(() => { location.reload(); }, 2000);");
});
Button btnCancelar = new Button("Cancelar", VaadinIcon.CLOSE_CIRCLE.create(), e -> dialog.close());
HorizontalLayout dialogFooter = new HorizontalLayout(btnEliminar, btnCancelar);
dialog.getFooter().add(dialogFooter);
dialog.open();
}
}

+ 106
- 0
src/main/java/mx/gob/jumapacelaya/ui/login/LoginView.java View File

@ -0,0 +1,106 @@
package mx.gob.jumapacelaya.ui.login;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.component.login.LoginI18n;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Route("login")
@PageTitle("Login")
@AnonymousAllowed
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
private static final Logger log = LoggerFactory.getLogger(LoginView.class);
private final LoginForm login = new LoginForm();
// Usuario local para demostracion
private final String localUser = "admin";
private final String localPassword = "admin";
public LoginView(){
//Configuracion de la vista
addClassName("login");
setSizeFull();
setPadding(false);
setMargin(false);
// Crear el layout horizontal
HorizontalLayout mainLayout = new HorizontalLayout();
mainLayout.setSizeFull();
mainLayout.setPadding(false);
mainLayout.setMargin(false);
// Configuración de i18n para el formulario de login
LoginI18n i18n = LoginI18n.createDefault();
LoginI18n.Form i18nFormulario = i18n.getForm();
i18nFormulario.setTitle("Mantenimiento Preventivo y Correctivo");
i18nFormulario.setUsername("Usuario");
i18nFormulario.setPassword("Contraseña");
i18nFormulario.setSubmit("Iniciar sesión");
i18n.setForm(i18nFormulario);
// Configuración de los mensajes de error
LoginI18n.ErrorMessage i18nError = i18n.getErrorMessage();
i18nError.setTitle("Credenciales incorrectas");
i18nError.setMessage("Usuario o contraseña incorrectos, verifica tus credenciales");
i18n.setErrorMessage(i18nError);
i18n.setAdditionalInformation("Versión 2.0.0 - © 2024 JUMAPACelaya");
// Configuración del formulario de login
login.setAction("login");
login.setForgotPasswordButtonVisible(false);
login.setI18n(i18n);
// Crear un contenedor para el formulario
VerticalLayout loginFormContainer = new VerticalLayout();
Image imageLogin = new Image("images/LOGO_24'27.png", "Login");
imageLogin.setWidth("300px");
loginFormContainer.add(imageLogin);
loginFormContainer.add(login);
loginFormContainer.setSizeUndefined();
loginFormContainer.setPadding(false);
loginFormContainer.setMargin(false);
loginFormContainer.setAlignItems(Alignment.CENTER);
loginFormContainer.setJustifyContentMode(JustifyContentMode.CENTER);
loginFormContainer.getElement().getThemeList().add("dark");
// Añadir la imagen y el contenedor del formulario al layout principal
mainLayout.add(loginFormContainer);
mainLayout.setFlexGrow(1, loginFormContainer);
mainLayout.setFlexGrow(2);
// Añadir el layout principal a la vista
add(mainLayout);
}
@Override
public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
if(beforeEnterEvent.getLocation()
.getQueryParameters()
.getParameters()
.containsKey("error")){
login.setError(true);
}
}
}

BIN
src/main/resources/META-INF/resources/icons/icon.png View File

Before After
Width: 512  |  Height: 512  |  Size: 37 KiB

BIN
src/main/resources/META-INF/resources/images/1024x768.png View File

Before After
Width: 1026  |  Height: 770  |  Size: 807 KiB

BIN
src/main/resources/META-INF/resources/images/900x160.png View File

Before After
Width: 901  |  Height: 161  |  Size: 22 KiB

BIN
src/main/resources/META-INF/resources/images/960X960_Nvo.png View File

Before After
Width: 961  |  Height: 961  |  Size: 50 KiB

BIN
src/main/resources/META-INF/resources/images/FirmaGerenteTI.png View File

Before After
Width: 400  |  Height: 200  |  Size: 14 KiB

BIN
src/main/resources/META-INF/resources/images/LOGO_1080X1024.png View File

Before After
Width: 1081  |  Height: 1025  |  Size: 110 KiB

BIN
src/main/resources/META-INF/resources/images/LOGO_24'27.png View File

Before After
Width: 861  |  Height: 424  |  Size: 60 KiB

BIN
src/main/resources/META-INF/resources/images/LOGO_900X160.png View File

Before After
Width: 901  |  Height: 161  |  Size: 22 KiB

BIN
src/main/resources/META-INF/resources/images/NVO_JUMAPA.png View File

Before After
Width: 1269  |  Height: 625  |  Size: 88 KiB

BIN
src/main/resources/META-INF/resources/images/bckgndNvo.png View File

Before After
Width: 1025  |  Height: 769  |  Size: 97 KiB

BIN
src/main/resources/META-INF/resources/images/empty-plant.png View File

Before After
Width: 336  |  Height: 335  |  Size: 69 KiB

BIN
src/main/resources/META-INF/resources/images/imgCorreo/correoMantt.png View File

Before After
Width: 1920  |  Height: 1080  |  Size: 1.8 MiB

BIN
src/main/resources/META-INF/resources/reportes/listadoMantenimientos.jasper View File


BIN
src/main/resources/META-INF/resources/reportes/mantenimientoFechas.jasper View File


BIN
src/main/resources/META-INF/resources/reportes/mantenimientoReport.jasper View File


+ 4
- 0
src/main/resources/application-dev.properties View File

@ -0,0 +1,4 @@
#Configuracion de la base de datos
db.url=jdbc:mysql://localhost:3307/mantenimientosdb
db.user=mantenimientos
db.pass=mantenimientos

+ 5
- 0
src/main/resources/application-prod.properties View File

@ -0,0 +1,5 @@
#Configuracion de la base de datos
db.url=jdbc:mysql://db:3306/mantenimientosdb
#db.url=jdbc:oracle:thin:@//SVRAPPS:1521/XEPDB1
db.user=mantenimientos
db.pass=mantenimientos

+ 34
- 0
src/main/resources/application.properties View File

@ -0,0 +1,34 @@
server.port=${PORT:8080}
logging.level.org.atmosphere = warn
spring.profiles.active=dev
# Launch the default browser when starting the application in development mode
vaadin.launch-browser=true
# To improve the performance during development.
# For more information https://vaadin.com/docs/latest/integrations/spring/configuration#special-configuration-parameters
vaadin.allowed-packages = com.vaadin,org.vaadin,mx.gob.jumapacelaya, de.f0rce.signaturepad
spring.jpa.defer-datasource-initialization = true
#Configuracion LDAP
spring.ldap.urls=ldap://172.1.0.1:389
spring.ldap.base=DC=JUMAPACELAYA,DC=GOB,DC=MX
spring.ldap.username=administrator
spring.ldap.password=Dr3na$134%4guA
###################PRODUCTIVO####################
redmine.url=https://proyman.jumapacelaya.gob.mx/
redmine.api_key=69be2a5df9bacce02722f566fdf0731d728a1b86
#Conexion al servidor de correo electronico
spring.mail.host=correo.jumapacelaya.gob.mx
spring.mail.port=587
spring.mail.username=noreply@jumapacelaya.gob.mx
spring.mail.password=Div#13AJum$17
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=false
spring.mail.properties.mail.smtp.ssl.trust=correo.jumapacelaya.gob.mx

+ 6
- 0
src/main/resources/banner.txt View File

@ -0,0 +1,6 @@
____ _ _ _ __ __ _ _ _ _
/ ___|(_)___| |_ ___ _ __ ___ __ _ __| | ___ | \/ | __ _ _ __ | |_ ___ _ __ (_)_ __ ___ (_) ___ _ __ | |_ ___
\___ \| / __| __/ _ \ '_ ` _ \ / _` | / _` |/ _ \ | |\/| |/ _` | '_ \| __/ _ \ '_ \| | '_ ` _ \| |/ _ \ '_ \| __/ _ \
___) | \__ \ || __/ | | | | | (_| | | (_| | __/ | | | | (_| | | | | || __/ | | | | | | | | | | __/ | | | || (_) |
|____/|_|___/\__\___|_| |_| |_|\__,_| \__,_|\___| |_| |_|\__,_|_| |_|\__\___|_| |_|_|_| |_| |_|_|\___|_| |_|\__\___/

+ 39
- 0
tsconfig.json View File

@ -0,0 +1,39 @@
// This TypeScript configuration file is generated by vaadin-maven-plugin.
// This is needed for TypeScript compiler to compile your TypeScript code in the project.
// It is recommended to commit this file to the VCS.
// You might want to change the configurations to fit your preferences
// For more information about the configurations, please refer to http://www.typescriptlang.org/docs/handbook/tsconfig-json.html
{
"_version": "9.1",
"compilerOptions": {
"sourceMap": true,
"jsx": "react-jsx",
"inlineSources": true,
"module": "esNext",
"target": "es2020",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"experimentalDecorators": true,
"useDefineForClassFields": false,
"baseUrl": "src/main/frontend",
"paths": {
"@vaadin/flow-frontend": ["generated/jar-resources"],
"@vaadin/flow-frontend/*": ["generated/jar-resources/*"],
"Frontend/*": ["*"]
}
},
"include": [
"src/main/frontend/**/*",
"types.d.ts"
],
"exclude": [
"src/main/frontend/generated/jar-resources/**"
]
}

+ 17
- 0
types.d.ts View File

@ -0,0 +1,17 @@
// This TypeScript modules definition file is generated by vaadin-maven-plugin.
// You can not directly import your different static files into TypeScript,
// This is needed for TypeScript compiler to declare and export as a TypeScript module.
// It is recommended to commit this file to the VCS.
// You might want to change the configurations to fit your preferences
declare module '*.css?inline' {
import type { CSSResultGroup } from 'lit';
const content: CSSResultGroup;
export default content;
}
// Allow any CSS Custom Properties
declare module 'csstype' {
interface Properties {
[index: `--${string}`]: any;
}
}

+ 9
- 0
vite.config.ts View File

@ -0,0 +1,9 @@
import { UserConfigFn } from 'vite';
import { overrideVaadinConfig } from './vite.generated';
const customConfig: UserConfigFn = (env) => ({
// Here you can add custom Vite parameters
// https://vitejs.dev/config/
});
export default overrideVaadinConfig(customConfig);

Loading…
Cancel
Save