first commit
This commit is contained in:
commit
71c124cc68
|
|
@ -0,0 +1,51 @@
|
|||
# These are some examples of commonly ignored file patterns.
|
||||
# You should customize this list as applicable to your project.
|
||||
# Learn more about .gitignore:
|
||||
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
||||
|
||||
# Node artifact files
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
# Compiled Java class files
|
||||
*.class
|
||||
|
||||
# Compiled Python bytecode
|
||||
*.py[cod]
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Package files
|
||||
*.jar
|
||||
|
||||
# Maven
|
||||
target/
|
||||
dist/
|
||||
|
||||
# JetBrains IDE
|
||||
.idea/
|
||||
|
||||
# Unit test reports
|
||||
TEST*.xml
|
||||
|
||||
# Generated by MacOS
|
||||
.DS_Store
|
||||
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
# Applications
|
||||
*.app
|
||||
*.war
|
||||
|
||||
# Large media files
|
||||
*.mp4
|
||||
*.tiff
|
||||
*.avi
|
||||
*.flv
|
||||
*.mov
|
||||
*.wmv
|
||||
|
||||
|
||||
*desktop.ini
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# ZendionInc
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.1.3.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"ZendionInc": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/ZendionInc",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": false,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css",
|
||||
"src/styles.scss",
|
||||
"node_modules/bootstrap/dist/css/bootstrap.min.css"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/jquery/dist/jquery.js",
|
||||
"node_modules/popper.js/dist/umd/popper.js",
|
||||
"node_modules/bootstrap/dist/js/bootstrap.js",
|
||||
"node_modules/chart.js/dist/Chart.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "ZendionInc:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "ZendionInc:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "ZendionInc:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "ZendionInc:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "ZendionInc:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "ZendionInc"
|
||||
}
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
-- MySQL dump 10.13 Distrib 8.0.20, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: 18.228.31.8 Database: zendioninc
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.22-0ubuntu0.20.04.2
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `chaves`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chaves`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `chaves` (
|
||||
`idchaves` int NOT NULL AUTO_INCREMENT,
|
||||
`licenca` varchar(150) DEFAULT NULL,
|
||||
`data_criacao` datetime DEFAULT NULL,
|
||||
`data_validade` datetime DEFAULT NULL,
|
||||
`idusuarios` int DEFAULT NULL,
|
||||
`usada` tinyint DEFAULT NULL,
|
||||
`idsistemas` int DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idchaves`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `chaves`
|
||||
--
|
||||
|
||||
LOCK TABLES `chaves` WRITE;
|
||||
/*!40000 ALTER TABLE `chaves` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `chaves` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `noticias`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `noticias`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `noticias` (
|
||||
`idnoticias` int NOT NULL AUTO_INCREMENT,
|
||||
`titulo` varchar(150) DEFAULT NULL,
|
||||
`descricao` longtext,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`link` varchar(200) DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idnoticias`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `noticias`
|
||||
--
|
||||
|
||||
LOCK TABLES `noticias` WRITE;
|
||||
/*!40000 ALTER TABLE `noticias` DISABLE KEYS */;
|
||||
INSERT INTO `noticias` VALUES (1,'Teste noticia 1','Aqui entra o texto da noticia de teste 1',1,'https://www.google.com.br/','2021-03-05 23:23:01','2021-03-05 23:23:16');
|
||||
/*!40000 ALTER TABLE `noticias` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `plataformas`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `plataformas`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `plataformas` (
|
||||
`idplataformas` int NOT NULL AUTO_INCREMENT,
|
||||
`descricao` varchar(150) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idplataformas`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `plataformas`
|
||||
--
|
||||
|
||||
LOCK TABLES `plataformas` WRITE;
|
||||
/*!40000 ALTER TABLE `plataformas` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `plataformas` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `sistemas`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sistemas`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sistemas` (
|
||||
`idsistemas` int NOT NULL AUTO_INCREMENT,
|
||||
`nome` varchar(150) DEFAULT NULL,
|
||||
`descricao` varchar(150) DEFAULT NULL,
|
||||
`versaoatual` varchar(45) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`idtiposdesistema` int DEFAULT NULL,
|
||||
`idplataformas` int DEFAULT NULL,
|
||||
`nome_install` varchar(150) DEFAULT NULL,
|
||||
`notasdeatualizacao` longtext,
|
||||
`idtiposlicenca` int DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idsistemas`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sistemas`
|
||||
--
|
||||
|
||||
LOCK TABLES `sistemas` WRITE;
|
||||
/*!40000 ALTER TABLE `sistemas` DISABLE KEYS */;
|
||||
INSERT INTO `sistemas` VALUES (9,'FMovel','Sistema de gestão de concecionaria','1.0.0.1',1,1,1,'fmovel_install.exe','Primeira versão',1,'2021-02-25 23:10:06','2021-03-04 00:30:07');
|
||||
/*!40000 ALTER TABLE `sistemas` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `sistemasdetalhes`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sistemasdetalhes`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sistemasdetalhes` (
|
||||
`idsistemasdetalhes` int NOT NULL AUTO_INCREMENT,
|
||||
`idsistemas` int DEFAULT NULL,
|
||||
`descricao` varchar(250) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idsistemasdetalhes`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sistemasdetalhes`
|
||||
--
|
||||
|
||||
LOCK TABLES `sistemasdetalhes` WRITE;
|
||||
/*!40000 ALTER TABLE `sistemasdetalhes` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `sistemasdetalhes` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `sistemasusuario`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sistemasusuario`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sistemasusuario` (
|
||||
`idsistemasusuario` int NOT NULL AUTO_INCREMENT,
|
||||
`idsistemas` int DEFAULT NULL,
|
||||
`idusuarios` int DEFAULT NULL,
|
||||
`data_download` datetime DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idsistemasusuario`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `sistemasusuario`
|
||||
--
|
||||
|
||||
LOCK TABLES `sistemasusuario` WRITE;
|
||||
/*!40000 ALTER TABLE `sistemasusuario` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `sistemasusuario` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `slides`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `slides`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `slides` (
|
||||
`idslides` int NOT NULL AUTO_INCREMENT,
|
||||
`descricao` varchar(150) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`link` varchar(250) DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idslides`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `slides`
|
||||
--
|
||||
|
||||
LOCK TABLES `slides` WRITE;
|
||||
/*!40000 ALTER TABLE `slides` DISABLE KEYS */;
|
||||
INSERT INTO `slides` VALUES (1,'TI',1,'undefined','2021-03-05 23:21:52','2021-03-05 23:22:04'),(2,'Inovacao',1,'undefined','2021-03-05 23:22:25','2021-03-05 23:22:30');
|
||||
/*!40000 ALTER TABLE `slides` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `tiposdesistema`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `tiposdesistema`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `tiposdesistema` (
|
||||
`idtiposdesistema` int NOT NULL AUTO_INCREMENT,
|
||||
`descricao` varchar(150) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idtiposdesistema`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `tiposdesistema`
|
||||
--
|
||||
|
||||
LOCK TABLES `tiposdesistema` WRITE;
|
||||
/*!40000 ALTER TABLE `tiposdesistema` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `tiposdesistema` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `tiposdeusuario`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `tiposdeusuario`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `tiposdeusuario` (
|
||||
`idtiposdeusuario` int NOT NULL AUTO_INCREMENT,
|
||||
`descricao` varchar(45) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idtiposdeusuario`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `tiposdeusuario`
|
||||
--
|
||||
|
||||
LOCK TABLES `tiposdeusuario` WRITE;
|
||||
/*!40000 ALTER TABLE `tiposdeusuario` DISABLE KEYS */;
|
||||
INSERT INTO `tiposdeusuario` VALUES (1,'Administrador',1,'2021-03-05 23:20:05',NULL),(2,'Cliente',1,'2021-03-05 23:20:05',NULL);
|
||||
/*!40000 ALTER TABLE `tiposdeusuario` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `tiposlicenca`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `tiposlicenca`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `tiposlicenca` (
|
||||
`idtiposlicenca` int NOT NULL AUTO_INCREMENT,
|
||||
`descricao` varchar(150) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idtiposlicenca`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `tiposlicenca`
|
||||
--
|
||||
|
||||
LOCK TABLES `tiposlicenca` WRITE;
|
||||
/*!40000 ALTER TABLE `tiposlicenca` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `tiposlicenca` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `trocasenha`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `trocasenha`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `trocasenha` (
|
||||
`idtrocasenha` int NOT NULL AUTO_INCREMENT,
|
||||
`idusuarios` int DEFAULT NULL,
|
||||
`tag` varchar(250) DEFAULT NULL,
|
||||
`usada` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idtrocasenha`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `trocasenha`
|
||||
--
|
||||
|
||||
LOCK TABLES `trocasenha` WRITE;
|
||||
/*!40000 ALTER TABLE `trocasenha` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `trocasenha` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `usuarios`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `usuarios`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `usuarios` (
|
||||
`idusuarios` int NOT NULL AUTO_INCREMENT,
|
||||
`nome` varchar(150) DEFAULT NULL,
|
||||
`usuario` varchar(45) DEFAULT NULL,
|
||||
`senha` varchar(45) DEFAULT NULL,
|
||||
`data_cadastro` datetime DEFAULT NULL,
|
||||
`email` varchar(45) DEFAULT NULL,
|
||||
`idtiposdeusuario` int DEFAULT NULL,
|
||||
`cpf` varchar(45) DEFAULT NULL,
|
||||
`habilitado` tinyint DEFAULT NULL,
|
||||
`insert_date` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_date` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`idusuarios`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `usuarios`
|
||||
--
|
||||
|
||||
LOCK TABLES `usuarios` WRITE;
|
||||
/*!40000 ALTER TABLE `usuarios` DISABLE KEYS */;
|
||||
INSERT INTO `usuarios` VALUES (1,'Diego Freitas','ZENDION','Z210203!','2021-03-05 23:15:50','zendionmazinni@gmail.com',1,'425.855.768-41',1,'2021-03-05 23:15:50','2021-03-05 23:18:42');
|
||||
/*!40000 ALTER TABLE `usuarios` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2021-03-05 20:27:35
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('Welcome to ZendionInc!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get(browser.baseUrl) as Promise<any>;
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root h1')).getText() as Promise<string>;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/ZendionInc'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"name": "zendion-inc",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~8.1.3",
|
||||
"@angular/cdk": "~8.2.3",
|
||||
"@angular/common": "~8.1.3",
|
||||
"@angular/compiler": "~8.1.3",
|
||||
"@angular/core": "~8.1.3",
|
||||
"@angular/forms": "~8.1.3",
|
||||
"@angular/material": "^8.2.3",
|
||||
"@angular/platform-browser": "~8.1.3",
|
||||
"@angular/platform-browser-dynamic": "~8.1.3",
|
||||
"@angular/router": "~8.1.3",
|
||||
"angular2-useful-swiper": "^8.0.1-beta.1",
|
||||
"bootstrap": "^4.6.0",
|
||||
"chart.js": "^2.7.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"jquery": "^3.6.0",
|
||||
"ng5-slider": "^1.2.6",
|
||||
"popper.js": "^1.16.1",
|
||||
"primeng": "^8.1.0",
|
||||
"rxjs": "~6.4.0",
|
||||
"swiper": "^4.5.1",
|
||||
"tslib": "^1.14.1",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.801.3",
|
||||
"@angular/cli": "~8.1.3",
|
||||
"@angular/compiler-cli": "~8.1.3",
|
||||
"@angular/language-service": "~8.1.3",
|
||||
"@types/jasmine": "~3.3.8",
|
||||
"@types/jasminewd2": "^2.0.8",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/swiper": "^4.4.11",
|
||||
"codelyzer": "^5.2.2",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.1.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.5.4",
|
||||
"protractor": "^5.4.4",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.15.0",
|
||||
"typescript": "~3.4.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<h2><span style="color: rgb(68, 68, 68);">Política Privacidade</span></h2><p><span style="color: rgb(68, 68, 68);">A sua privacidade é importante para nós. É política do Zendion Inc respeitar a sua privacidade em relação a qualquer informação sua que possamos coletar no site <a href="https://zendioninc.mooo.com/">Zendion Inc</a>, e outros sites que possuímos e operamos.</span></p><p><span style="color: rgb(68, 68, 68);">Solicitamos informações pessoais apenas quando realmente precisamos delas para lhe fornecer um serviço. Fazemo-lo por meios justos e legais, com o seu conhecimento e consentimento. Também informamos por que estamos coletando e como será usado.</span></p><p><span style="color: rgb(68, 68, 68);">Apenas retemos as informações coletadas pelo tempo necessário para fornecer o serviço solicitado. Quando armazenamos dados, protegemos dentro de meios comercialmente aceitáveis para evitar perdas e roubos, bem como acesso, divulgação, cópia, uso ou modificação não autorizados.</span></p><p><span style="color: rgb(68, 68, 68);">Não compartilhamos informações de identificação pessoal publicamente ou com terceiros, exceto quando exigido por lei.</span></p><p><span style="color: rgb(68, 68, 68);">O nosso site pode ter links para sites externos que não são operados por nós. Esteja ciente de que não temos controle sobre o conteúdo e práticas desses sites e não podemos aceitar responsabilidade por suas respectivas </span><a href="https://politicaprivacidade.com/" rel="noopener noreferrer" target="_blank" style="background-color: transparent; color: rgb(68, 68, 68);">políticas de privacidade</a><span style="color: rgb(68, 68, 68);">.</span></p><p><span style="color: rgb(68, 68, 68);">Você é livre para recusar a nossa solicitação de informações pessoais, entendendo que talvez não possamos fornecer alguns dos serviços desejados.</span></p><p><span style="color: rgb(68, 68, 68);">O uso continuado de nosso site será considerado como aceitação de nossas práticas em torno de privacidade e informações pessoais. Se você tiver alguma dúvida sobre como lidamos com dados do usuário e informações pessoais, entre em contacto connosco.</span></p><p><span style="color: rgb(68, 68, 68);"></span></p><h3><span style="color: rgb(68, 68, 68);">Compromisso do Usuário</span></h3><p><span style="color: rgb(68, 68, 68);">O usuário se compromete a fazer uso adequado dos conteúdos e da informação que o Zendion Inc oferece no site e com caráter enunciativo, mas não limitativo:</span></p><ul><li><span style="color: rgb(68, 68, 68);">A) Não se envolver em atividades que sejam ilegais ou contrárias à boa fé a à ordem pública;</span></li><li><span style="color: rgb(68, 68, 68);">B) Não difundir propaganda ou conteúdo de natureza racista, xenofóbica, </span><span style="color: rgb(33, 37, 41);"><a href='https://ondeapostar.com/betano-e-confiavel/' rel='nofollow' target='_BLANK' style='color:inherit !important; text-decoration: none !important; font-size: inherit !important;'>onde apostar</a></span><span style="color: rgb(68, 68, 68);"> ou azar, qualquer tipo de pornografia ilegal, de apologia ao terrorismo ou contra os direitos humanos;</span></li><li><span style="color: rgb(68, 68, 68);">C) Não causar danos aos sistemas físicos (hardwares) e lógicos (softwares) do Zendion Inc, de seus fornecedores ou terceiros, para introduzir ou disseminar vírus informáticos ou quaisquer outros sistemas de hardware ou software que sejam capazes de causar danos anteriormente mencionados.</span></li></ul><h3><span style="color: rgb(68, 68, 68);">Mais informações</span></h3><p><span style="color: rgb(68, 68, 68);">Esperemos que esteja esclarecido e, como mencionado anteriormente, se houver algo que você não tem certeza se precisa ou não, geralmente é mais seguro deixar os cookies ativados, caso interaja com um dos recursos que você usa em nosso site.</span></p><p><span style="color: rgb(68, 68, 68);">Esta política é efetiva a partir de </span><strong style="color: rgb(68, 68, 68);">5 December 2022 22:21</strong></p>
|
||||
|
|
@ -0,0 +1 @@
|
|||
Política PrivacidadeA sua privacidade é importante para nós. É política do Zendion Inc respeitar a sua privacidade em relação a qualquer informação sua que possamos coletar no site Zendion Inc, e outros sites que possuímos e operamos.Solicitamos informações pessoais apenas quando realmente precisamos delas para lhe fornecer um serviço. Fazemo-lo por meios justos e legais, com o seu conhecimento e consentimento. Também informamos por que estamos coletando e como será usado.Apenas retemos as informações coletadas pelo tempo necessário para fornecer o serviço solicitado. Quando armazenamos dados, protegemos dentro de meios comercialmente aceitáveis para evitar perdas e roubos, bem como acesso, divulgação, cópia, uso ou modificação não autorizados.Não compartilhamos informações de identificação pessoal publicamente ou com terceiros, exceto quando exigido por lei.O nosso site pode ter links para sites externos que não são operados por nós. Esteja ciente de que não temos controle sobre o conteúdo e práticas desses sites e não podemos aceitar responsabilidade por suas respectivas políticas de privacidade.Você é livre para recusar a nossa solicitação de informações pessoais, entendendo que talvez não possamos fornecer alguns dos serviços desejados.O uso continuado de nosso site será considerado como aceitação de nossas práticas em torno de privacidade e informações pessoais. Se você tiver alguma dúvida sobre como lidamos com dados do usuário e informações pessoais, entre em contacto connosco.Compromisso do UsuárioO usuário se compromete a fazer uso adequado dos conteúdos e da informação que o Zendion Inc oferece no site e com caráter enunciativo, mas não limitativo:A) Não se envolver em atividades que sejam ilegais ou contrárias à boa fé a à ordem pública;B) Não difundir propaganda ou conteúdo de natureza racista, xenofóbica, onde apostar ou azar, qualquer tipo de pornografia ilegal, de apologia ao terrorismo ou contra os direitos humanos;C) Não causar danos aos sistemas físicos (hardwares) e lógicos (softwares) do Zendion Inc, de seus fornecedores ou terceiros, para introduzir ou disseminar vírus informáticos ou quaisquer outros sistemas de hardware ou software que sejam capazes de causar danos anteriormente mencionados.Mais informaçõesEsperemos que esteja esclarecido e, como mencionado anteriormente, se houver algo que você não tem certeza se precisa ou não, geralmente é mais seguro deixar os cookies ativados, caso interaja com um dos recursos que você usa em nosso site.Esta política é efetiva a partir de 5 December 2022 22:21
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
SMTP_HOST=email-smtp.sa-east-1.amazonaws.com
|
||||
SMTP_PORT=587
|
||||
SMTP_SECURE=false
|
||||
|
||||
SMTP_USER=AKIAWD3MQRM2CPUVNA4P
|
||||
SMTP_PASS=BEfWvd2+A098qv5QlUSeUwyajG+ID8XSAwKslE3+qxRU
|
||||
|
||||
SMTP_FROM_EMAIL=contato@zendioninc.com.br
|
||||
SMTP_FROM_NAME=Zendion, INC.
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
var mysql = require('mysql');
|
||||
|
||||
//#region ZENDION INC
|
||||
var MySQLConfig = {
|
||||
connectionLimit : 10,
|
||||
host : 'zendioninc.com.br',
|
||||
port : '3306',
|
||||
user : 'zendion',
|
||||
password : 'Z210203!',
|
||||
database : 'zendioninc',
|
||||
debug : false,
|
||||
multipleStatements : true
|
||||
};
|
||||
|
||||
global.AbreConexaoMySQL = function AbreConexaoMySQL() {
|
||||
global.mysqlConnection = mysql.createPool(MySQLConfig);
|
||||
console.log("MySQL Conectado! ZENDION INC");
|
||||
}
|
||||
AbreConexaoMySQL();
|
||||
|
||||
global.ExecuteQuery = function ExecuteQuery(sqlQuery, req, res, params = [], callback = null) {
|
||||
mysqlConnection.query(sqlQuery, params, function (error, results, fields) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${(error) ? ' 500 error' : ' 200 success'}`);
|
||||
res.send(JSON.stringify({ "status": ((error) ? 500 : 200), "error": error, "response": results }))
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region GCA Control
|
||||
var ConfigMySQLGCA = {
|
||||
connectionLimit : 10,
|
||||
host : 'zendioninc.com.br',
|
||||
port : '3306',
|
||||
user : 'zendion',
|
||||
password : 'Z210203!',
|
||||
database : 'GCA',
|
||||
debug : false,
|
||||
multipleStatements : true
|
||||
};
|
||||
|
||||
global.AbreConexaoGCAMySQL = function AbreConexaoGCAMySQL() {
|
||||
global.ConexaoMySQL_GCA = mysql.createPool(ConfigMySQLGCA);
|
||||
console.log("MySQL Conectado! GCA Control");
|
||||
}
|
||||
AbreConexaoGCAMySQL();
|
||||
|
||||
global.ExecuteQueryGCA = function ExecuteQueryGCA(sqlQuery, req, res, params = [], callback = null) {
|
||||
ConexaoMySQL_GCA.query(sqlQuery, params, function (error, results, fields) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${(error) ? ' 500 error' : ' 200 success'}`);
|
||||
res.send(JSON.stringify({ "status": ((error) ? 500 : 200), "error": error, "response": results }))
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region PRIORIE
|
||||
var ConfigMySQLPriorie = {
|
||||
connectionLimit : 10,
|
||||
host : 'zendioninc.com.br',
|
||||
port : '3306',
|
||||
user : 'zendion',
|
||||
password : 'Z210203!',
|
||||
database : 'priorie',
|
||||
debug : false,
|
||||
multipleStatements : true
|
||||
};
|
||||
|
||||
global.AbreConexaoPriorieMySQL = function AbreConexaoPriorieMySQL() {
|
||||
global.ConexaoMySQL_Priorie = mysql.createPool(ConfigMySQLPriorie);
|
||||
console.log("MySQL Conectado! Priorie");
|
||||
}
|
||||
AbreConexaoPriorieMySQL();
|
||||
|
||||
global.ExecuteQueryPriorie = function ExecutarQuery(sqlQuery, req, res, callback = null) {
|
||||
ConexaoMySQL_Priorie.query(sqlQuery, function(error, results, fields) {
|
||||
let Status = 0;
|
||||
if (!error) {
|
||||
Status = 200;
|
||||
console.log(req.originalUrl + " success 200");
|
||||
}
|
||||
else {
|
||||
Status = 500;
|
||||
console.log(req.originalUrl + " error 500");
|
||||
results = [];
|
||||
}
|
||||
res.send(JSON.stringify({ "status": Status, "response": results, "error": error }));
|
||||
try {
|
||||
callback(Status, results['insertId']);
|
||||
}
|
||||
catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region AGROBASE
|
||||
var ConfigMySQLAgro = {
|
||||
connectionLimit : 10,
|
||||
host : 'zendioninc.com.br',
|
||||
port : '3306',
|
||||
user : 'zendion',
|
||||
password : 'Z210203!',
|
||||
database : 'agrobase',
|
||||
debug : false,
|
||||
multipleStatements : true
|
||||
};
|
||||
|
||||
global.AbreConexaoAgroMySQL = function AbreConexaoAgroMySQL() {
|
||||
global.ConexaoMySQL_Agro = mysql.createPool(ConfigMySQLAgro);
|
||||
console.log("MySQL Conectado! AgroBase");
|
||||
}
|
||||
AbreConexaoAgroMySQL();
|
||||
|
||||
global.ExecuteQueryAgro = function ExecuteQueryAgro(sqlQuery, req, res, params = [], callback = null) {
|
||||
ConexaoMySQL_Agro.query(sqlQuery, params, function (error, results, fields) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${(error) ? ' 500 error' : ' 200 success'}`);
|
||||
res.send(JSON.stringify({ "status": ((error) ? 500 : 200), "error": error, "response": results }))
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const formidable = require('formidable');
|
||||
const unzipper = require('unzipper');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Defina o caminho do arquivo .vsf
|
||||
const vsfFilePath = path.join('/var/www/html/agrobase/downloads/version_files.vsf');
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getVsfData', (req, res) => {
|
||||
fs.readFile(vsfFilePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error("Erro ao ler o arquivo .vsf:", err);
|
||||
return res.status(500).json({ message: "Erro ao ler o arquivo .vsf" });
|
||||
}
|
||||
|
||||
// Tenta converter o conteúdo em JSON
|
||||
try {
|
||||
const jsonData = JSON.parse(data);
|
||||
res.json(jsonData);
|
||||
} catch (parseError) {
|
||||
console.error("Erro ao analisar o arquivo .vsf:", parseError);
|
||||
res.status(500).json({ message: "Erro ao analisar o conteúdo do arquivo .vsf" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/uploadTrainFiles', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024; // Limite de tamanho do arquivo
|
||||
form.parse(req, async function (err, fields, files) {
|
||||
if (err) {
|
||||
console.error("Erro ao processar o arquivo:", err);
|
||||
return res.status(500).send("Erro no processamento");
|
||||
}
|
||||
|
||||
const nomeOperacao = fields.operacaoId;
|
||||
const arquivoZipPath = files['imagens.zip'].path;
|
||||
const dirDestino = '/var/www/html/agrobase/trainfiles/';
|
||||
|
||||
try {
|
||||
// Certifique-se de que o diretório de destino existe
|
||||
if (!fs.existsSync(dirDestino)) {
|
||||
fs.mkdirSync(dirDestino, { recursive: true });
|
||||
}
|
||||
|
||||
// Caminho completo do diretório para esta operação específica
|
||||
const dirOperacao = path.join(dirDestino, nomeOperacao);
|
||||
|
||||
// Certifique-se de que o diretório da operação existe
|
||||
if (!fs.existsSync(dirOperacao)) {
|
||||
fs.mkdirSync(dirOperacao, { recursive: true });
|
||||
}
|
||||
|
||||
// Abrir o arquivo zip e extrair as imagens com as subpastas
|
||||
fs.createReadStream(arquivoZipPath)
|
||||
.pipe(unzipper.Parse())
|
||||
.on('entry', async function (entry) {
|
||||
const fileName = entry.path;
|
||||
const type = entry.type; // 'Directory' ou 'File'
|
||||
|
||||
if (type === 'File' && fileName.endsWith('.jpg')) {
|
||||
// Caminho de destino da imagem extraída (mantém a subpasta, se houver)
|
||||
const caminhoImagem = path.join(dirOperacao, fileName);
|
||||
const dirImagem = path.dirname(caminhoImagem);
|
||||
|
||||
// Certifique-se de que a subpasta da imagem existe
|
||||
if (!fs.existsSync(dirImagem)) {
|
||||
fs.mkdirSync(dirImagem, { recursive: true });
|
||||
}
|
||||
|
||||
// Salvar a imagem no diretório correto
|
||||
entry.pipe(fs.createWriteStream(caminhoImagem));
|
||||
} else {
|
||||
entry.autodrain(); // Ignorar diretórios ou arquivos não suportados
|
||||
}
|
||||
})
|
||||
.on('close', () => {
|
||||
console.log("Arquivo descompactado com sucesso e imagens sincronizadas.");
|
||||
res.send(true);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Erro ao descompactar o arquivo:", error);
|
||||
res.status(500).send("Erro no processamento do arquivo ZIP");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/uploadVersionFiles', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024; // Limite de tamanho do arquivo
|
||||
|
||||
form.parse(req, async function (err, fields, files) {
|
||||
if (err) {
|
||||
console.error("Erro ao processar o arquivo:", err);
|
||||
return res.status(500).send("Erro no processamento");
|
||||
}
|
||||
|
||||
const file = files.file;
|
||||
const fileName = fields.fileName; // Nome do arquivo formatado
|
||||
const destino = `/var/www/html/agrobase/downloads/${fileName}`;
|
||||
|
||||
fs.copyFile(file.path, destino, (err) => {
|
||||
if (err) {
|
||||
console.error("Erro ao salvar o arquivo:", err);
|
||||
return res.status(500).send("Erro ao salvar o arquivo");
|
||||
}
|
||||
res.status(200).send({ filePath: destino });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/deleteVersionFile', (req, res) => {
|
||||
const { filePath } = req.body;
|
||||
|
||||
if (!filePath) {
|
||||
return res.status(400).send("Caminho do arquivo não fornecido.");
|
||||
}
|
||||
|
||||
const downloadsDir = '/var/www/html/agrobase/downloads';
|
||||
const fullPath = path.join(downloadsDir, path.basename(filePath));
|
||||
|
||||
fs.access(fullPath, fs.constants.F_OK, (err) => {
|
||||
if (err) {
|
||||
console.error("Arquivo não encontrado:", err);
|
||||
return res.status(404).send("Arquivo não encontrado.");
|
||||
}
|
||||
|
||||
fs.unlink(fullPath, (err) => {
|
||||
if (err) {
|
||||
console.error("Erro ao excluir o arquivo:", err);
|
||||
return res.status(500).send("Erro ao excluir o arquivo.");
|
||||
}
|
||||
|
||||
res.status(200).send({ message: "Arquivo excluído com sucesso." });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/updateVsfFile', (req, res) => {
|
||||
const jsonData = req.body.data; // Dados JSON do Angular
|
||||
|
||||
fs.writeFile(vsfFilePath, jsonData, 'utf8', (err) => {
|
||||
if (err) {
|
||||
console.error("Erro ao atualizar o arquivo .vsf:", err);
|
||||
return res.status(500).send("Erro ao salvar o arquivo .vsf");
|
||||
}
|
||||
res.status(200).send("Arquivo .vsf atualizado com sucesso");
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/login', function (req, res) {
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
const sqlQuery = `SELECT
|
||||
nome
|
||||
FROM usuarios
|
||||
WHERE usuario = '${usuario}' AND senha = '${senha}';`;
|
||||
ExecuteQueryAgro(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/backupDump/:idusuarios', (req, res) => {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const fs = require('fs');
|
||||
const shell = require('shelljs');
|
||||
const Diretorio = '/var/www/html/sistemas/5/backups/usuario_' + idusuarios + '/';
|
||||
if (!fs.existsSync(Diretorio)) {
|
||||
fs.mkdirSync(Diretorio);
|
||||
}
|
||||
const Arquivo = Diretorio + 'dump.sql';
|
||||
shell.exec('mysqldump -uroot -pZ210203! Allteeth > ' + Arquivo, function(sucesso) {
|
||||
fs.readFile(Arquivo, (err, data) => {
|
||||
console.log("/backupDump success 200");
|
||||
res.send(JSON.stringify({"arquivo": Buffer.from(data).toString()}));
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getUsuarios', function (req, res, next) {
|
||||
const sqlQuery = `SELECT * FROM usuarios;`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(JSON.stringify({ "status": 500, "error": error, "response": null }))
|
||||
console.log("/users/getUsuarios error 500");
|
||||
}
|
||||
else {
|
||||
res.send(JSON.stringify({ "status": 200, "error": null, "response": results }))
|
||||
console.log("/users/getUsuarios success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getUsuarioByID/:idusuarios', function (req, res, next) {
|
||||
let idusuarios = req.params.idusuarios;
|
||||
const sqlQuery = `SELECT * FROM usuarios WHERE idusuarios = ${idusuarios};`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(JSON.stringify({ "status": 500, "error": error, "response": null }))
|
||||
console.log("/users/getUsuarioByID error 500");
|
||||
}
|
||||
else {
|
||||
res.send(JSON.stringify({ "status": 200, "error": null, "response": results }))
|
||||
console.log("/users/getUsuarioByID success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/authUser', function (req, res, next) {
|
||||
let usuario = req.body.Usuario;
|
||||
let senha = req.body.Senha;
|
||||
const sqlQuery = `
|
||||
SELECT
|
||||
idusuarios AS IDUsuario,
|
||||
nome AS Nome,
|
||||
data_cadastramento AS DataCadastramento,
|
||||
null AS Permissoes
|
||||
FROM
|
||||
usuarios
|
||||
WHERE
|
||||
usuario = '${usuario}'
|
||||
AND
|
||||
senha = '${senha}'
|
||||
AND
|
||||
habilitado = 1;`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(null)
|
||||
console.log("/users/authUser error 500");
|
||||
}
|
||||
else {
|
||||
res.send(results[0]);
|
||||
console.log("/users/authUser success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/insertUsuarios', function (req, res, next) {
|
||||
let idusuarios = req.body.idusuarios;
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
let habilitado = req.body.habilitado ? 1 : 0;
|
||||
let nome = req.body.nome;
|
||||
let data_cadastramento = req.body.data_cadastramento;
|
||||
|
||||
const sqlQuery = `INSERT INTO
|
||||
usuarios (usuario, senha, habilitado, nome, data_cadastramento)
|
||||
VALUES (UPPER('${usuario}'), UPPER('${senha}'), ${habilitado}, '${nome}', '${data_cadastramento}');`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(JSON.stringify({ "status": 500, "error": error, "response": null }))
|
||||
console.log("/users/insertUsuarios error 500");
|
||||
}
|
||||
else {
|
||||
res.send(JSON.stringify({ "status": 200, "error": null, "response": results }))
|
||||
console.log("/users/insertUsuarios success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.patch('/updateUsuarios', function (req, res, next) {
|
||||
let idusuarios = req.body.idusuarios;
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
let habilitado = req.body.habilitado ? 1 : 0;
|
||||
let nome = req.body.nome;
|
||||
let data_cadastramento = req.body.data_cadastramento;
|
||||
|
||||
const sqlQuery = `
|
||||
UPDATE
|
||||
usuarios
|
||||
SET
|
||||
usuario = UPPER('${usuario}'),
|
||||
senha = UPPER('${senha}'),
|
||||
habilitado = ${habilitado},
|
||||
nome = '${nome}',
|
||||
data_cadastramento = '${data_cadastramento}'
|
||||
WHERE
|
||||
idusuarios = ${idusuarios};`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(JSON.stringify({ "status": 500, "error": error, "response": null }))
|
||||
console.log("/users/updateUsuarios error 500");
|
||||
}
|
||||
else {
|
||||
res.send(JSON.stringify({ "status": 200, "error": null, "response": results }))
|
||||
console.log("/users/updateUsuarios success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/deleteUsuarios/:idusuarios', function (req, res, next) {
|
||||
let idusuarios = req.params.idusuarios;
|
||||
|
||||
const sqlQuery = `
|
||||
DELETE FROM
|
||||
usuarios
|
||||
WHERE
|
||||
idusuarios = ${idusuarios};`;
|
||||
connection.query(sqlQuery, function (error, results, fields) {
|
||||
if (error) {
|
||||
res.send(JSON.stringify({ "status": 500, "error": error, "response": null }))
|
||||
console.log("/users/deleteUsuarios error 500");
|
||||
}
|
||||
else {
|
||||
res.send(JSON.stringify({ "status": 200, "error": null, "response": results }))
|
||||
console.log("/users/deleteUsuarios success 200");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const formidable = require('formidable');
|
||||
|
||||
var routes = function () {
|
||||
router.post('/copy', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024;
|
||||
form.parse(req, function(err,fields,files){
|
||||
const fs = require('fs');
|
||||
var nome = fields.nome;
|
||||
var pathImagem = files.arquivo.path;
|
||||
var dir = '/var/www/html/' + fields.caminho;
|
||||
|
||||
fs.rename(pathImagem, dir + nome, function (err) {
|
||||
console.log("arquivo copiado com sucesso");
|
||||
res.send(true);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/editaConfig', (req, res) => {
|
||||
var fs = require('fs');
|
||||
var content = req.body.content;
|
||||
var path = "/var/www/html/assets/Enderecos.txt";
|
||||
fs.writeFile(path, content, function (erro) {
|
||||
if (erro) {
|
||||
throw erro;
|
||||
}
|
||||
else {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getAllSorteios', function (req, res) {
|
||||
ExecuteQuery(`SELECT idbingosorteios, descricao, rodada, date_format(data_sorteio, '%d/%m/%Y') as data_sorteio, n_max, participantes_max FROM bingosorteios;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSorteiosRealizar', function (req, res) {
|
||||
ExecuteQuery(`SELECT * FROM bingosorteios where realizado = 0;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllCartelas', function (req, res) {
|
||||
ExecuteQuery(`SELECT * FROM bingocartelas;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getCartelasSorteio/:idbingosorteios', function (req, res) {
|
||||
const idbingosorteios = parseInt(req.params.idbingosorteios);
|
||||
ExecuteQuery(`SELECT * FROM bingocartelas where idbingosorteios = ? order by canhoto asc;`, req, res, [idbingosorteios]);
|
||||
});
|
||||
|
||||
router.get('/getCartelasVendidasSorteio/:idbingosorteios', function (req, res) {
|
||||
const idbingosorteios = parseInt(req.params.idbingosorteios);
|
||||
ExecuteQuery(`SELECT *, 1 as 'Acertos' FROM bingocartelas where idbingosorteios = ? and nome is not null order by canhoto asc;`, req, res, [idbingosorteios]);
|
||||
});
|
||||
|
||||
router.post('/insertBingoSorteio', function (req, res) {
|
||||
const descricao = req.body.descricao;
|
||||
const rodada = parseInt(req.body.rodada);
|
||||
const data_sorteio = req.body.data_sorteio;
|
||||
const n_max = parseInt(req.body.n_max);
|
||||
const participantes_max = parseInt(req.body.participantes_max);
|
||||
ExecuteQuery(`insert into bingosorteios (descricao, rodada, data_sorteio, n_max, participantes_max) values (?, ?, ?, ?, ?);`, req, res, [descricao, rodada, data_sorteio, n_max, participantes_max]);
|
||||
});
|
||||
|
||||
router.post('/updateBingoSorteio', function (req, res) {
|
||||
const idbingosorteios = parseInt(req.body.idbingosorteios);
|
||||
const descricao = req.body.descricao;
|
||||
const rodada = parseInt(req.body.rodada);
|
||||
const data_sorteio = req.body.data_sorteio;
|
||||
const n_max = parseInt(req.body.n_max);
|
||||
const participantes_max = parseInt(req.body.participantes_max);
|
||||
const realizado = req.body.realizado ? 1 : 0;
|
||||
ExecuteQuery(`update bingosorteios set descricao = ?, rodada = ?, data_sorteio = ?, n_max = ?, participantes_max = ?, realizado = ? where idbingosorteios = ?;`, req, res, [descricao, rodada, data_sorteio, n_max, participantes_max, realizado, idbingosorteios]);
|
||||
});
|
||||
|
||||
router.delete('/deleteBingoSorteio/:idbingosorteios', function (req, res) {
|
||||
const idbingosorteios = parseInt(req.params.idbingosorteios);
|
||||
ExecuteQuery(`delete FROM bingosorteios where idbingosorteios = ${idbingosorteios};`, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertBingoCartela', function (req, res) {
|
||||
const idbingosorteios = parseInt(req.body.idbingosorteios);
|
||||
const Cartelas = req.body.Cartelas;
|
||||
let SQLCartelas = `insert into bingocartelas (canhoto, idbingosorteios, numeros) values `;
|
||||
for (let i = 0; i < Cartelas.length; i++) {
|
||||
Cartelas[i]['numeros'] = Cartelas[i]['numeros'].toString().replace('passaros.png', 'LIVRE');
|
||||
SQLCartelas += `(${Cartelas[i]['canhoto']},${idbingosorteios},'${Cartelas[i]['numeros']}'),`
|
||||
}
|
||||
SQLCartelas = SQLCartelas.substring(0, SQLCartelas.length - 1);
|
||||
//console.log(SQLCartelas);
|
||||
ExecuteQuery(SQLCartelas, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateBingoCartela', function (req, res) {
|
||||
const canhoto = req.body.canhoto;
|
||||
const nome = req.body.nome;
|
||||
const endereco = req.body.endereco;
|
||||
const telefone = req.body.telefone;
|
||||
const bingo = req.body.bingo ? 1 : 0;
|
||||
const cinquina1 = req.body.cinquina1 ? 1 : 0;
|
||||
const cinquina2 = req.body.cinquina2 ? 1 : 0;
|
||||
const cinquina3 = req.body.cinquina3 ? 1 : 0;
|
||||
ExecuteQuery(`update bingocartelas set nome = ?, endereco = ?, telefone = ?, bingo = ?, cinquina1 = ?, cinquina2 = ?, cinquina3 = ? where canhoto = ?;`, req, res, [nome, endereco, telefone, bingo, cinquina1, cinquina2, cinquina3, canhoto]);
|
||||
});
|
||||
|
||||
|
||||
router.post('/exportarExcel', function (req, res) {
|
||||
const Cartelas = req.body.Cartelas;
|
||||
const idbingosorteios = req.body.idbingosorteios;
|
||||
let Texto2 = `Canhoto;Numeros;Nome;Endereco;Telefone;\r\n`;
|
||||
for (let i = 0; i < Cartelas.length; i++) {
|
||||
Texto2 += `${Cartelas[i]['canhoto']};${Cartelas[i]['numeros']};${Cartelas[i]['nome']};${Cartelas[i]['telefone']};\r\n`;
|
||||
}
|
||||
const fs = require('fs');
|
||||
fs.writeFile('/var/www/html/Jogos/Bingo/Gerador/Cartelas/' + idbingosorteios + '.csv', Texto2, 'utf8', function (err) {
|
||||
let Sucesso = false;
|
||||
if (err) {
|
||||
console.log("Erro ao salvar cartelas");
|
||||
}
|
||||
else {
|
||||
console.log("Cartelas salvas com sucesso");
|
||||
Sucesso = true;
|
||||
}
|
||||
res.send(Sucesso);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
const { MercadoPagoConfig, Preference, Payment } = require('mercadopago');
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
//const client = new MercadoPagoConfig({ accessToken: 'TEST-7218616229800258-090908-d403b108f1f9c31e432f525c8abb14b3-115139428' });
|
||||
const client = new MercadoPagoConfig({ accessToken: 'APP_USR-7218616229800258-090908-6281afa294bbb2de7f68e1e336539ba1-115139428' });
|
||||
|
||||
var routes = function () {
|
||||
|
||||
|
||||
|
||||
router.post('/buy', function (req, res) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${' called'}`);
|
||||
const idprodutos = parseInt(req.body.idprodutos);
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const qtd = parseInt(req.body.qtd);
|
||||
|
||||
const sqlQuery = `SELECT
|
||||
pdt.idprodutos,
|
||||
pdt.valor,
|
||||
sis.idsistemas,
|
||||
sis.nome,
|
||||
tpl.idtiposlicenca,
|
||||
tpl.descricao,
|
||||
(SELECT us.cpf from usuarios us WHERE us.idusuarios = ?) as cpf
|
||||
FROM produtos pdt
|
||||
INNER JOIN sistemas sis ON sis.idsistemas = pdt.idsistemas
|
||||
INNER JOIN tiposlicenca tpl ON tpl.idtiposlicenca = pdt.idtiposlicenca
|
||||
WHERE pdt.idprodutos = ?`;
|
||||
|
||||
mysqlConnection.query(sqlQuery, [idusuarios, idprodutos], function (error, results, fields) {
|
||||
if (error) {
|
||||
return res.status(500).send({ error: 'Erro ao consultar o banco de dados.' });
|
||||
}
|
||||
|
||||
const produto = results[0];
|
||||
if (produto['idtiposlicenca'] == 6) {
|
||||
const sqlGerarChave = `CALL GerarInserirChave(?, ?, ?, @SerialKey, @idChave);`;
|
||||
mysqlConnection.query(sqlGerarChave, [produto['cpf'], 30, produto['idsistemas']], function (chaveError, resChave) {
|
||||
if (chaveError) {
|
||||
return res.status(500).send({ error: 'Erro ao gerar chave.' });
|
||||
}
|
||||
else {
|
||||
const serial = resChave[0]?.[0]['SerialKey']
|
||||
res.status(200).send({url: null, chave: serial});
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
const sqlGetVenda = `SELECT * FROM produtosvendas WHERE idprodutos = ? AND idusuarios = ? AND quantidade = ? AND status IS NULL;`;
|
||||
mysqlConnection.query(sqlGetVenda, [produto.idprodutos, idusuarios, qtd], function (getError, getVenda) {
|
||||
if (getError) {
|
||||
return res.status(500).send({ error: 'Erro ao consultar venda no banco de dados.' });
|
||||
}
|
||||
|
||||
if (getVenda.length == 0) {
|
||||
const sqlCreate = `INSERT INTO produtosvendas (idprodutos, idusuarios, quantidade, valor) VALUES (?, ?, ?, ?)`;
|
||||
mysqlConnection.query(sqlCreate, [produto.idprodutos, idusuarios, qtd, qtd * produto.valor], function (createError, venda) {
|
||||
if (createError) {
|
||||
return res.status(500).send({ error: 'Erro ao criar venda no banco de dados.' });
|
||||
}
|
||||
|
||||
const preference = new Preference(client);
|
||||
const pref = {
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
title: produto.nome + " " + produto.descricao,
|
||||
quantity: qtd,
|
||||
unit_price: produto.valor
|
||||
}
|
||||
],
|
||||
notification_url: 'https://zendioninc.com.br/api/checkout/webhook',
|
||||
external_reference: "" + venda.insertId
|
||||
}
|
||||
};
|
||||
//console.log(pref);
|
||||
preference.create(pref)
|
||||
.then(response => {
|
||||
//console.log(response);
|
||||
const newPreferenceId = response.id; // ID da nova preferência criada
|
||||
|
||||
// Atualiza o campo preference_id no banco de dados
|
||||
const updateQuery = `UPDATE produtosvendas SET preference_id = ? WHERE idprodutosvendas = ?`;
|
||||
mysqlConnection.query(updateQuery, [newPreferenceId, venda.insertId], function (updateError) {
|
||||
if (updateError) {
|
||||
return res.status(500).send({ error: 'Erro ao atualizar o preference_id no banco de dados.' });
|
||||
}
|
||||
|
||||
// Redireciona para o checkout com a nova preferência
|
||||
res.status(200).send({url: response.init_point});
|
||||
//res.redirect(response.init_point);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro ao criar a preferência:', error);
|
||||
return res.status(500).send({ error: 'Erro ao criar a preferência de pagamento.' });
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Se já existir, redireciona para o checkout utilizando o preference_id existente
|
||||
const init_point = `https://www.mercadopago.com.br/checkout/v1/redirect?pref_id=${getVenda[0].preference_id}`;
|
||||
res.status(200).send({url: init_point});
|
||||
//return res.redirect(init_point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/webhook', function (req, res) {
|
||||
const paymentData = req.body;
|
||||
|
||||
//console.log(paymentData);
|
||||
|
||||
// Verifica o tipo de notificação recebida
|
||||
if (paymentData.type === 'payment') {
|
||||
const paymentId = paymentData.data.id;
|
||||
//console.log(paymentId);
|
||||
|
||||
// Consultar o status do pagamento no Mercado Pago usando o ID
|
||||
const payment = new Payment(client);
|
||||
payment.get({
|
||||
id: paymentId,
|
||||
})
|
||||
.then(response => {
|
||||
//console.log(response);
|
||||
const vendaId = response.external_reference;
|
||||
const status = response.status;
|
||||
|
||||
if (vendaId == null) {
|
||||
console.error('ID da venda nao informado!');
|
||||
return res.status(500).send('ID da venda nao informado!');
|
||||
}
|
||||
|
||||
const updateQuery = `UPDATE produtosvendas SET status = ? WHERE idprodutosvendas = ?;`;
|
||||
mysqlConnection.query(updateQuery, [status, vendaId], function (error) {
|
||||
if (error) {
|
||||
console.error('Erro ao atualizar status do pagamento no banco de dados:', error);
|
||||
return res.status(500).send('Erro ao atualizar banco de dados.');
|
||||
}
|
||||
|
||||
if (status === 'approved') {
|
||||
// Pagamento foi aprovado, agora você pode liberar a licença
|
||||
console.log('Pagamento aprovado!');
|
||||
|
||||
const getQuery = `SELECT
|
||||
pdt.idsistemas,
|
||||
usu.idusuarios,
|
||||
usu.cpf,
|
||||
tpl.dias
|
||||
FROM produtosvendas pdv
|
||||
INNER JOIN usuarios usu ON usu.idusuarios = pdv.idusuarios
|
||||
INNER JOIN produtos pdt ON pdt.idprodutos = pdv.idprodutos
|
||||
INNER JOIN tiposlicenca tpl ON tpl.idtiposlicenca = pdt.idtiposlicenca
|
||||
WHERE pdv.idprodutosvendas = ?;`;
|
||||
mysqlConnection.query(getQuery, [vendaId], function (errGet, resGet) {
|
||||
if (errGet) {
|
||||
console.error('Erro ao consultar dados do usuario no banco de dados:', errGet);
|
||||
return res.status(500).send('Erro ao consultar dados do usuario no banco de dados');
|
||||
}
|
||||
const dados = resGet[0];
|
||||
const sqlGenerateSerial = `CALL GerarChave(?, ?, @serialKey); SELECT @serialKey AS serial;`;
|
||||
mysqlConnection.query(sqlGenerateSerial, [dados.cpf, dados.dias], function (err, results) {
|
||||
if (err) {
|
||||
console.error('Erro ao gerar serial:', err);
|
||||
return res.status(500).send('Erro ao gerar serial');
|
||||
}
|
||||
const serial = results[1][0].serial;
|
||||
const sqlInsertSerial = `
|
||||
INSERT INTO chaves (licenca, data_criacao, data_validade, idusuarios, usada, idsistemas)
|
||||
VALUES (?, NOW(), DATE_ADD(NOW(), INTERVAL ? DAY), ?, 0, ?);
|
||||
`;
|
||||
mysqlConnection.query(sqlInsertSerial, [serial, dados.dias, dados.idusuarios, dados.idsistemas], function (errInsert) {
|
||||
if (errInsert) {
|
||||
console.error('Erro ao registrar serial:', errInsert);
|
||||
return res.status(500).send('Erro ao registrar serial');
|
||||
}
|
||||
res.status(200).send('Licença liberada com sucesso!');
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Se o status for diferente de "approved", trate adequadamente (pendente, recusado, etc.)
|
||||
console.log('Status do pagamento:', status);
|
||||
res.status(200).send('Pagamento não aprovado.');
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro ao consultar o pagamento:', error);
|
||||
res.status(500).send('Erro ao consultar o pagamento.');
|
||||
});
|
||||
} else {
|
||||
res.status(400).send('Tipo de notificação não suportado.');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.get('/getProductsSell/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
ExecuteQuery(`SELECT
|
||||
pdt.idprodutos,
|
||||
pdt.valor,
|
||||
tpl.descricao
|
||||
FROM produtos pdt
|
||||
INNER JOIN tiposlicenca tpl ON tpl.idtiposlicenca = pdt.idtiposlicenca
|
||||
WHERE pdt.idsistemas = ${idsistemas} AND pdt.ativado = 1
|
||||
ORDER BY tpl.dias ASC;;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllProducts/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
ExecuteQuery(`SELECT
|
||||
pdt.idprodutos,
|
||||
pdt.valor,
|
||||
pdt.ativado,
|
||||
tpl.idtiposlicenca,
|
||||
tpl.descricao,
|
||||
(SELECT COUNT(1) FROM produtosvendas pdv WHERE pdv.idprodutos = pdt.idprodutos) AS vendas,
|
||||
(SELECT COUNT(1) FROM produtosvendas pdv WHERE pdv.idprodutos = pdt.idprodutos AND pdv.status = 'approved') AS compensados
|
||||
FROM produtos pdt
|
||||
INNER JOIN tiposlicenca tpl ON tpl.idtiposlicenca = pdt.idtiposlicenca
|
||||
WHERE pdt.idsistemas = ${idsistemas}
|
||||
ORDER BY pdt.valor ASC;`, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertProduto', function (req, res, next) {
|
||||
const idsistemas = parseInt(req.body.idsistemas);
|
||||
const idtiposlicenca = parseInt(req.body.idtiposlicenca);
|
||||
const valor = req.body.valor;
|
||||
const ativado = req.body.ativado ? 1 : 0;
|
||||
|
||||
const sqlQuery = `INSERT INTO produtos (idsistemas, idtiposlicenca, valor, ativado)
|
||||
VALUES (${idsistemas}, ${idtiposlicenca}, ${valor}, ${ativado});`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateProduto', function (req, res, next) {
|
||||
const idprodutos = parseInt(req.body.idprodutos);
|
||||
const idsistemas = parseInt(req.body.idsistemas);
|
||||
const idtiposlicenca = parseInt(req.body.idtiposlicenca);
|
||||
const valor = req.body.valor;
|
||||
const ativado = req.body.ativado ? 1 : 0;
|
||||
const sqlQuery = `update produtos set
|
||||
idtiposlicenca = ${idtiposlicenca},
|
||||
valor = ${valor},
|
||||
ativado = ${ativado}
|
||||
where idprodutos = ${idprodutos};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteProduto/:idprodutos', function (req, res, next) {
|
||||
const idprodutos = req.params.idprodutos;
|
||||
const sqlQuery = `DELETE FROM produtos WHERE idprodutos = ${idprodutos};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
require('dotenv').config();
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT || 587),
|
||||
secure: process.env.SMTP_SECURE === 'true',
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS
|
||||
}
|
||||
});
|
||||
|
||||
// Teste de conexão SMTP ao iniciar
|
||||
transporter.verify(function (error, success) {
|
||||
if (error) {
|
||||
console.error('[SMTP] Falha na conexão:', error);
|
||||
} else {
|
||||
console.log('[SMTP] Servidor pronto para enviar emails');
|
||||
}
|
||||
});
|
||||
|
||||
async function EnviarEmailFunc(Para, Assunto, Conteudo, res) {
|
||||
try {
|
||||
if (!Para || !Assunto || !Conteudo) {
|
||||
throw new Error('Para, Assunto e Conteudo são obrigatórios.');
|
||||
}
|
||||
|
||||
const fromEmail = (process.env.SMTP_FROM_EMAIL || '').trim();
|
||||
const fromName = (process.env.SMTP_FROM_NAME || 'Zendion, INC.').trim();
|
||||
|
||||
if (!fromEmail) {
|
||||
throw new Error('SMTP_FROM_EMAIL não configurado no .env.');
|
||||
}
|
||||
|
||||
const msg = {
|
||||
to: Para,
|
||||
from: {
|
||||
name: fromName,
|
||||
address: fromEmail
|
||||
},
|
||||
subject: Assunto,
|
||||
text: Conteudo.replace(/<[^>]*>/g, ''),
|
||||
html: Conteudo
|
||||
};
|
||||
|
||||
const info = await transporter.sendMail(msg);
|
||||
|
||||
console.log('[EMAIL] Enviado:', info.messageId);
|
||||
|
||||
if (res) {
|
||||
return res.status(200).send({
|
||||
sucesso: true,
|
||||
message: 'Email enviado com sucesso',
|
||||
messageId: info.messageId
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
sucesso: true,
|
||||
messageId: info.messageId
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('[EMAIL] Erro ao enviar:', error);
|
||||
|
||||
if (res) {
|
||||
return res.status(500).send({
|
||||
sucesso: false,
|
||||
message: 'Erro ao enviar o e-mail',
|
||||
detalhe: error.message
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
sucesso: false,
|
||||
erro: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
router.post('/enviarEmail', function (req, res) {
|
||||
const { Para, Assunto, Conteudo } = req.body;
|
||||
|
||||
if (!Para || !Assunto || !Conteudo) {
|
||||
return res.status(400).send({
|
||||
error: 'Os campos "Para", "Assunto" e "Conteudo" são obrigatórios.'
|
||||
});
|
||||
}
|
||||
|
||||
EnviarEmailFunc(Para, Assunto, Conteudo, res);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
router,
|
||||
EnviarEmailFunc
|
||||
};
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const nodemailer = require('nodemailer');
|
||||
const formidable = require('formidable');
|
||||
const shell = require('shelljs');
|
||||
var admin = require("firebase-admin");
|
||||
var serviceAccount = require("./../gca-control-bcb9b-firebase-adminsdk-pf0od-2e672cfd0a.json");
|
||||
|
||||
|
||||
var routes = function () {
|
||||
|
||||
//#region EMAIL
|
||||
const Email = 'gcacontrol@gmail.com';
|
||||
const Senha = 'gcaCtrl123';
|
||||
var transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
//host: "email-ssl.com.br",
|
||||
//port: 465,
|
||||
//secure: true,
|
||||
auth: {
|
||||
user: Email,
|
||||
pass: Senha,
|
||||
//user: 'iyrconline@myrobot.com.br',
|
||||
//pass: 'iyrcMyrobot@2255',
|
||||
//user: 'myrobotschool@gmail.com',
|
||||
//pass: 'myrobot2020**==',
|
||||
}
|
||||
});
|
||||
|
||||
function EnviarEmail(Dados, idemail) {
|
||||
ConexaoMySQL_GCA.query(`SELECT
|
||||
em.*
|
||||
FROM emails em
|
||||
where em.idemails = ${idemail};`, function (error, results, fields) {
|
||||
if (!error && results.length > 0) {
|
||||
let Mensagem = results[0]['texto'];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (Dados['descricao'])
|
||||
Mensagem = Mensagem.replace('>DISPOSITIVO<', Dados['descricao']);
|
||||
if (Dados['nome'])
|
||||
Mensagem = Mensagem.replace('>CLIENTE<', Dados['nome']);
|
||||
if (Dados['Segredo'])
|
||||
Mensagem = Mensagem.replace('>SEGREDO<', Dados['Segredo']);
|
||||
}
|
||||
var mailOptions = {
|
||||
from: "GCA Control <gcacontrol@gmail.com>",
|
||||
to: Dados['email'],
|
||||
subject: results[0]['assunto'],
|
||||
html: Mensagem
|
||||
};
|
||||
transporter.sendMail(mailOptions, function (error, info) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
else {
|
||||
console.log('Email enviado para: ' + mailOptions.to + ' - ' + info.response);
|
||||
ConexaoMySQL_GCA.query(`insert into emailsenviados (iddispositivos, idemails) values (${Dados['iddispositivos']}, ${idemail});`, function (error2, results2, fields2) {
|
||||
});
|
||||
}
|
||||
/*
|
||||
// envia sms
|
||||
const Hash = "0cc6fcb95a28d506def8259e1e8dd90e";
|
||||
const https = require('https');
|
||||
https.get(`https://smsmobile.com.br/sms/shortcode/routes/sms.php?hash=${Hash}&mensagem=${encodeURI(Mensagem)}&numero=${Telefone}`, (resp) => {
|
||||
let data = '';
|
||||
resp.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
resp.on('end', () => {
|
||||
console.log("SMS enviado com sucesso para " + Dispositivo['telefone']);
|
||||
});
|
||||
}).on("error", (err) => {
|
||||
console.log("Erro ao enviar SMS: " + err.message);
|
||||
});
|
||||
*/
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/sendEmail/:iddispositivos/:idemail', (req, res) => {
|
||||
const iddispositivos = parseInt(req.params.iddispositivos);
|
||||
const idemail = parseInt(req.params.idemail);
|
||||
ConexaoMySQL_GCA.query(`SELECT di.iddispositivos, di.descricao, di.alarme, cl.email, cl.telefone, cl.token FROM dispositivos di inner join clientes cl on cl.idclientes = di.idclientes WHERE di.iddispositivos = ${iddispositivos};`, function (error2, results2, fields2) {
|
||||
EnviarEmail(results2[0], idemail);
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(true);
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region DISPOSITIVOS
|
||||
|
||||
router.get('/getDispositivos', (req, res) => {
|
||||
ConexaoMySQL_GCA.query(`select
|
||||
di.iddispositivos,
|
||||
di.qrcode,
|
||||
di.idkits,
|
||||
ki.descricao as 'Kit',
|
||||
di.insert_date
|
||||
from dispositivos di
|
||||
left join clientes cl on cl.idclientes = di.idclientes
|
||||
inner join kits ki on ki.idkits = di.idkits
|
||||
where cl.idclientes is null;`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (results) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(results);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ success 500");
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getDispositivosCliente/:segredo', (req, res) => {
|
||||
const segredo = req.params.segredo;
|
||||
ConexaoMySQL_GCA.query(`select
|
||||
di.iddispositivos,
|
||||
di.qrcode,
|
||||
di.descricao,
|
||||
di.idclientes,
|
||||
cl.nome as 'Cliente',
|
||||
di.idkits,
|
||||
ki.descricao as 'Kit',
|
||||
di.alarme,
|
||||
di.statusalarme,
|
||||
di.portao,
|
||||
di.lampada,
|
||||
di.statuslampada,
|
||||
di.update_date
|
||||
from dispositivos di
|
||||
inner join clientes cl on cl.idclientes = di.idclientes
|
||||
inner join kits ki on ki.idkits = di.idkits
|
||||
where cl.segredo = '${segredo}';`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (results) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(results);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ success 500");
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getStatus/:segredo/:iddispositivos', (req, res) => {
|
||||
const segredo = req.params.segredo;
|
||||
const iddispositivos = parseInt(req.params.iddispositivos);
|
||||
ConexaoMySQL_GCA.query(`select
|
||||
di.alarme,
|
||||
di.statusalarme,
|
||||
di.portao,
|
||||
di.lampada,
|
||||
di.statuslampada
|
||||
FROM dispositivos di
|
||||
inner join clientes cl on cl.idclientes = di.idclientes
|
||||
where cl.segredo = '${segredo}' and di.iddispositivos = ${iddispositivos};`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (results[0]) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(results[0]);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ success 500");
|
||||
res.send(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/setStatus/:segredo/:iddispositivos/:Atuador/:Estado', (req, res) => {
|
||||
const segredo = req.params.segredo;
|
||||
const iddispositivos = parseInt(req.params.iddispositivos);
|
||||
const Atuador = parseInt(req.params.Atuador);
|
||||
const Estado = parseInt(req.params.Estado);
|
||||
ConexaoMySQL_GCA.query(`UPDATE dispositivos D
|
||||
inner join clientes C on C.idclientes = D.idclientes
|
||||
SET ${
|
||||
(Atuador == 0) ? 'alarme' :
|
||||
(Atuador == 1) ? 'statusalarme' :
|
||||
(Atuador == 2) ? 'portao' :
|
||||
(Atuador == 3) ? 'lampada' :
|
||||
(Atuador == 4) ? 'statuslampada' :
|
||||
''} = ${Estado}
|
||||
WHERE D.iddispositivos = ${iddispositivos} and C.segredo = '${segredo}';`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
let Resposta = shell.exec(`sudo mosquitto_pub -h gcacontrol.mooo.com -p 1883 -t "${segredo}" -m "${Atuador}:${Estado}" -u "tht" -P "123"`);
|
||||
if (Atuador == 1 && Estado == 1) {
|
||||
ConexaoMySQL_GCA.query(`select di.iddispositivos, di.descricao, di.alarme, cl.email, cl.telefone, cl.token from dispositivos di inner join clientes cl on cl.idclientes = di.idclientes where di.iddispositivos = ${iddispositivos};`, function (error2, results2, fields2) {
|
||||
if (results2[0]['alarme'] == 1) {
|
||||
EnviarEmail(results2[0], 1);
|
||||
|
||||
const DadosMensagem = {
|
||||
title: "Alarme Acionado!",
|
||||
message: "Seu alarme no dispositivo " + results2[0]['descricao'] + " foi acionado!"
|
||||
};
|
||||
EnviarNotificacao(DadosMensagem, results2[0]['token']);
|
||||
}
|
||||
res.send(true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
res.send(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/vincularDispositivo', (req, res) => {
|
||||
const descricao = req.body.descricao;
|
||||
const segredo = req.body.segredo;
|
||||
const iddispositivos = parseInt(req.body.iddispositivos);
|
||||
ConexaoMySQL_GCA.query(`UPDATE dispositivos set
|
||||
descricao = '${descricao}',
|
||||
idclientes = (select idclientes from clientes where segredo = '${segredo}')
|
||||
where iddispositivos = ${iddispositivos};`, function (error, results, fields) {
|
||||
if (!error) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(true);
|
||||
}
|
||||
else {
|
||||
console.log(error);
|
||||
console.log(req.originalUrl + "/ error 500");
|
||||
res.send(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region CLIENTES
|
||||
|
||||
router.post('/insertCliente', (req, res) => {
|
||||
const nome = req.body.nome;
|
||||
const cidade = req.body.cidade;
|
||||
const telefone = req.body.telefone;
|
||||
const email = req.body.email;
|
||||
const cpf = req.body.cpf;
|
||||
ConexaoMySQL_GCA.query(`select * from clientes where cpf = '${cpf}' or email = '${email}';`, function (errorS, resultsS, fieldsS) {
|
||||
if (resultsS.length == 0) {
|
||||
GeraSegredo(function(segredo) {
|
||||
ConexaoMySQL_GCA.query(`insert into clientes (nome, cidade, telefone, email, segredo, cpf)
|
||||
values ('${nome}', '${cidade}', '${telefone}', '${email}', '${segredo}', '${cpf}');`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (!error) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
let Cliente = {
|
||||
nome: nome,
|
||||
email: email,
|
||||
telefone: telefone,
|
||||
Segredo: segredo
|
||||
}
|
||||
EnviarEmail(Cliente, 2);
|
||||
res.redirect(`http://${req.headers.host.split(':')[0]}/cadastro.html?segredo=${segredo}`);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ error 500");
|
||||
res.redirect(`http://${req.headers.host.split(':')[0]}/cadastro.html?erro=0`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
res.redirect(`http://${req.headers.host.split(':')[0]}/cadastro.html?erro=1`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function GeraSegredo(callback) {
|
||||
const caracteresPermitidos = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?_-";
|
||||
let secret = "";
|
||||
ConexaoMySQL_GCA.query(`select segredo from clientes;`, function (error, results, fields) {
|
||||
for (let i = 0; i < 15; i++) {
|
||||
secret += caracteresPermitidos[Math.floor(Math.random() * (caracteresPermitidos.length))];
|
||||
}
|
||||
let Aprovado = true;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
if (results[i]['segredo'] == secret)
|
||||
Aprovado = false;
|
||||
}
|
||||
if (Aprovado)
|
||||
callback(secret);
|
||||
else
|
||||
GeraSegredo(callback);
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/setClienteToken/:segredo/:token', (req, res) => {
|
||||
const segredo = req.params.segredo;
|
||||
const token = req.params.token;
|
||||
ConexaoMySQL_GCA.query(`UPDATE clientes SET
|
||||
token = '${token}'
|
||||
where segredo = '${segredo}';`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (results) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(true);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ success 500");
|
||||
res.send(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/salvarConfigCliente', (req, res) => {
|
||||
const Segredo = req.body.Segredo;
|
||||
const NomeRede = req.body.NomeRede;
|
||||
const SenhaRede = req.body.SenhaRede;
|
||||
const Dispositivo = parseInt(req.body.Dispositivo);
|
||||
ConexaoMySQL_GCA.query(`UPDATE clientes set
|
||||
nomeRede = '${NomeRede}',
|
||||
senhaRede = '${SenhaRede}',
|
||||
indexDispositivo = ${Dispositivo}
|
||||
where segredo = '${Segredo}';`, function (error, results, fields) {
|
||||
if (!error) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(true);
|
||||
}
|
||||
else {
|
||||
console.log(error);
|
||||
console.log(req.originalUrl + "/ error 500");
|
||||
res.send(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region CONFIGURACOES
|
||||
|
||||
router.get('/getConfig', (req, res) => {
|
||||
ConexaoMySQL_GCA.query(`select * from configuracoes;`, function (error, results, fields) {
|
||||
if (error) throw error;
|
||||
if (results) {
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(results[0]);
|
||||
}
|
||||
else {
|
||||
console.log(req.originalUrl + "/ success 500");
|
||||
res.send([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region PUSH NOTIFICATION FIREBASE
|
||||
|
||||
admin.initializeApp({
|
||||
credential: admin.credential.cert(serviceAccount),
|
||||
projectId: "gca-control-bcb9b"
|
||||
});
|
||||
|
||||
function EnviarNotificacao(DadosMensagem, registrationToken) {
|
||||
// This registration token comes from the client FCM SDKs.
|
||||
|
||||
const message = {
|
||||
data: DadosMensagem,
|
||||
token: registrationToken
|
||||
};
|
||||
|
||||
// Send a message to the device corresponding to the provided
|
||||
// registration token.
|
||||
admin.messaging().send(message).then((response) => {
|
||||
// Response is a message ID string.
|
||||
console.log('Successfully sent message:', response);
|
||||
}).catch((error) => {
|
||||
console.log('Error sending message:', error);
|
||||
});
|
||||
}
|
||||
|
||||
router.post('/sendPushNotification', (req, res) => {
|
||||
const titulo = req.body.titulo;
|
||||
const mensagem = req.body.mensagem;
|
||||
const segredo = req.body.segredo;
|
||||
ConexaoMySQL_GCA.query(`SELECT token FROM clientes WHERE segredo = '${segredo}';`, function (error, results, fields) {
|
||||
if (!error) {
|
||||
|
||||
const DadosMensagem = {
|
||||
title: titulo,
|
||||
message: mensagem
|
||||
};
|
||||
EnviarNotificacao(DadosMensagem, results[0]['token']);
|
||||
|
||||
console.log(req.originalUrl + "/ success 200");
|
||||
res.send(true);
|
||||
}
|
||||
else {
|
||||
console.log(error);
|
||||
console.log(req.originalUrl + "/ error 500");
|
||||
res.send(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const formidable = require('formidable');
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getAllNoticias', function (req, res) {
|
||||
ExecuteQuery(`SELECT * FROM noticias;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getNoticiasEn', function (req, res, next) {
|
||||
const sqlQuery = `select
|
||||
idnoticias,
|
||||
titulo,
|
||||
descricao,
|
||||
CASE WHEN habilitado = 1 THEN 'Sim' ELSE 'Não' END AS habilitado,
|
||||
link
|
||||
FROM noticias
|
||||
WHERE habilitado = 1;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getNoticiaByID/:idnoticias', function (req, res, next) {
|
||||
const idnoticias = req.params.idnoticias;
|
||||
const sqlQuery = `SELECT * FROM noticias WHERE idnoticias = ${idnoticias};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertNoticias', function (req, res, next) {
|
||||
const idnoticias = req.body.idnoticias;
|
||||
const titulo = req.body.titulo;
|
||||
const descricao = req.body.descricao;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const link = req.body.link;
|
||||
const sqlQuery = `INSERT INTO noticias (titulo, descricao, habilitado, link)
|
||||
VALUES ('${titulo}', '${descricao}', ${habilitado}, '${link}');`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateNoticias', function (req, res, next) {
|
||||
const idnoticias = req.body.idnoticias;
|
||||
const titulo = req.body.titulo;
|
||||
const descricao = req.body.descricao;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const link = req.body.link;
|
||||
const sqlQuery = `update noticias set
|
||||
titulo = '${titulo}',
|
||||
descricao = '${descricao}',
|
||||
habilitado = ${habilitado},
|
||||
link = '${link}'
|
||||
where idnoticias = ${idnoticias};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteNoticias/:idnoticias', function (req, res, next) {
|
||||
const idnoticias = req.params.idnoticias;
|
||||
const sqlQuery = `DELETE FROM noticias WHERE idnoticias = ${idnoticias};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/copy', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024;
|
||||
form.parse(req, function(err,fields,files){
|
||||
const fs = require('fs');
|
||||
var idnoticias = fields.idnoticias;
|
||||
var pathImagem = files.imagem.path;
|
||||
var dir = '/var/www/html/imagens/noticias/';
|
||||
fs.rename(pathImagem, dir + "noticia_" + idnoticias + ".jpg", function (err) {
|
||||
console.log("arquivo copiado com sucesso");
|
||||
res.send(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getAllLogs', function (req, res) {
|
||||
ExecuteQuery(`select * from vw_oriontard_logs where dataLog > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 3 MONTH);`, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertLog', function (req, res) {
|
||||
const cpf = req.body.cpf;
|
||||
const perfil = req.body.perfil;
|
||||
const latitude = req.body.longitude;
|
||||
const longitude = req.body.latitude;
|
||||
const log = req.body.log;
|
||||
ExecuteQuery(`insert into orionTardProLogs (cpf, perfil, latitude, longitude, log) values (?, ?, ?, ?, ?);`,
|
||||
req, res, [cpf, perfil, latitude, longitude, log]);
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,585 @@
|
|||
require('../connector');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
//#region LOGIN
|
||||
|
||||
router.post('/login', function(req, res) {
|
||||
const usuario = req.body.usuario;
|
||||
const senha = req.body.senha;
|
||||
ExecuteQueryPriorie(`select * from usuarios where usuario = '${usuario}' and senha = '${senha}' and habilitado = 1;`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region USUARIOS
|
||||
|
||||
router.post('/cadastrarUsuario', function(req, res) {
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const iddepartamentos = req.body.iddepartamentos;
|
||||
const nome = req.body.nome;
|
||||
const usuario = req.body.usuario;
|
||||
const senha = req.body.senha;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const email = req.body.email;
|
||||
ExecuteQueryPriorie(`insert into usuarios (iddepartamentos, nome, senha, usuario, habilitado, email) values
|
||||
(${iddepartamentos}, '${nome}', '${senha}', '${usuario}', ${habilitado}, '${email}');`, req, res);
|
||||
});
|
||||
|
||||
router.patch('/atualizarUsuario', function(req, res) {
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const iddepartamentos = parseInt(req.body.iddepartamentos);
|
||||
const nome = req.body.nome;
|
||||
const usuario = req.body.usuario;
|
||||
const senha = req.body.senha;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const email = req.body.email;
|
||||
ExecuteQueryPriorie(`update usuarios set
|
||||
iddepartamentos = ${iddepartamentos},
|
||||
nome = '${nome}',
|
||||
senha = '${senha}',
|
||||
usuario = '${usuario}',
|
||||
habilitado = ${habilitado},
|
||||
email = '${email}'
|
||||
where idusuarios = ${idusuarios};`, req, res);
|
||||
});
|
||||
|
||||
router.delete('/removerUsuario/:idusuarios', function(req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
ExecuteQueryPriorie(`delete from usuarios
|
||||
where idusuarios = ${idusuarios};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllUsuarios', function(req, res) {
|
||||
ExecuteQueryPriorie(`select
|
||||
us.* ,
|
||||
dp.descricao as 'departamento'
|
||||
from usuarios us
|
||||
inner join departamentos dp on dp.iddepartamentos = us.iddepartamentos
|
||||
order by nome asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getUsuariosEnabled', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from usuarios where habilitado = 1;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getUsuario/:idusuarios', function(req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
ExecuteQueryPriorie(`select * from usuarios
|
||||
where idusuarios = ${idusuarios};`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region TAREFAS
|
||||
|
||||
router.post('/cadastrarTarefa', function(req, res) {
|
||||
const idtarefas = parseInt(req.body.idtarefas);
|
||||
const criadapor = parseInt(req.body.criadapor);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const idtopicos = parseInt(req.body.idtopicos);
|
||||
const idstatus = parseInt(req.body.idstatus);
|
||||
const idtipotarefa = parseInt(req.body.idtipotarefa);
|
||||
const previsaoinicio = req.body.previsaoinicio;
|
||||
const iniciadoem = req.body.iniciadoem;
|
||||
const previsaotermino = req.body.previsaotermino;
|
||||
const concluidoem = req.body.concluidoem;
|
||||
const prioridade = parseInt(req.body.prioridade);
|
||||
const observacao = fixApostrofe(req.body.observacao);
|
||||
ExecuteQueryPriorie(`insert into tarefas (criadapor, descricao, idprojetos, idtopicos, idstatus, idtipotarefa, ${(previsaoinicio) ? 'previsaoinicio,' : ''} ${(iniciadoem) ? 'iniciadoem,' : ''} ${(previsaotermino) ? 'previsaotermino,' : ''} ${(concluidoem) ? 'concluidoem,' : ''} prioridade, observacao) values
|
||||
(${criadapor}, '${descricao}', ${idprojetos}, ${idtopicos}, ${idstatus}, ${idtipotarefa}, ${(previsaoinicio) ? "'" + previsaoinicio + "'," : ''} ${(iniciadoem) ? "'" + iniciadoem + "'," : ''} ${(previsaotermino) ? "'" + previsaotermino + "'," : ''} ${(concluidoem) ? "'" + concluidoem + "'," : ''} ${prioridade}, '${observacao}');`, req, res);
|
||||
});
|
||||
|
||||
router.patch('/atualizarTarefa', function(req, res) {
|
||||
const idtarefas = parseInt(req.body.idtarefas);
|
||||
const criadapor = parseInt(req.body.criadapor);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const idtopicos = parseInt(req.body.idtopicos);
|
||||
const idstatus = parseInt(req.body.idstatus);
|
||||
const idtipotarefa = parseInt(req.body.idtipotarefa);
|
||||
const previsaoinicio = req.body.previsaoinicio;
|
||||
const iniciadoem = req.body.iniciadoem;
|
||||
const previsaotermino = req.body.previsaotermino;
|
||||
const concluidoem = req.body.concluidoem;
|
||||
const prioridade = parseInt(req.body.prioridade);
|
||||
const observacao = fixApostrofe(req.body.observacao);
|
||||
ExecuteQueryPriorie(`update tarefas set
|
||||
criadapor = ${criadapor},
|
||||
descricao = '${descricao}',
|
||||
idprojetos = ${idprojetos},
|
||||
idtopicos = ${idtopicos},
|
||||
idstatus = ${idstatus},
|
||||
idtipotarefa = ${idtipotarefa},
|
||||
${(previsaoinicio) ? "previsaoinicio = '" + previsaoinicio + "',": ''}
|
||||
${(iniciadoem) ? "iniciadoem = '" + iniciadoem + "',": ''}
|
||||
${(previsaotermino) ? "previsaotermino = '" + previsaotermino + "',": ''}
|
||||
${(concluidoem) ? "concluidoem = '" + concluidoem + "',": ''}
|
||||
prioridade = ${prioridade},
|
||||
observacao = '${observacao}'
|
||||
where idtarefas = ${idtarefas};`, req, res, function(Status) {
|
||||
if (Status == 200 && idstatus == 4) {
|
||||
const SQLDados = `select
|
||||
A.*,
|
||||
us.nome as 'Gerente',
|
||||
us.email as 'EmailGerente',
|
||||
us2.nome
|
||||
from (select distinct
|
||||
ta.idtarefas,
|
||||
date_format(ta.concluidoem, '%d/%m/%Y') as 'ConcluidaEm',
|
||||
dm.idusuarios,
|
||||
pr.descricao as 'Projeto',
|
||||
tp.descricao as 'Topico',
|
||||
ta.descricao as 'Tarefa'
|
||||
from tarefas ta
|
||||
inner join projetos pr on pr.idprojetos = ta.idprojetos
|
||||
inner join topicos tp on tp.idtopicos = ta.idtopicos
|
||||
inner join departamentosmembros dm on dm.iddepartamentos = pr.iddepartamentos
|
||||
inner join usuarios us on us.iddepartamentos = dm.iddepartamentos and dm.gestor = 1
|
||||
where ta.idtarefas = ${idtarefas}) A
|
||||
inner join usuarios us on us.idusuarios = A.idusuarios
|
||||
inner join projetosmembros pm on pm.idtarefas = A.idtarefas
|
||||
inner join usuarios us2 on us2.idusuarios = pm.idusuarios;`;
|
||||
connection.query(SQLDados, function(error, Dados, fields) {
|
||||
if (Dados && Dados[0]['EmailGerente'] != "" && Dados[0]['EmailGerente'] != null) {
|
||||
let Membros = "";
|
||||
for (let i = 0; i < Dados.length; i++) {
|
||||
if (i > 0)
|
||||
Membros += ", ";
|
||||
Membros += Dados[i]['nome'];
|
||||
}
|
||||
const Mensagem = `Olá ${Dados[0]['Gerente']}!<br>
|
||||
Uma tarefa do projeto ${Dados[0]['Projeto']} foi marcada com concluída:<br><br>
|
||||
Projeto: ${Dados[0]['Projeto']}<br>
|
||||
Tópico: ${Dados[0]['Topico']}<br>
|
||||
Tarefa: ${Dados[0]['Tarefa']}<br>
|
||||
Data de Conclusão: ${Dados[0]['ConcluidaEm']}<br>
|
||||
Membros: ${Membros}<br><br>
|
||||
Acesse o sistema para conferir!<br><br>
|
||||
<a href="http://priorie.mooo.com/login">Clique aqui para acessar o sistema</a>`;
|
||||
EnviarEmail(Mensagem, "Tarefa Concluída", Dados[0]['EmailGerente']);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/removerTarefa/:idtarefas', function(req, res) {
|
||||
const idtarefas = parseInt(req.params.idtarefas);
|
||||
ExecuteQueryPriorie(`delete from tarefas
|
||||
where idtarefas = ${idtarefas};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllTarefas', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from tarefas;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTarefa/:idtarefas', function(req, res) {
|
||||
const idtarefas = parseInt(req.params.idtarefas);
|
||||
ExecuteQueryPriorie(`select * from tarefas
|
||||
where idtarefas = ${idtarefas};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTarefasUsuario/:idusuarios/:iddepartamentos/:IdsStatus/:idprojetos/:idtopicos', function(req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const iddepartamentos = parseInt(req.params.iddepartamentos);
|
||||
const idprojetos = parseInt(req.params.idprojetos);
|
||||
const idtopicos = parseInt(req.params.idtopicos);
|
||||
const IdsStatus = req.params.IdsStatus;
|
||||
|
||||
let Condicao = `pr.iddepartamentos = ${iddepartamentos} /*${(idusuarios == 0) ? 'or' : 'and'}*/and ((`;
|
||||
if (idusuarios == 0)
|
||||
Condicao += `pm.idusuarios in (select distinct dm.idusuarios from departamentosmembros dm where dm.iddepartamentos = ${iddepartamentos})`;
|
||||
else
|
||||
Condicao += "pm.idusuarios = " + idusuarios;
|
||||
Condicao += " and st.idstatus in " + IdsStatus;
|
||||
if (idprojetos > 0)
|
||||
Condicao += " and ta.idprojetos = " + idprojetos;
|
||||
if (idtopicos > 0)
|
||||
Condicao += " and ta.idtopicos = " + idtopicos;
|
||||
if (IdsStatus.includes("100")) {
|
||||
//Condicao += `) or (0 = (select count(*) from projetosmembros pm1 where pm1.idtarefas = ta.idtarefas)${(idprojetos > 0) ? ' and ta.idprojetos = ' + idprojetos : ''}))`;
|
||||
Condicao += `) or (0 = (select count(*) from projetosmembros pm1 inner join tarefas ta1 on ta1.idtarefas = pm1.idtarefas inner join projetos pr1 on pr1.idprojetos = ta1.idprojetos where pm1.idtarefas = ta.idtarefas)${(idprojetos > 0) ? ' and ta.idprojetos = ' + idprojetos : ''}))`;
|
||||
}
|
||||
else
|
||||
Condicao += "))";
|
||||
let sqlQuery = `select
|
||||
A.*,
|
||||
GROUP_CONCAT(us.nome SEPARATOR ', ') as 'Membros',
|
||||
GROUP_CONCAT(us.idusuarios SEPARATOR ',') as 'MembrosIDs'
|
||||
from (
|
||||
SELECT distinct
|
||||
ta.idtarefas,
|
||||
ta.descricao,
|
||||
ta.criadapor,
|
||||
(select us2.nome from usuarios us2 where us2.idusuarios = ta.criadapor) as 'criadapor_d',
|
||||
ta.idprojetos,
|
||||
pr.descricao as 'projeto',
|
||||
pr.iddepartamentos,
|
||||
ta.idtopicos,
|
||||
tp.descricao as 'topico',
|
||||
ta.idstatus,
|
||||
ta.idstatus as 'idstatus_c',
|
||||
st.descricao as 'status',
|
||||
st.prioridade as 'prioridade_s',
|
||||
st.color,
|
||||
st.background,
|
||||
ta.idtipotarefa,
|
||||
tt.descricao as 'tipotarefa',
|
||||
ta.previsaoinicio,
|
||||
ta.iniciadoem,
|
||||
ta.previsaotermino,
|
||||
ta.concluidoem,
|
||||
ta.prioridade,
|
||||
pd.descricao as 'prioridade_d',
|
||||
ta.observacao,
|
||||
date_format(ta.insert_date, '%d/%m/%Y %H:%i') as 'insert_date',
|
||||
(select count(*) from projetosmembros pm2 where pm2.idtarefas = ta.idtarefas) as 'QtdMembros'
|
||||
FROM tarefas ta
|
||||
inner join projetos pr on pr.idprojetos = ta.idprojetos
|
||||
inner join topicos tp on tp.idtopicos = ta.idtopicos
|
||||
inner join status st on st.idstatus = ta.idstatus
|
||||
inner join tipotarefa tt on tt.idtipotarefa = ta.idtipotarefa
|
||||
left join projetosmembros pm on pm.idtarefas = ta.idtarefas
|
||||
inner join prioridades pd on pd.prioridade = ta.prioridade
|
||||
where ${Condicao}) A
|
||||
left join projetosmembros pm on pm.idtarefas = A.idtarefas
|
||||
left join usuarios us on us.idusuarios = pm.idusuarios
|
||||
group by A.idtarefas
|
||||
order by A.prioridade_s desc, A.prioridade asc, A.idtipotarefa asc;`;
|
||||
//console.log(sqlQuery);
|
||||
ExecuteQueryPriorie(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getMembrosTarefa/:idtarefas', function(req, res) {
|
||||
const idtarefas = parseInt(req.params.idtarefas);
|
||||
ExecuteQueryPriorie(`SELECT
|
||||
pm.idprojetosmembros,
|
||||
pm.idusuarios,
|
||||
pm.idtarefas,
|
||||
us.nome
|
||||
FROM projetosmembros pm
|
||||
left join usuarios us on us.idusuarios = pm.idusuarios
|
||||
where pm.idtarefas = ${idtarefas};`, req, res);
|
||||
});
|
||||
|
||||
router.delete('/removerMembroTarefa/:idtarefas/:idusuarios', function(req, res) {
|
||||
const idtarefas = parseInt(req.params.idtarefas);
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
ExecuteQueryPriorie(`delete from projetosmembros
|
||||
where idtarefas = ${idtarefas} and idusuarios = ${idusuarios};`, req, res);
|
||||
});
|
||||
|
||||
router.post('/cadastrarTarefaMembros', function(req, res) {
|
||||
const idtarefas = parseInt(req.body.idtarefas);
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
ExecuteQueryPriorie(`insert into projetosmembros (idusuarios, idtarefas)
|
||||
values (${idusuarios}, ${idtarefas});`, req, res, function(Status, idprojetosmembros) {
|
||||
if (Status != 200) {
|
||||
return;
|
||||
}
|
||||
const SQLDados = `select
|
||||
pm.idusuarios,
|
||||
us.nome,
|
||||
us.email,
|
||||
pr.descricao as 'Projeto',
|
||||
tp.descricao as 'Topico',
|
||||
ta.descricao as 'Tarefa',
|
||||
date_format(ta.previsaoinicio, '%d/%m/%Y') as 'Inicio',
|
||||
date_format(ta.previsaotermino, '%d/%m/%Y') as 'Previsao',
|
||||
pd.descricao as 'Prioridade',
|
||||
dp.descricao as 'Departamento'
|
||||
from projetosmembros pm
|
||||
inner join tarefas ta on ta.idtarefas = pm.idtarefas
|
||||
inner join projetos pr on pr.idprojetos = ta.idprojetos
|
||||
inner join topicos tp on tp.idtopicos = ta.idtopicos
|
||||
inner join prioridades pd on pd.prioridade = ta.prioridade
|
||||
inner join usuarios us on us.idusuarios = pm.idusuarios
|
||||
inner join departamentos dp on dp.iddepartamentos = pr.iddepartamentos
|
||||
where idprojetosmembros = ${idprojetosmembros};`;
|
||||
connection.query(SQLDados, function(error, Dados, fields) {
|
||||
if (Dados && Dados[0]['email'] != "" && Dados[0]['email'] != null) {
|
||||
const Mensagem = `Olá ${Dados[0]['nome']}!<br>
|
||||
Você tem uma nova tarefa atribuída no sistema Priorie para o departamento ${Dados[0]['Departamento']}:<br><br>
|
||||
Projeto: ${Dados[0]['Projeto']}<br>
|
||||
Tópico: ${Dados[0]['Topico']}<br>
|
||||
Tarefa: ${Dados[0]['Tarefa']}<br>
|
||||
Prioridade: ${Dados[0]['Prioridade']}<br>
|
||||
Previsão de início: ${Dados[0]['Inicio']}<br>
|
||||
Previsão de término: ${Dados[0]['Previsao']}<br><br>
|
||||
Acesse o sistema para conferir!<br><br>
|
||||
<a href="http://priorie.mooo.com/login">Clique aqui para acessar o sistema</a>`;
|
||||
EnviarEmail(Mensagem, "Nova Tarefa Atribuída", Dados[0]['email']);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getTarefasPorMembro/:IdsStatus/:idprojetos/:idtopicos', function(req, res) {
|
||||
const IdsStatus = req.params.IdsStatus;
|
||||
const idprojetos = parseInt(req.params.idprojetos);
|
||||
const idtopicos = parseInt(req.params.idtopicos);
|
||||
let Condicao = "";
|
||||
if (idprojetos > 0)
|
||||
Condicao += " and ta.idprojetos = " + idprojetos;
|
||||
if (idtopicos > 0)
|
||||
Condicao += " and ta.idtopicos = " + idtopicos;
|
||||
ExecuteQueryPriorie(`SELECT
|
||||
pm.idusuarios,
|
||||
pr.iddepartamentos,
|
||||
ta.idstatus,
|
||||
count(*) as 'QtdeTarefas'
|
||||
FROM projetosmembros pm
|
||||
inner join tarefas ta on ta.idtarefas = pm.idtarefas
|
||||
inner join projetos pr on pr.idprojetos = ta.idprojetos
|
||||
where ta.idstatus in ${IdsStatus}${Condicao}
|
||||
group by pr.iddepartamentos, pm.idusuarios, ta.idstatus;`, req, res);
|
||||
});
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region STATUS
|
||||
|
||||
router.get('/getAllStatus', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from status;`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region DEPARTAMENTOS
|
||||
|
||||
router.get('/getAllDepartamentos', function(req, res) {
|
||||
ExecuteQueryPriorie(`SELECT * from departamentos order by descricao asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getDepartamento/:iddepartamentos', function(req, res) {
|
||||
const iddepartamentos = parseInt(req.params.iddepartamentos);
|
||||
ExecuteQueryPriorie(`SELECT * from departamentos where iddepartamentos = ${iddepartamentos} order by descricao asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getDepartamentosMembro/:idusuarios', function(req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
ExecuteQueryPriorie(`select * from departamentosmembros where idusuarios = ${idusuarios};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getDepMembroDetalhe/:idusuarios', function(req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
ExecuteQueryPriorie(`SELECT
|
||||
dm.iddepartamentosmembros,
|
||||
dm.idusuarios,
|
||||
us.nome,
|
||||
us.iddepartamentos as 'iddepartamentos_u',
|
||||
dm.iddepartamentos,
|
||||
dp.descricao,
|
||||
dm.gestor,
|
||||
dm.permitecadastro
|
||||
FROM departamentosmembros dm
|
||||
inner join usuarios us on us.idusuarios = dm.idusuarios
|
||||
inner join departamentos dp on dp.iddepartamentos = dm.iddepartamentos
|
||||
where dm.idusuarios = ${idusuarios}
|
||||
order by us.nome asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getMemborsDepartamento/:iddepartamentos', function(req, res) {
|
||||
const iddepartamentos = parseInt(req.params.iddepartamentos);
|
||||
ExecuteQueryPriorie(`SELECT
|
||||
dm.iddepartamentosmembros,
|
||||
dm.idusuarios,
|
||||
us.nome,
|
||||
us.iddepartamentos as 'iddepartamentos_u',
|
||||
dm.iddepartamentos,
|
||||
dp.descricao,
|
||||
dm.gestor,
|
||||
dm.permitecadastro
|
||||
FROM departamentosmembros dm
|
||||
inner join usuarios us on us.idusuarios = dm.idusuarios
|
||||
inner join departamentos dp on dp.iddepartamentos = dm.iddepartamentos
|
||||
where dm.iddepartamentos = ${iddepartamentos}
|
||||
order by us.nome asc;`, req, res);
|
||||
});
|
||||
|
||||
|
||||
router.post('/cadastrarDepMembro', function(req, res) {
|
||||
const iddepartamentosmembros = parseInt(req.body.iddepartamentosmembros);
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const iddepartamentos = parseInt(req.body.iddepartamentos);
|
||||
const gestor = req.body.gestor ? 1 : 0;
|
||||
const permitecadastro = req.body.permitecadastro ? 1 : 0;
|
||||
ExecuteQueryPriorie(`insert into departamentosmembros (idusuarios, iddepartamentos, gestor, permitecadastro)
|
||||
values (${idusuarios}, ${iddepartamentos}, ${gestor}, ${permitecadastro});`, req, res);
|
||||
});
|
||||
|
||||
router.patch('/atualizarDepMembro', function(req, res) {
|
||||
const iddepartamentosmembros = parseInt(req.body.iddepartamentosmembros);
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const iddepartamentos = parseInt(req.body.iddepartamentos);
|
||||
const gestor = req.body.gestor ? 1 : 0;
|
||||
const permitecadastro = req.body.permitecadastro ? 1 : 0;
|
||||
ExecuteQueryPriorie(`update departamentosmembros set
|
||||
idusuarios = ${idusuarios},
|
||||
iddepartamentos = ${iddepartamentos},
|
||||
gestpr = ${gestor},
|
||||
permitecadastro = ${permitecadastro}
|
||||
where idtopicos = ${idtopicos};`, req, res);
|
||||
});
|
||||
|
||||
router.delete('/removerDepMembro/:iddepartamentosmembros', function(req, res) {
|
||||
const iddepartamentosmembros = parseInt(req.params.iddepartamentosmembros);
|
||||
ExecuteQueryPriorie(`delete from departamentosmembros
|
||||
where iddepartamentosmembros = ${iddepartamentosmembros};`, req, res);
|
||||
});
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region PROJETOS
|
||||
|
||||
router.post('/cadastrarProjeto', function(req, res) {
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const iddepartamentos = parseInt(req.body.iddepartamentos);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
ExecuteQueryPriorie(`insert into projetos (iddepartamentos, descricao) values
|
||||
(${iddepartamentos}, '${descricao}');`, req, res);
|
||||
});
|
||||
|
||||
router.patch('/atualizarProjeto', function(req, res) {
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const iddepartamentos = parseInt(req.body.iddepartamentos);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
ExecuteQueryPriorie(`update projetos set
|
||||
iddepartamentos = ${iddepartamentos},
|
||||
descricao = '${descricao}'
|
||||
where idprojetos = ${idprojetos};`, req, res);
|
||||
});
|
||||
|
||||
router.delete('/removerProjeto/:idprojetos', function(req, res) {
|
||||
const idprojetos = parseInt(req.params.idprojetos);
|
||||
ExecuteQueryPriorie(`delete from projetos
|
||||
where idprojetos = ${idprojetos};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllProjetos', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from projetos;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getProjetosDepartamento/:iddepartamentos', function(req, res) {
|
||||
const iddepartamentos = parseInt(req.params.iddepartamentos);
|
||||
ExecuteQueryPriorie(`select * from projetos where iddepartamentos = ${iddepartamentos} order by descricao asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllTiposTarefas', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from tipotarefa;`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region TOPICOS
|
||||
|
||||
router.post('/cadastrarTopico', function(req, res) {
|
||||
const idtopicos = parseInt(req.body.idtopicos);
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
ExecuteQueryPriorie(`insert into topicos (idprojetos, descricao) values
|
||||
(${idprojetos}, '${descricao}');`, req, res);
|
||||
});
|
||||
|
||||
router.patch('/atualizarTopico', function(req, res) {
|
||||
const idtopicos = parseInt(req.body.idtopicos);
|
||||
const idprojetos = parseInt(req.body.idprojetos);
|
||||
const descricao = fixApostrofe(req.body.descricao);
|
||||
ExecuteQueryPriorie(`update topicos set
|
||||
idprojetos = ${idprojetos},
|
||||
descricao = '${descricao}'
|
||||
where idtopicos = ${idtopicos};`, req, res);
|
||||
});
|
||||
|
||||
router.delete('/removerTopico/:idtopicos', function(req, res) {
|
||||
const idtopicos = parseInt(req.params.idtopicos);
|
||||
ExecuteQueryPriorie(`delete from topicos
|
||||
where idtopicos = ${idtopicos};`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllTopicos', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from topicos;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTopico/:idtopicos', function(req, res) {
|
||||
const idtopicos = parseInt(req.params.idtopicos);
|
||||
ExecuteQueryPriorie(`select * from topicos where idtopicos = ${idtopicos} order by descricao asc;`, req, res);
|
||||
});
|
||||
|
||||
router.get('/getAllTopicosTarefa/:idprojetos', function(req, res) {
|
||||
const idprojetos = parseInt(req.params.idprojetos);
|
||||
ExecuteQueryPriorie(`select * from topicos where idprojetos = ${idprojetos} order by descricao asc;`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region PRIORIDADES
|
||||
|
||||
router.get('/getAllPrioridades', function(req, res) {
|
||||
ExecuteQueryPriorie(`select * from prioridades;`, req, res);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region ENVIO DE NOTIFICACOES
|
||||
|
||||
const nodemailer = require('nodemailer');
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
user: "zendioninc.contato@gmail.com",
|
||||
pass: "gmailzendioninc",
|
||||
}
|
||||
});
|
||||
/*var transporter = nodemailer.createTransport({
|
||||
host: "email-ssl.com.br",
|
||||
port: 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: 'staff@myrobot.com.br',
|
||||
pass: 'stAff66**'
|
||||
}
|
||||
});*/
|
||||
|
||||
function EnviarEmail(Mensagem, Assunto, Email) {
|
||||
var mailOptions = {
|
||||
from: '"Zendion, INC" <zendioninc.contato@gmail.com>',
|
||||
to: Email,
|
||||
subject: Assunto,
|
||||
html: Mensagem
|
||||
};
|
||||
transporter.sendMail(mailOptions, function (error, info) {
|
||||
if (error) {
|
||||
console.log("Erro ao enviar e-mail para: " + mailOptions.to);
|
||||
console.log(error);
|
||||
}
|
||||
else {
|
||||
console.log('Email enviado com sucesso para: ' + mailOptions.to + ' - ' + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region FUNCOES
|
||||
|
||||
function fixApostrofe(content) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
content = content.replace("'", ''');
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const formidable = require('formidable');
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getSistemas', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM sistemas order by nome asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSistemasEn', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM sistemas WHERE habilitado = 1 order by nome asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSistemaByID/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `SELECT * FROM sistemas WHERE idsistemas = ${idsistemas};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSistemaByIDLista/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `SELECT
|
||||
s.*,
|
||||
p.descricao as plataforma,
|
||||
t.descricao as tiposdesistema,
|
||||
l.descricao as tiposlicenca
|
||||
FROM sistemas s
|
||||
INNER JOIN plataformas p ON s.idplataformas = p.idplataformas
|
||||
INNER JOIN tiposdesistema t ON t.idtiposdesistema = s.idtiposdesistema
|
||||
INNER JOIN tiposlicenca l ON s.idtiposlicenca = l.idtiposlicenca
|
||||
WHERE idsistemas = ${idsistemas}
|
||||
order by s.nome asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSistemaVersao/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `SELECT versaoatual as VersaoAtual, nome_install as NomeInstall FROM sistemas WHERE idsistemas = ${idsistemas};`;
|
||||
//ExecuteQuery(sqlQuery, req, res);
|
||||
mysqlConnection.query(sqlQuery, [], function (error, results, fields) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${(error) ? ' 500 error' : ' 200 success'}`);
|
||||
res.send(results[0])
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getTiposdesistema', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM tiposdesistema order by descricao asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTiposdesistemaByID/:idtiposdesistema', function (req, res) {
|
||||
const idtiposdesistema = parseInt(req.params.idtiposdesistema);
|
||||
const sqlQuery = `SELECT * FROM tiposdesistema WHERE idtiposdesistema = ${idtiposdesistema};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTiposdelicenca', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM tiposlicenca order by descricao asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTiposdelicencaByID/:idtiposlicenca', function (req, res) {
|
||||
const idtiposlicenca = parseInt(req.params.idtiposlicenca);
|
||||
const sqlQuery = `SELECT * FROM tiposlicenca WHERE idtiposlicenca = ${idtiposlicenca};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getPlataformas', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM plataformas order by descricao asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getPlataformaByID/:idplataformas', function (req, res) {
|
||||
let idplataformas = parseInt(req.params.idplataformas);
|
||||
const sqlQuery = `SELECT * FROM plataformas WHERE idplataformas = ${idplataformas};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getDetalhesByID/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `SELECT * FROM sistemasdetalhes WHERE idsistemas = ${idsistemas} order by ordem asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getDetalhesByIDEn/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `SELECT * FROM sistemasdetalhes WHERE idsistemas = ${idsistemas} AND habilitado = 1 order by ordem asc;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertSistemas', function (req, res) {
|
||||
const idsistemas = req.body.idsistemas;
|
||||
const nome = req.body.nome;
|
||||
const descricao = req.body.descricao;
|
||||
const versaoatual = req.body.versaoatual;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const idtiposdesistema = req.body.idtiposdesistema;
|
||||
const idplataformas = req.body.idplataformas;
|
||||
const nome_install = req.body.nome_install;
|
||||
const notasdeatualizacao = req.body.notasdeatualizacao;
|
||||
const idtiposlicenca = req.body.idtiposlicenca;
|
||||
const sqlQuery = `INSERT INTO sistemas (nome, descricao, versaoatual, habilitado, downloads, idtiposdesistema, idplataformas, nome_install, notasdeatualizacao, idtiposlicenca)
|
||||
VALUES ('${nome}', '${descricao}', '${versaoatual}', ${habilitado}, 0, ${idtiposdesistema}, ${idplataformas}, '${nome_install}', '${notasdeatualizacao}', ${idtiposlicenca});`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateSistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.body.idsistemas);
|
||||
const nome = req.body.nome;
|
||||
const descricao = req.body.descricao;
|
||||
const versaoatual = req.body.versaoatual;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const idtiposdesistema = req.body.idtiposdesistema;
|
||||
const idplataformas = req.body.idplataformas;
|
||||
const nome_install = req.body.nome_install;
|
||||
const notasdeatualizacao = req.body.notasdeatualizacao;
|
||||
const idtiposlicenca = req.body.idtiposlicenca;
|
||||
const sqlQuery = `UPDATE sistemas SET
|
||||
nome = '${nome}',
|
||||
descricao = '${descricao}',
|
||||
versaoatual = '${versaoatual}',
|
||||
habilitado = ${habilitado},
|
||||
idtiposdesistema = ${idtiposdesistema},
|
||||
idplataformas = ${idplataformas},
|
||||
nome_install = '${nome_install}',
|
||||
notasdeatualizacao = '${notasdeatualizacao}',
|
||||
idtiposlicenca = ${idtiposlicenca}
|
||||
WHERE idsistemas = ${idsistemas};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteSistemas/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const sqlQuery = `DELETE FROM sistemas WHERE idsistemas = ${idsistemas};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteSistemaUsuario/:idsistemas/:idusuarios', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `DELETE FROM sistemasusuario WHERE idsistemas = ${idsistemas} AND idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/downloadSistema', function (req, res) {
|
||||
const idsistemas = parseInt(req.body.idsistemas);
|
||||
const sqlQuery = `UPDATE sistemas SET
|
||||
downloads = downloads + 1
|
||||
WHERE idsistemas = ${idsistemas};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertSistemaUsuario', function (req, res) {
|
||||
const idsistemas = parseInt(req.body.idsistemas);
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const sqlQuery = `INSERT INTO sistemasusuario (idsistemas, idusuarios, data_download)
|
||||
SELECT DISTINCT ${idsistemas} AS idsistemas, ${idusuarios} AS idusuarios, NOW() AS data_download
|
||||
FROM sistemasusuario su WHERE (SELECT COUNT(*) qtdDown FROM sistemasusuario WHERE idsistemas = ${idsistemas} AND idusuarios = ${idusuarios}) = 0;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/copy', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024;
|
||||
form.parse(req, function(err,fields,files){
|
||||
const fs = require('fs');
|
||||
var nome_install = fields.nome;
|
||||
var versaoatual = fields.versaoatual;
|
||||
var idsistemas = fields.idsistemas;
|
||||
var pathArquivo = "";
|
||||
var pathIcone = "";
|
||||
|
||||
try {
|
||||
pathArquivo = files.arquivo.path;
|
||||
}
|
||||
catch(e) {
|
||||
console.log("não copia arquivo");
|
||||
}
|
||||
try {
|
||||
pathIcone = files.icone.path;
|
||||
}
|
||||
catch(e) {
|
||||
console.log("não copia icone");
|
||||
}
|
||||
var dir = '/var/www/html/sistemas/';
|
||||
if (!fs.existsSync(dir + idsistemas + "/")) {
|
||||
fs.mkdirSync(dir + idsistemas + "/");
|
||||
fs.mkdirSync(dir + idsistemas + "/detalhes/");
|
||||
fs.mkdirSync(dir + idsistemas + "/versoes/");
|
||||
fs.mkdirSync(dir + idsistemas + "/backups/");
|
||||
fs.mkdirSync(dir + idsistemas + "/versoes/" + versaoatual + "/");
|
||||
}
|
||||
else if (!fs.existsSync(dir + idsistemas + "/versoes/" + versaoatual + "/")) {
|
||||
fs.mkdirSync(dir + idsistemas + "/versoes/" + versaoatual + "/");
|
||||
}
|
||||
if (pathArquivo != "") {
|
||||
fs.rename(pathArquivo, dir + idsistemas + "/versoes/" + versaoatual + "/" + nome_install, function (err) {
|
||||
console.log("arquivo copiado com sucesso");
|
||||
});
|
||||
}
|
||||
if (pathIcone != "") {
|
||||
fs.rename(pathIcone, dir + idsistemas + "/icone.png", function (err) {
|
||||
console.log("icone copiado com sucesso!");
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
res.send(true);
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/getChavesSistema/:idsistemas/:idusuarios', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `SELECT * FROM chaves
|
||||
WHERE idsistemas = ${idsistemas} AND idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getChavesSistemaLista/:idsistemas/:idusuarios', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `SELECT
|
||||
idchaves,
|
||||
licenca as Chave,
|
||||
data_criacao as DataCriacao,
|
||||
data_validade as DataValidade,
|
||||
CASE WHEN data_validade < NOW() THEN 'Expirada' ELSE 'Válida' END AS Status,
|
||||
CASE WHEN usada = 0 THEN 'Não' ELSE 'Sim' END AS Ativada
|
||||
FROM chaves
|
||||
WHERE idsistemas = ${idsistemas} AND idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertChave', function (req, res) {
|
||||
let licenca = req.body.licenca;
|
||||
let idusuarios = req.body.idusuarios;
|
||||
let idsistemas = req.body.idsistemas;
|
||||
let data_validade = req.body.data_validade;
|
||||
let newdate = data_validade.toString();
|
||||
newdate = newdate.substring(0, newdate.length - 1);
|
||||
const sqlQuery = `INSERT INTO chaves (licenca, data_criacao, data_validade, idusuarios, usada, idsistemas)
|
||||
VALUES ('${licenca}', NOW(), '${newdate}', ${idusuarios}, 0, ${idsistemas});`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertDetalhe', function (req, res) {
|
||||
const idsistemasdetalhes = req.body.idsistemasdetalhes;
|
||||
const idsistemas = req.body.idsistemas;
|
||||
const descricao = req.body.descricao;
|
||||
const ordem = parseInt(req.body.ordem);
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const sqlQuery = `INSERT INTO sistemasdetalhes (idsistemas, descricao, ordem, habilitado)
|
||||
VALUES (${idsistemas}, '${descricao}', ${ordem}, ${habilitado});`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateDetalhe', function (req, res) {
|
||||
const idsistemasdetalhes = req.body.idsistemasdetalhes;
|
||||
const idsistemas = req.body.idsistemas;
|
||||
const descricao = req.body.descricao;
|
||||
const ordem = parseInt(req.body.ordem);
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const sqlQuery = `UPDATE sistemasdetalhes SET
|
||||
idsistemas = ${idsistemas},
|
||||
descricao = '${descricao}',
|
||||
ordem = ${ordem},
|
||||
habilitado = ${habilitado}
|
||||
WHERE idsistemasdetalhes = ${idsistemasdetalhes};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteDetalhe/:idsistemasdetalhes/:idsistemas/:index', function (req, res) {
|
||||
const idsistemasdetalhes = parseInt(req.params.idsistemasdetalhes);
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const index = parseInt(req.params.index);
|
||||
const sqlQuery = `DELETE FROM sistemasdetalhes WHERE idsistemasdetalhes = ${idsistemasdetalhes};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
var Path = '/var/www/html/sistemas/' + idsistemas + "/detalhes/sistema_" + index + ".jpg";
|
||||
const fs = require('fs');
|
||||
if (fs.existsSync(Path)) {
|
||||
fs.unlinkSync(Path);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/copyDetalhe', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024;
|
||||
form.parse(req, function(err,fields,files) {
|
||||
const fs = require('fs');
|
||||
var nome = fields.nome;
|
||||
var idsistemas = fields.idsistemas;
|
||||
var pathArquivo = files.arquivo.path;
|
||||
var dir = '/var/www/html/sistemas/' + idsistemas + "/detalhes/";
|
||||
fs.rename(pathArquivo, dir + nome, function (err) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
else
|
||||
console.log("arquivo copiado com sucesso");
|
||||
res.send(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/atualizarListaDetalhes/:idsistemas', (req, res) => {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const fs = require('fs');
|
||||
var dir = '/var/www/html/sistemas/' + idsistemas + "/detalhes/";
|
||||
let i = 0;
|
||||
fs.readdirSync(dir).forEach(file => {
|
||||
fs.renameSync(dir + file, dir + file.split('_')[0] + "_" + i + '.jpg');
|
||||
i++;
|
||||
});
|
||||
res.send(true);
|
||||
});
|
||||
|
||||
router.get('/getSistemaVersoes/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const fs = require('fs');
|
||||
const dir = '/var/www/html/sistemas/' + idsistemas + "/versoes/";
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
const versoes = fs.readdirSync(dir);
|
||||
var lista = [];
|
||||
versoes.forEach(versao => {
|
||||
const file = fs.readdirSync(dir + versao)[0];
|
||||
const arquivo = dir + versao + "/" + file;
|
||||
const stats = fs.statSync(arquivo);
|
||||
lista.push(arquivo + "¬" + stats.birthtime);
|
||||
});
|
||||
res.send(lista);
|
||||
});
|
||||
|
||||
router.get('/getSistemaDownloads/:idsistemas', function (req, res) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const fs = require('fs');
|
||||
const dir = '/var/www/html/sistemas/' + idsistemas + "/downloads/";
|
||||
if (!fs.existsSync(dir))
|
||||
fs.mkdirSync(dir);
|
||||
const downloads = fs.readdirSync(dir);
|
||||
var lista = [];
|
||||
downloads.forEach(download => {
|
||||
var stats = fs.statSync(dir + download);
|
||||
lista.push(dir + download + "¬" + stats.birthtime);
|
||||
});
|
||||
res.send(lista);
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const formidable = require('formidable');
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/getAllSlides', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM slides;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSlidesEn', function (req, res) {
|
||||
const sqlQuery = `select
|
||||
idslides,
|
||||
descricao,
|
||||
CASE WHEN habilitado = 1 THEN 'Sim' ELSE 'Não' END AS habilitado,
|
||||
link
|
||||
FROM slides
|
||||
WHERE habilitado = 1;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSlideByID/:idslides', function (req, res) {
|
||||
const idslides = parseInt(req.params.idslides);
|
||||
const sqlQuery = `SELECT * FROM slides WHERE idslides = ${idslides};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertSlides', function (req, res) {
|
||||
const idslides = req.body.idslides;
|
||||
const descricao = req.body.descricao;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const link = req.body.link;
|
||||
const sqlQuery = `INSERT INTO slides (descricao, habilitado, link) VALUES ('${descricao}', ${habilitado}, '${link}');`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateSlides', function (req, res) {
|
||||
const idslides = parseInt(req.body.idslides);
|
||||
const descricao = req.body.descricao;
|
||||
const habilitado = req.body.habilitado ? 1 : 0;
|
||||
const link = req.body.link;
|
||||
const sqlQuery = `UPDATE slides SET
|
||||
descricao = '${descricao}',
|
||||
habilitado = ${habilitado},
|
||||
link = '${link}'
|
||||
WHERE idslides = ${idslides};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteSlides/:idslides', function (req, res) {
|
||||
const idslides = parseInt(req.params.idslides);
|
||||
const sqlQuery = `DELETE FROM slides WHERE idslides = ${idslides};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/copy', (req, res) => {
|
||||
let form = new formidable.IncomingForm();
|
||||
form.maxFileSize = 600 * 1024 * 1024;
|
||||
form.parse(req, function(err,fields,files){
|
||||
const fs = require('fs');
|
||||
var idslides = fields.idslides;
|
||||
var pathImagem = files.imagem.path;
|
||||
var dir = '/var/www/html/imagens/slides/';
|
||||
fs.rename(pathImagem, dir + "slide_" + idslides + ".jpg", function (err) {
|
||||
console.log("arquivo copiado com sucesso");
|
||||
res.send(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
var routes = function () {
|
||||
|
||||
router.get('/ativarUsuario/:idusuarios', function (req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
|
||||
if (!idusuarios || isNaN(idusuarios)) {
|
||||
return res.status(400).send(RenderPaginaAtivacao({
|
||||
sucesso: false,
|
||||
titulo: 'Link inválido',
|
||||
mensagem: 'O link de ativação utilizado é inválido ou está incompleto.',
|
||||
textoBotao: 'Voltar ao site'
|
||||
}));
|
||||
}
|
||||
|
||||
const sqlQuery = `
|
||||
UPDATE usuarios
|
||||
SET habilitado = 1
|
||||
WHERE idusuarios = ?;
|
||||
`;
|
||||
|
||||
mysqlConnection.query(sqlQuery, [idusuarios], function (error, results) {
|
||||
console.log(`${new Date().toUTCString()} - ${req.originalUrl} ${(error) ? '500 error' : '200 success'}`);
|
||||
|
||||
if (error) {
|
||||
return res.status(500).send(RenderPaginaAtivacao({
|
||||
sucesso: false,
|
||||
titulo: 'Erro ao ativar conta',
|
||||
mensagem: 'Não foi possível ativar sua conta no momento. Tente novamente mais tarde ou entre em contato com o suporte.',
|
||||
textoBotao: 'Voltar ao site'
|
||||
}));
|
||||
}
|
||||
|
||||
if (!results || results.affectedRows === 0) {
|
||||
return res.status(404).send(RenderPaginaAtivacao({
|
||||
sucesso: false,
|
||||
titulo: 'Conta não encontrada',
|
||||
mensagem: 'Não encontramos uma conta associada a este link de ativação.',
|
||||
textoBotao: 'Voltar ao site'
|
||||
}));
|
||||
}
|
||||
|
||||
return res.status(200).send(RenderPaginaAtivacao({
|
||||
sucesso: true,
|
||||
titulo: 'Conta ativada com sucesso!',
|
||||
mensagem: 'Sua conta foi ativada e você já pode acessar a plataforma Zendion, INC.',
|
||||
textoBotao: 'Entrar agora'
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
function RenderPaginaAtivacao({ sucesso, titulo, mensagem, textoBotao }) {
|
||||
const corPrincipal = sucesso ? '#071b63' : '#991b1b';
|
||||
const corFundoIcone = sucesso ? '#dcfce7' : '#fee2e2';
|
||||
const corIcone = sucesso ? '#15803d' : '#b91c1c';
|
||||
const icone = sucesso ? '✓' : '!';
|
||||
const linkBotao = sucesso ? 'https://zendioninc.com.br/login' : 'https://zendioninc.com.br/home';
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${titulo}</title>
|
||||
</head>
|
||||
|
||||
<body style="margin:0; padding:0; background:#f4f6fb; font-family:Arial, Helvetica, sans-serif; color:#1f2937;">
|
||||
<div style="min-height:100vh; display:flex; align-items:center; justify-content:center; padding:32px 16px; box-sizing:border-box; background:linear-gradient(135deg, #f4f6fb 0%, #eef3ff 45%, #ffffff 100%);">
|
||||
|
||||
<div style="width:100%; max-width:560px; background:#ffffff; border-radius:22px; overflow:hidden; box-shadow:0 24px 70px rgba(15, 23, 42, 0.16); border:1px solid rgba(148, 163, 184, 0.22);">
|
||||
|
||||
<div style="background:#071b63; padding:28px 32px; text-align:center;">
|
||||
<img src="https://zendioninc.com.br/assets/logo_escrito.png" alt="Zendion, INC." style="height:54px; max-width:240px; object-fit:contain; filter:brightness(0) invert(1);">
|
||||
</div>
|
||||
|
||||
<div style="padding:42px 34px; text-align:center;">
|
||||
<div style="width:72px; height:72px; margin:0 auto 22px auto; border-radius:999px; display:flex; align-items:center; justify-content:center; background:${corFundoIcone}; color:${corIcone}; font-size:38px; font-weight:900;">
|
||||
${icone}
|
||||
</div>
|
||||
|
||||
<h1 style="margin:0 0 14px 0; color:#0f172a; font-size:28px; line-height:36px; font-weight:800;">
|
||||
${titulo}
|
||||
</h1>
|
||||
|
||||
<p style="margin:0 0 28px 0; color:#64748b; font-size:16px; line-height:26px;">
|
||||
${mensagem}
|
||||
</p>
|
||||
|
||||
<a href="${linkBotao}" style="display:inline-block; background:${corPrincipal}; color:#ffffff; text-decoration:none; font-size:15px; font-weight:800; padding:14px 28px; border-radius:12px; box-shadow:0 12px 24px rgba(7, 27, 99, 0.22);">
|
||||
${textoBotao}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style="background:#f8fafc; padding:18px 28px; text-align:center; border-top:1px solid #e5e7eb;">
|
||||
<p style="margin:0; color:#94a3b8; font-size:12px; line-height:20px;">
|
||||
Zendion, INC. • Este é um processo automático de ativação de conta.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
router.get('/getUsuarios', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM usuarios;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getUsuarioByID/:idusuarios', function (req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `SELECT * FROM usuarios WHERE idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getSistemasDoUsuario/:idusuarios', function (req, res) {
|
||||
const idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `SELECT
|
||||
s.idsistemas,
|
||||
s.nome,
|
||||
su.data_download,
|
||||
su.idusuarios,
|
||||
s.descricao,
|
||||
(SELECT COUNT(1) FROM chaves cv WHERE cv.idsistemas = s.idsistemas AND cv.idusuarios = su.idusuarios AND cv.data_validade > CURRENT_DATE) AS chavesValidas,
|
||||
CASE WHEN s.idtiposlicenca = 6 THEN 1 ELSE 0 END AS gratis
|
||||
FROM sistemasusuario su
|
||||
INNER JOIN sistemas s ON s.idsistemas = su.idsistemas
|
||||
WHERE su.idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/authUser', function (req, res) {
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
const sqlQuery = `SELECT
|
||||
idusuarios,
|
||||
nome,
|
||||
idtiposdeusuario,
|
||||
habilitado
|
||||
FROM usuarios
|
||||
WHERE usuario = '${usuario}' AND senha = '${senha}';`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTiposdeusuario', function (req, res) {
|
||||
const sqlQuery = `SELECT * FROM tiposdeusuario;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertUsuarios', function (req, res) {
|
||||
let idusuarios = req.body.idusuarios;
|
||||
let nome = req.body.nome;
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
let email = req.body.email;
|
||||
let idtiposdeusuario = req.body.idtiposdeusuario;
|
||||
let cpf = req.body.cpf;
|
||||
let habilitado = req.body.habilitado ? 1 : 0;
|
||||
const sqlQuery = `INSERT INTO usuarios (nome, usuario, senha, data_cadastro, cpf, habilitado, email, idtiposdeusuario)
|
||||
VALUES ('${nome}', UPPER('${usuario}'), UPPER('${senha}'), now(), '${cpf}', ${habilitado}, '${email}', ${idtiposdeusuario});`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/updateUsuarios', function (req, res) {
|
||||
let idusuarios = req.body.idusuarios;
|
||||
let nome = req.body.nome;
|
||||
let usuario = req.body.usuario;
|
||||
let senha = req.body.senha;
|
||||
let email = req.body.email;
|
||||
let idtiposdeusuario = req.body.idtiposdeusuario;
|
||||
let cpf = req.body.cpf;
|
||||
let habilitado = req.body.habilitado ? 1 : 0;
|
||||
const sqlQuery = `UPDATE usuarios SET
|
||||
nome = '${nome}',
|
||||
usuario = UPPER('${usuario}'),
|
||||
senha = UPPER('${senha}'),
|
||||
cpf = '${cpf}',
|
||||
habilitado = ${habilitado},
|
||||
email = '${email}',
|
||||
idtiposdeusuario = ${idtiposdeusuario}
|
||||
WHERE idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.delete('/deleteUsuarios/:idusuarios', function (req, res) {
|
||||
let idusuarios = parseInt(req.params.idusuarios);
|
||||
const sqlQuery = `DELETE FROM usuarios WHERE idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/setUsada', function (req, res) {
|
||||
let chave = req.body.Chave;
|
||||
const sqlQuery = `UPDATE chaves SET usada = 1 WHERE licenca = '${chave}';`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/validaLicenca', function (req, res) {
|
||||
let usuario = req.body.Usuario;
|
||||
let senha = req.body.Senha;
|
||||
let chave = req.body.Chave;
|
||||
const sqlQuery = `SELECT
|
||||
u.nome AS Nome,
|
||||
u.cpf AS CPF,
|
||||
c.usada AS Usada,
|
||||
c.idsistemas AS IDSistema
|
||||
FROM chaves c
|
||||
INNER JOIN usuarios u ON c.idusuarios = u.idusuarios
|
||||
WHERE c.licenca = '${chave}' AND u.usuario = '${usuario}' AND u.senha = '${senha}' AND u.habilitado = 1 AND c.usada = 0;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/insertTrocasenha', function (req, res) {
|
||||
let idusuarios = parseInt(req.body.idusuarios);
|
||||
let tag = req.body.tag;
|
||||
const sqlQuery = `INSERT INTO trocasenha (idusuarios, tag, usada) VALUES (${idusuarios}, '${tag}', 0);`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTrocasenha', function (req, res, next) {
|
||||
const sqlQuery = `SELECT * FROM trocasenha WHERE usada = 0;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.get('/getTrocasenhaByTag/:tag', function (req, res, next) {
|
||||
let tag = req.params.tag;
|
||||
const sqlQuery = `SELECT * FROM trocasenha WHERE tag = '${tag}' AND usada = 0;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/setExpirado', function (req, res, next) {
|
||||
let tag = req.body.tag;
|
||||
const sqlQuery = `UPDATE trocasenha SET usada = 1 WHERE tag = '${tag}';`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.patch('/trocaSenha', function (req, res, next) {
|
||||
const idusuarios = parseInt(req.body.idusuarios);
|
||||
const senha = req.body.senha;
|
||||
const sqlQuery = `UPDATE usuarios SET
|
||||
senha = UPPER('${senha}')
|
||||
WHERE idusuarios = ${idusuarios};`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
router.post('/validaLicencaByChave/:idsistemas', function (req, res, next) {
|
||||
const idsistemas = parseInt(req.params.idsistemas);
|
||||
const chave = req.body.Chave;
|
||||
const sqlQuery = `SELECT
|
||||
u.nome AS Nome,
|
||||
u.cpf AS CPF,
|
||||
c.usada AS Usada,
|
||||
c.idsistemas AS IDSistema
|
||||
FROM chaves c
|
||||
INNER JOIN usuarios u ON c.idusuarios = u.idusuarios
|
||||
WHERE c.licenca = '${chave}' AND c.idsistemas = ${idsistemas} AND u.habilitado = 1 AND c.usada = 0;`;
|
||||
ExecuteQuery(sqlQuery, req, res);
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"uid": "zendioninc_api",
|
||||
"append": true,
|
||||
"watch": false,
|
||||
"script": "server.js",
|
||||
"sourceDir": "/var/www/html/server/",
|
||||
"workingDir": "/var/www/html/server/"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"type": "service_account",
|
||||
"project_id": "gca-control-bcb9b",
|
||||
"private_key_id": "2e672cfd0a80e4d837abe0b0588540954677e4f8",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKqU5nsJGM5P8C\n4DUsrNYIbIVQxZRxL1mdEvAtYuLg8S6sEjIaxUQElDazQ9W8X4fdU/oVL9oziCCG\nwlJoEKsaPMiLIi4aBzgyCxSjsMk1uJonl++TkEPxUQa4gy8fq/UhHXkBROS9nBy2\n7VWqvcN176oPmYwhg5qLxfhYsZWwwZLBtntpQNaGdA0Ul7h+nwp5qsrkst3Qx2Su\nqfvUOYr8pvvzb+P+eU1Qw5aPBjGQQXcZ8rE4d3qyTSJ+xaZwblPViQhHAch/bt8n\n2uKN/rFjl3QpumzDuiF7z7+dFqf4vnCfpHbar1jLK3HIS6RE+y5iTqBeREzRSLts\n2VAN1PP1AgMBAAECggEACW4nQMIcWmpLJy2Fg+qXULqIrz7BFCLlgF6MewwuLanu\nEkyMH3yc7Y/zsKlK1ZJmGSmKdPhuUUtiZMA/mJSSpaynkfkunIBIADoi79AEOOH6\nGGFkoPZLrGZpEeZsJ6+Mf0nmuCVQyzWWYiO5QrHvBGVOgZ3TQbmk6XVLmQhLGcz+\n6LdO225096syWBvAelcv8iSs2D7mEv920TT5Hj1ZwOuEnfOca38fiBpi359VrbMd\nqEDDO3B3qoy3mrWxWLW1NqTdavLLvJhee651xrFq4f5Zy99uuHVs9DD+L5Yo56BD\nRZBKJOmMHMtvpe3ePyYfr8d1E0ijMuWwIStnRHgFSQKBgQDuKgGwGq54wvg0ybgK\ngqtP/2gGHjXnS1ii5vUxy2DverCv1FcI5ll7/1LcgKQSwFBZGYcg+p7ZMTh31CCe\nQPvIEeFuo0pJIdqcjANKi1V9tQLq2BzJMJ/KXQpkr97Bz9PNaBy877Or/Nsf95Ao\n6rdaCteox5FU1vmFay2rfW/8XQKBgQDZ1qeIFMUFqKnMFKokk/bWnuSeCnwf6IGu\naMKQY0lVV1Y1nM7Ti0fLZRrEpYnSjvwpPYvno+onGH5yUSlP3owJdvaqPdLSAy54\nHrm/YdUUBx+f2LUdcC7hIaS+2b3rXlO5tT98wqbqYvFf5QSVfknjKpAEJ0ADYm7M\n4+bizLaceQKBgGdjcOwkCQ1/hgRUdUKKyxelRmExiDDqMoY1QMfnBCOx3TXXNhk0\n9i+v/Saf6ZoCRl8Hh/O3GHIsvdi3C5nnl+WYbYZ7+Gma+q3u0hbwOaKii6urOYPV\nSeitTy+6cTcto0KOKbuTSyokUHOmIrzAd+vsvQYV7G8qC5PxnRfPEmg5AoGAJShr\nXVgFn4h8pjYkK6cdpNBnuNmbAKpdbI2sGosFGEyUhQKheQ46CeTOIxsFnmgLdVFt\nSu734wFXmFJl1JzmkDq9qp5vFqm6RH0hPBcJDKiGaXLCuinHpVliy7dCoSJu76+O\nC878P+DuwWfEV2e6XMiG1l6HmcwxkDuTx74ZrCkCgYEAsa0RwkyCvQBShW7BtZot\nd6iziBqI+gqSq4KYraWvvMVrjA00IKk0B/uzofnK/aX98HJM4NzO9EAbW0ARpn5D\nDv7FwBRT+fWG8CW+XvT5LiKO7KYILimFm4cvzuv5gztLGexlfFBiUn1+t6fzI5Yf\neCafFoJuPEDGHoIOAqd5PME=\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "firebase-adminsdk-pf0od@gca-control-bcb9b.iam.gserviceaccount.com",
|
||||
"client_id": "105026073302094660795",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-pf0od%40gca-control-bcb9b.iam.gserviceaccount.com"
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "274810216572",
|
||||
"project_id": "gca-control-bcb9b",
|
||||
"storage_bucket": "gca-control-bcb9b.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:274810216572:android:0d9250a6adb98f84f4a9f9",
|
||||
"android_client_info": {
|
||||
"package_name": "com.ZendionInc.GCAControl"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "274810216572-6c1qof9nb2gns24604s1narajuhfluh4.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDTKEi1eHsF50y1KIMHY9x04OXXOVqs7ig"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "274810216572-6c1qof9nb2gns24604s1narajuhfluh4.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "server",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@sendgrid/mail": "^8.1.3",
|
||||
"body-parser": "^1.18.3",
|
||||
"cors": "^2.8.4",
|
||||
"dotenv": "^17.4.2",
|
||||
"express": "^4.16.3",
|
||||
"express-formidable": "^1.0.0",
|
||||
"express-jwt": "^5.3.1",
|
||||
"firebase-admin": "^10.0.1",
|
||||
"formidable": "^1.2.1",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"lodash": "^4.17.10",
|
||||
"mercadopago": "^2.0.15",
|
||||
"mysql": "^2.15.0",
|
||||
"nodemailer": "^6.10.1",
|
||||
"nodemon": "^3.1.14",
|
||||
"shelljs": "^0.8.4",
|
||||
"unzipper": "^0.12.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
var express = require('express');
|
||||
var http = require('http');
|
||||
var app = express();
|
||||
var cors = require('cors');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
var corsOptions = {
|
||||
origin: '*',
|
||||
optionsSuccessStatus: 200
|
||||
}
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(bodyParser.json());
|
||||
|
||||
http.createServer(app).listen(1337, () => {
|
||||
console.log(`API is listening on 1337`);
|
||||
});
|
||||
|
||||
app.use('/users', require('./controllers/usuariosController')());
|
||||
app.use('/sistemas', require('./controllers/sistemasController')());
|
||||
app.use('/slides', require('./controllers/sliderController')());
|
||||
app.use('/noticias', require('./controllers/noticiasController')());
|
||||
app.use('/arquivos', require('./controllers/arquivosController')());
|
||||
app.use('/bingo', require('./controllers/bingoController')());
|
||||
app.use('/gca', require('./controllers/gcaController')());
|
||||
app.use('/priorie', require('./controllers/priorieController')());
|
||||
app.use('/email', require('./controllers/emailController').router);
|
||||
app.use('/checkout', require('./controllers/checkoutController')());
|
||||
|
||||
app.use('/otp', require('./controllers/oriontardproController')());
|
||||
|
||||
// Allteeth
|
||||
app.use('/api_5/sincronia', require('./controllers/allteeth/sincroniaController')());
|
||||
app.use('/api_5/users', require('./controllers/allteeth/usuariosController')());
|
||||
|
||||
app.use('/agrobase', require('./controllers/agrobaseController')());
|
||||
|
|
@ -0,0 +1 @@
|
|||
agrobase login
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-agrobase-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class AgrobaseLoginComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<!-- Título da Página -->
|
||||
<h1>Gerenciamento de Arquivos de Versão</h1>
|
||||
|
||||
<!-- Botão para adicionar novo arquivo -->
|
||||
<div class="actions">
|
||||
<button mat-raised-button color="primary" (click)="abrirDialogoArquivo()">Adicionar Arquivo</button>
|
||||
</div>
|
||||
|
||||
<!-- Tabela de Arquivos -->
|
||||
<table mat-table [dataSource]="arquivos" class="mat-elevation-z8 table-container">
|
||||
<!-- Coluna do Nome do Arquivo para Download -->
|
||||
<ng-container matColumnDef="ArquivoDownload">
|
||||
<th mat-header-cell *matHeaderCellDef>Nome do Arquivo para Download</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.ArquivoDownload }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna do Nome do Arquivo -->
|
||||
<ng-container matColumnDef="Arquivo">
|
||||
<th mat-header-cell *matHeaderCellDef>Nome do Arquivo</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.Arquivo }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna do Diretório -->
|
||||
<ng-container matColumnDef="Diretorio">
|
||||
<th mat-header-cell *matHeaderCellDef>Diretório</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.Diretorio }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna da Extensão -->
|
||||
<ng-container matColumnDef="Extensao">
|
||||
<th mat-header-cell *matHeaderCellDef>Extensão</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.Extensao }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna da Versão -->
|
||||
<ng-container matColumnDef="Versao">
|
||||
<th mat-header-cell *matHeaderCellDef>Versão</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.Versao }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna do Tipo de Arquivo -->
|
||||
<ng-container matColumnDef="TipoArquivo">
|
||||
<th mat-header-cell *matHeaderCellDef>Tipo de Arquivo</th>
|
||||
<td mat-cell *matCellDef="let arquivo">{{ arquivo.TipoArquivo | tipoArquivoNome }}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Coluna de Ações -->
|
||||
<ng-container matColumnDef="acoes">
|
||||
<th mat-header-cell *matHeaderCellDef>Ações</th>
|
||||
<td mat-cell *matCellDef="let arquivo">
|
||||
<button mat-icon-button color="primary" (click)="abrirDialogoArquivo(arquivo)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="excluirArquivo(arquivo)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
|
||||
<!-- Diálogo para Editar/Adicionar Arquivo -->
|
||||
<ng-template #dialogoArquivo let-data>
|
||||
<h2 mat-dialog-title>{{ data?.novo ? 'Adicionar Arquivo' : 'Editar Arquivo' }}</h2>
|
||||
<form [formGroup]="arquivoForm" (ngSubmit)="onSubmit()">
|
||||
<!-- Campo para o nome do arquivo -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nome do Arquivo Local</mat-label>
|
||||
<input matInput placeholder="Nome do Arquivo Local" formControlName="Arquivo" required />
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para o diretório do arquivo -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Diretório</mat-label>
|
||||
<input matInput placeholder="Diretório" formControlName="Diretorio" required />
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para a extensão do arquivo -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Extensão</mat-label>
|
||||
<input matInput placeholder="Extensão" formControlName="Extensao" required />
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para a versão do arquivo -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Versão</mat-label>
|
||||
<input matInput placeholder="Versão" formControlName="Versao" required />
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para o tipo do arquivo (dropdown com opções) -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Tipo do Arquivo</mat-label>
|
||||
<mat-select formControlName="TipoArquivo" required>
|
||||
<mat-option *ngFor="let tipo of tiposArquivos" [value]="tipo">{{ tipo }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para o nome do arquivo -->
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Nome do Arquivo para Download</mat-label>
|
||||
<input matInput placeholder="Nome do Arquivo para Download" formControlName="ArquivoDownload" required />
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Campo para upload do arquivo -->
|
||||
<input type="file" (change)="onFileSelected($event)" style="margin-top: 16px;" />
|
||||
|
||||
<!-- Botões de ação para cancelar ou salvar -->
|
||||
<div mat-dialog-actions style="justify-content: flex-end;">
|
||||
<button mat-button (click)="onCancel()">Cancelar</button>
|
||||
<button mat-raised-button color="primary" type="submit">{{ data?.novo ? 'Adicionar' : 'Salvar' }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
.agrobase-container {
|
||||
background-color: #1A237E; /* Fundo azul escuro */
|
||||
color: #E3F2FD; /* Texto branco */
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #FFFFFF; /* Título branco */
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 100%; /* Largura total */
|
||||
background-color: #283593; /* Azul médio para destaque */
|
||||
color: #E3F2FD; /* Texto branco */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mat-header-cell, .mat-cell {
|
||||
color: #E3F2FD; /* Texto branco */
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
color: #E3F2FD; /* Texto branco */
|
||||
background-color: #283593; /* Azul médio para contraste */
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mat-dialog-container {
|
||||
background-color: #1E88E5; /* Fundo mais claro para o diálogo */
|
||||
color: #E3F2FD;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.mat-button {
|
||||
color: #E3F2FD;
|
||||
background-color: #42A5F5; /* Botão azul claro */
|
||||
}
|
||||
|
||||
.mat-button:hover {
|
||||
background-color: #64B5F6; /* Azul mais claro para hover */
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { MatDialog, MatTableDataSource } from '@angular/material';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AgrobaseVersionFileModel, TiposArquivos } from 'src/app/models/agrobaseModel';
|
||||
import { AgrobaseService } from 'src/app/services/agrobase.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-agrobase-versionamento',
|
||||
templateUrl: './versionamento.component.html',
|
||||
styleUrls: ['./versionamento.component.scss']
|
||||
})
|
||||
export class AgrobaseVersionamentoComponent implements OnInit {
|
||||
|
||||
displayedColumns: string[] = ['ArquivoDownload', 'Arquivo', 'Diretorio', 'Extensao', 'Versao', 'TipoArquivo', 'acoes'];
|
||||
arquivos: MatTableDataSource<AgrobaseVersionFileModel> = new MatTableDataSource<AgrobaseVersionFileModel>();
|
||||
arquivoForm: FormGroup;
|
||||
tiposArquivos = Object.values(TiposArquivos).filter(value => typeof value === 'string');
|
||||
arquivoSelecionado: File | null = null;
|
||||
|
||||
@ViewChild('dialogoArquivo', null) dialogoArquivo;
|
||||
|
||||
constructor(
|
||||
private agrobaseService: AgrobaseService,
|
||||
private dialog: MatDialog,
|
||||
private fb: FormBuilder,
|
||||
) {
|
||||
this.arquivoForm = this.fb.group({
|
||||
id: [''],
|
||||
Arquivo: [''],
|
||||
Diretorio: [''],
|
||||
Extensao: [''],
|
||||
Versao: [''],
|
||||
TipoArquivo: [''],
|
||||
ArquivoDownload: [''],
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.carregarArquivos();
|
||||
}
|
||||
|
||||
carregarArquivos() {
|
||||
this.agrobaseService.getArquivosVersao().subscribe(
|
||||
(data) => {
|
||||
this.arquivos.data = data;
|
||||
},
|
||||
(error) => {
|
||||
console.error('Erro ao carregar dados de versão:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
abrirDialogoArquivo(arquivo?: AgrobaseVersionFileModel) {
|
||||
const dialogRef = this.dialog.open(this.dialogoArquivo, {
|
||||
data: arquivo ? { ...arquivo } : { novo: true }
|
||||
});
|
||||
|
||||
if (arquivo) {
|
||||
this.arquivoForm.patchValue(arquivo);
|
||||
} else {
|
||||
this.arquivoForm.reset();
|
||||
}
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.salvarArquivo(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onFileSelected(event: any) {
|
||||
this.arquivoSelecionado = event.target.files[0] || null;
|
||||
}
|
||||
|
||||
// Este método irá enviar o arquivo .vsf atualizado para o servidor
|
||||
atualizarArquivoVsf() {
|
||||
const jsonData = JSON.stringify(this.arquivos.data);
|
||||
|
||||
this.agrobaseService.atualizarVsfFile(jsonData).subscribe(
|
||||
() => console.log("Arquivo .vsf atualizado com sucesso no servidor."),
|
||||
(error) => console.error("Erro ao atualizar o arquivo .vsf:", error)
|
||||
);
|
||||
}
|
||||
|
||||
// Modifique o método salvarArquivo para incluir a atualização do .vsf após o upload do arquivo
|
||||
salvarArquivo(dadosArquivo: AgrobaseVersionFileModel) {
|
||||
if (this.arquivoSelecionado) {
|
||||
this.agrobaseService.uploadFile(this.arquivoSelecionado, dadosArquivo.ArquivoDownload).subscribe(response => {
|
||||
this.salvarNaTabela(dadosArquivo);
|
||||
this.atualizarArquivoVsf(); // Chama a atualização do .vsf
|
||||
});
|
||||
} else {
|
||||
this.salvarNaTabela(dadosArquivo);
|
||||
this.atualizarArquivoVsf(); // Atualiza o .vsf mesmo sem upload de arquivo
|
||||
}
|
||||
}
|
||||
|
||||
salvarNaTabela(dadosArquivo: AgrobaseVersionFileModel) {
|
||||
|
||||
console.log(dadosArquivo.TipoArquivo);
|
||||
dadosArquivo.TipoArquivo = TiposArquivos[dadosArquivo.TipoArquivo as unknown as keyof typeof TiposArquivos];
|
||||
console.log(dadosArquivo.TipoArquivo);
|
||||
|
||||
let index = this.arquivos.data.findIndex(a =>
|
||||
a.id === dadosArquivo.id ||
|
||||
(a.Arquivo === dadosArquivo.Arquivo && a.Diretorio === dadosArquivo.Diretorio)
|
||||
);
|
||||
|
||||
if (index >= 0) {
|
||||
// Substitui o item existente com os dados atualizados
|
||||
this.arquivos.data[index] = dadosArquivo;
|
||||
} else {
|
||||
// Adiciona um novo item caso não exista na lista
|
||||
dadosArquivo.id = this.gerarIdUnico(); // Gera um ID único
|
||||
this.arquivos.data = [...this.arquivos.data, dadosArquivo];
|
||||
}
|
||||
|
||||
this.arquivos._updateChangeSubscription(); // Atualiza a tabela
|
||||
}
|
||||
|
||||
// Função auxiliar para gerar IDs únicos
|
||||
gerarIdUnico(): number {
|
||||
return this.arquivos.data.length > 0 ? Math.max(...this.arquivos.data.map(a => a.id || 0)) + 1 : 1;
|
||||
}
|
||||
|
||||
excluirArquivo(arquivo: AgrobaseVersionFileModel) {
|
||||
if (confirm("Tem certeza que deseja excluir o arquivo " + arquivo.Arquivo + "?")) {
|
||||
this.agrobaseService.deleteVersionFile(arquivo.ArquivoDownload).subscribe(
|
||||
(data) => {
|
||||
this.arquivos.data = this.arquivos.data.filter(a => a !== arquivo);
|
||||
this.arquivos._updateChangeSubscription(); // Atualiza a tabela
|
||||
this.atualizarArquivoVsf();
|
||||
},
|
||||
(error) => {
|
||||
console.error('Erro ao carregar dados de versão:', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.arquivoForm.valid) {
|
||||
const dadosArquivo: AgrobaseVersionFileModel = this.arquivoForm.value;
|
||||
this.salvarArquivo(dadosArquivo);
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { UsuariosService } from './services/usuarios.service';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { UsersComponent } from './users/users.component';
|
||||
import { ClientComponent } from './client/client.component';
|
||||
import { FuncoesGlobais } from 'src/environments/environment';
|
||||
import { SistemasComponent } from './sistemas/sistemas.component';
|
||||
import { SistemasService } from './services/sistemas.service';
|
||||
import { CriarcontaComponent } from './criarconta/criarconta.component';
|
||||
import { DetalhesSistemaComponent } from './detalhes-sistema/detalhes-sistema.component';
|
||||
import { BaseSiteComponent } from './base-site/base-site.component';
|
||||
import { ChavesComponent } from './chaves/chaves.component';
|
||||
import { EditHomeComponent } from './edit-home/edit-home.component';
|
||||
import { SliderComponent } from './slider/slider.component';
|
||||
import { NoticiasComponent } from './noticias/noticias.component';
|
||||
import { SliderService } from './services/slider.service';
|
||||
import { NoticiasService } from './services/noticias.service';
|
||||
import { GeralService } from './services/geral.service';
|
||||
import { CadDetSistemaComponent } from './cad-det-sistema/cad-det-sistema.component';
|
||||
import { EasyAVAComponent } from './easy-ava/easy-ava.component';
|
||||
import { EasyAVAService } from './services/easy-ava.service';
|
||||
import { BingoSortComponent } from './bingo-sort/bingo-sort.component';
|
||||
import { BingoComponent } from './bingo/bingo.component';
|
||||
import { BingoDashboardComponent } from './bingo-dashboard/bingo-dashboard.component';
|
||||
import { BingoService } from './services/bingoService';
|
||||
import { OrionDashboardComponent } from './orion-dashboard/orion-dashboard.component';
|
||||
import { OrionService } from './services/orionService';
|
||||
import { ProdutosComponent } from './produtos/produtos.component';
|
||||
import { ProdutosService } from './services/produtosService';
|
||||
import { AgrobaseLoginComponent } from './agrobase/login/login.component';
|
||||
import { AgrobaseVersionamentoComponent } from './agrobase/versionamento/versionamento.component';
|
||||
import { AgrobaseService } from './services/agrobase.service';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{
|
||||
path: '',
|
||||
component: BaseSiteComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
}, {
|
||||
path: 'detalhes/:idsistemas',
|
||||
component: DetalhesSistemaComponent,
|
||||
},
|
||||
]
|
||||
}, {
|
||||
path: 'login',
|
||||
component: LoginComponent,
|
||||
}, {
|
||||
path: 'login/esqueci',
|
||||
component: LoginComponent,
|
||||
}, {
|
||||
path: 'login/trocar/:tag',
|
||||
component: LoginComponent,
|
||||
}, {
|
||||
path: 'criarconta',
|
||||
component: CriarcontaComponent,
|
||||
}, {
|
||||
path: 'dashboard',
|
||||
component: DashboardComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'usuarios/cadastro',
|
||||
component: UsersComponent,
|
||||
}, {
|
||||
path: 'usuarios/editar/:idusuarios',
|
||||
component: UsersComponent,
|
||||
}, {
|
||||
path: 'usuarios/visualizar',
|
||||
component: UsersComponent,
|
||||
}, {
|
||||
path: 'sistemas/cadastro',
|
||||
component: SistemasComponent,
|
||||
}, {
|
||||
path: 'sistemas/editar/:idsistemas',
|
||||
component: SistemasComponent,
|
||||
}, {
|
||||
path: 'sistemas/visualizar',
|
||||
component: SistemasComponent,
|
||||
}, {
|
||||
path: 'sistemas/detalhes/:idsistemas',
|
||||
component: CadDetSistemaComponent,
|
||||
}, {
|
||||
path: 'sistemas/produtos/:idsistemas',
|
||||
component: ProdutosComponent,
|
||||
}, {
|
||||
path: 'cliente',
|
||||
component: ClientComponent,
|
||||
}, {
|
||||
path: 'cliente/chave/:idsistemas',
|
||||
component: ChavesComponent,
|
||||
}, {
|
||||
path: 'admin/home',
|
||||
component: EditHomeComponent,
|
||||
}, {
|
||||
path: 'admin/slides',
|
||||
component: SliderComponent,
|
||||
}, {
|
||||
path: 'admin/slides/visualizar',
|
||||
component: SliderComponent,
|
||||
}, {
|
||||
path: 'admin/slides/editar/:idslides',
|
||||
component: SliderComponent,
|
||||
}, {
|
||||
path: 'admin/noticias',
|
||||
component: NoticiasComponent,
|
||||
}, {
|
||||
path: 'admin/noticias/visualizar',
|
||||
component: NoticiasComponent,
|
||||
}, {
|
||||
path: 'admin/noticias/editar/:idnoticias',
|
||||
component: NoticiasComponent,
|
||||
}
|
||||
]
|
||||
}, {
|
||||
path: 'easyava',
|
||||
component: EasyAVAComponent,
|
||||
}, {
|
||||
path: 'bingo',
|
||||
//component: BingoComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
component: BingoDashboardComponent,
|
||||
}, {
|
||||
path: 'sorteio',
|
||||
component: BingoSortComponent,
|
||||
},
|
||||
]
|
||||
}, {
|
||||
path: 'orion-dashboard',
|
||||
component: OrionDashboardComponent
|
||||
}, {
|
||||
path: 'agrobase',
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
component: AgrobaseLoginComponent,
|
||||
}, {
|
||||
path: 'versionamento',
|
||||
component: AgrobaseVersionamentoComponent,
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes),
|
||||
],
|
||||
exports: [
|
||||
RouterModule,
|
||||
],
|
||||
providers: [
|
||||
FuncoesGlobais,
|
||||
UsuariosService,
|
||||
SistemasService,
|
||||
SliderService,
|
||||
NoticiasService,
|
||||
GeralService,
|
||||
EasyAVAService,
|
||||
BingoService,
|
||||
OrionService,
|
||||
ProdutosService,
|
||||
AgrobaseService
|
||||
]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
|
@ -0,0 +1 @@
|
|||
<router-outlet></router-outlet>
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
.form-cabecalho {
|
||||
border: 1px solid gray;
|
||||
margin-right: 1em;
|
||||
border-radius: 0.3em 0.3em 0 0;
|
||||
background: gray;
|
||||
padding-top: 0.4em;
|
||||
padding-left: 2em;
|
||||
height: 3em;
|
||||
border-bottom: #d8d8d8;
|
||||
}
|
||||
|
||||
.form-corpo {
|
||||
border: 1px solid gray;
|
||||
margin-right: 1em;
|
||||
background: lightgrey;
|
||||
padding: 1em;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.checkHabilitado {
|
||||
width: 8em;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
table {
|
||||
font-family: arial, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
.quadro-Branco {
|
||||
color: #000;
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
background: #fff;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
.MyHR {
|
||||
background: #eee;
|
||||
height: 1px;
|
||||
margin: auto;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.FundoCheio {
|
||||
position: absolute;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@mixin sp-layout {
|
||||
@media screen and (max-width: 750px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
background: radial-gradient(ellipse at bottom, #0d1d31 0%, #0c0d13 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@function random_range($min, $max) {
|
||||
$rand: random();
|
||||
$random_range: $min + floor($rand * (($max - $min) + 1));
|
||||
@return $random_range;
|
||||
}
|
||||
|
||||
.stars {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120%;
|
||||
transform: rotate(-45deg);
|
||||
z-index: -10;
|
||||
}
|
||||
|
||||
.star {
|
||||
$star-count: 20;
|
||||
--star-color: var(--primary-color);
|
||||
--star-tail-length: 6em;
|
||||
--star-tail-height: 2px;
|
||||
--star-width: calc(var(--star-tail-length) / 6);
|
||||
--fall-duration: 9s;
|
||||
--tail-fade-duration: var(--fall-duration);
|
||||
|
||||
position: absolute;
|
||||
top: var(--top-offset);
|
||||
left: 0;
|
||||
width: var(--star-tail-length);
|
||||
height: var(--star-tail-height);
|
||||
color: var(--star-color);
|
||||
background: linear-gradient(45deg, currentColor, transparent);
|
||||
border-radius: 50%;
|
||||
filter: drop-shadow(0 0 6px currentColor);
|
||||
transform: translate3d(104em, 0, 0);
|
||||
animation: fall var(--fall-duration) var(--fall-delay) linear infinite, tail-fade var(--tail-fade-duration) var(--fall-delay) ease-out infinite;
|
||||
|
||||
@include sp-layout {
|
||||
// For mobile performance, tail-fade animation will be removed QAQ
|
||||
animation: fall var(--fall-duration) var(--fall-delay) linear infinite;
|
||||
}
|
||||
|
||||
@for $i from 1 through $star-count {
|
||||
&:nth-child(#{$i}) {
|
||||
--star-tail-length: #{random_range(500em, 750em) / 100};
|
||||
--top-offset: #{random_range(0vh, 10000vh) / 100};
|
||||
--fall-duration: #{random_range(6000, 12000s) / 1000};
|
||||
--fall-delay: #{random_range(0, 10000s) / 1000};
|
||||
}
|
||||
}
|
||||
|
||||
&::before, &::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: calc(var(--star-width) / -2);
|
||||
width: var(--star-width);
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent, currentColor, transparent);
|
||||
border-radius: inherit;
|
||||
animation: blink 2s linear infinite;
|
||||
}
|
||||
|
||||
&::before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
&::after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fall {
|
||||
to {
|
||||
transform: translate3d(-30em, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tail-fade {
|
||||
0%, 50% {
|
||||
width: var(--star-tail-length);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
70%, 80% {
|
||||
width: 0;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { Title } from '@angular/platform-browser';
|
||||
import { Component } from '@angular/core';
|
||||
import { GeralService } from './services/geral.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
|
||||
export class AppComponent {
|
||||
|
||||
constructor(
|
||||
private geralSerivice: GeralService,
|
||||
private titleService: Title
|
||||
) {
|
||||
this.titleService.setTitle(environment.Titulo);
|
||||
}
|
||||
|
||||
title = '"Zendion, Inc."';
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import { BrowserModule, Title } from '@angular/platform-browser';
|
||||
import { LOCALE_ID, NgModule } from '@angular/core';
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localePt from '@angular/common/locales/pt';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { Angular2UsefulSwiperModule } from 'angular2-useful-swiper';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { UsersComponent } from './users/users.component';
|
||||
import { ClientComponent } from './client/client.component';
|
||||
import { SistemasComponent } from './sistemas/sistemas.component';
|
||||
import { CriarcontaComponent } from './criarconta/criarconta.component';
|
||||
import { DetalhesSistemaComponent } from './detalhes-sistema/detalhes-sistema.component';
|
||||
import { BaseSiteComponent } from './base-site/base-site.component';
|
||||
import { ChavesComponent } from './chaves/chaves.component';
|
||||
import { EditHomeComponent } from './edit-home/edit-home.component';
|
||||
import { SliderComponent } from './slider/slider.component';
|
||||
import { NoticiasComponent } from './noticias/noticias.component';
|
||||
import { CadDetSistemaComponent } from './cad-det-sistema/cad-det-sistema.component';
|
||||
import { EasyAVAComponent } from './easy-ava/easy-ava.component';
|
||||
import { BingoSortComponent } from './bingo-sort/bingo-sort.component';
|
||||
import { BingoComponent } from './bingo/bingo.component';
|
||||
import { BingoDashboardComponent } from './bingo-dashboard/bingo-dashboard.component';
|
||||
import { OrionDashboardComponent } from './orion-dashboard/orion-dashboard.component';
|
||||
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { Ng5SliderModule } from 'ng5-slider';
|
||||
import { ProdutosComponent } from './produtos/produtos.component';
|
||||
import { AgrobaseLoginComponent } from './agrobase/login/login.component';
|
||||
import { AgrobaseVersionamentoComponent } from './agrobase/versionamento/versionamento.component';
|
||||
import { TipoArquivoNomePipe } from './pipes/tipo-arquivo-nome.pipe';
|
||||
|
||||
|
||||
// Registrar a localidade pt-BR
|
||||
registerLocaleData(localePt);
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
LoginComponent,
|
||||
DashboardComponent,
|
||||
UsersComponent,
|
||||
ClientComponent,
|
||||
SistemasComponent,
|
||||
CriarcontaComponent,
|
||||
DetalhesSistemaComponent,
|
||||
BaseSiteComponent,
|
||||
ChavesComponent,
|
||||
EditHomeComponent,
|
||||
SliderComponent,
|
||||
NoticiasComponent,
|
||||
CadDetSistemaComponent,
|
||||
EasyAVAComponent,
|
||||
BingoSortComponent,
|
||||
BingoComponent,
|
||||
BingoDashboardComponent,
|
||||
OrionDashboardComponent,
|
||||
ProdutosComponent,
|
||||
AgrobaseLoginComponent,
|
||||
AgrobaseVersionamentoComponent,
|
||||
TipoArquivoNomePipe
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
Angular2UsefulSwiperModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule,
|
||||
BrowserAnimationsModule,
|
||||
MatDatepickerModule,
|
||||
MatNativeDateModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatButtonModule,
|
||||
MatSidenavModule,
|
||||
MatTabsModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatIconModule,
|
||||
MatDialogModule,
|
||||
Ng5SliderModule
|
||||
],
|
||||
providers: [
|
||||
Title,
|
||||
{ provide: LOCALE_ID, useValue: 'pt-BR' }
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<div class="site-layout">
|
||||
|
||||
<header class="site-header">
|
||||
<div class="header-content">
|
||||
|
||||
<a class="brand-link" [routerLink]="'/home'">
|
||||
<img src="assets/logo_escrito.png" alt="Zendion, INC." class="logo logo-escrito">
|
||||
<img src="assets/logo.png" alt="Zendion, INC." class="logo logo-favicon">
|
||||
</a>
|
||||
|
||||
<nav class="header-nav">
|
||||
<a [routerLink]="'/home'">Início</a>
|
||||
<a href="/home#sistemas">Sistemas</a>
|
||||
<a href="/home#noticias">Notícias</a>
|
||||
</nav>
|
||||
|
||||
<div class="header-actions">
|
||||
<button type="button" class="btn-header btn-header-secondary" (click)="btnCriarcontaClick()">
|
||||
{{ btnSuperior }}
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn-header btn-header-primary" (click)="btnLoginClick()">
|
||||
{{ btnLoginText }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="site-main">
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="footer-content">
|
||||
|
||||
<div class="footer-section about">
|
||||
<img src="assets/logo_escrito.png" alt="Zendion, INC." class="footer-logo">
|
||||
|
||||
<p>
|
||||
A Zendion, INC. desenvolve soluções tecnológicas para simplificar processos,
|
||||
conectar informações e apoiar operações digitais desde 2019.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Navegação</h4>
|
||||
|
||||
<a [routerLink]="'/home'">Início</a>
|
||||
<a href="/home#sistemas">Sistemas</a>
|
||||
<a href="/home#noticias">Notícias</a>
|
||||
<a [routerLink]="'/login'">Área do cliente</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Contato</h4>
|
||||
|
||||
<p>{{ emailContato }}</p>
|
||||
<p>{{ foneContato }}</p>
|
||||
<p>Zendion, INC.</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Institucional</h4>
|
||||
|
||||
<p>
|
||||
Tecnologia, sistemas e automação para empresas que querem operar com mais clareza.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© 2019 - {{ currentYear }} Zendion, INC. Todos os direitos reservados.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
.site-layout {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f4f6fb;
|
||||
}
|
||||
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(7, 27, 99, 0.92);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
box-shadow: 0 12px 34px rgba(15, 23, 42, 0.18);
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
width: 100%;
|
||||
max-width: 1220px;
|
||||
min-height: 76px;
|
||||
margin: 0 auto;
|
||||
padding: 0 22px;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
gap: 26px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.logo-escrito {
|
||||
height: 46px;
|
||||
}
|
||||
|
||||
.logo-favicon {
|
||||
display: none;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.header-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.header-nav a {
|
||||
position: relative;
|
||||
color: #dbeafe;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
transition: color 0.18s ease;
|
||||
}
|
||||
|
||||
.header-nav a::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -7px;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
border-radius: 999px;
|
||||
background: #ffffff;
|
||||
transition: width 0.18s ease;
|
||||
}
|
||||
|
||||
.header-nav a:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.header-nav a:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn-header {
|
||||
min-height: 42px;
|
||||
padding: 0 18px;
|
||||
border-radius: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease, color 0.18s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-header:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-header-primary {
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.btn-header-primary:hover {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.btn-header-secondary {
|
||||
background: rgba(255, 255, 255, 0.10);
|
||||
color: #ffffff;
|
||||
border-color: rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.btn-header-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.site-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
margin-top: auto;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(255, 255, 255, 0.10), transparent 30%),
|
||||
linear-gradient(145deg, #071b63, #04113f);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
width: 100%;
|
||||
max-width: 1220px;
|
||||
margin: 0 auto;
|
||||
padding: 48px 22px 36px 22px;
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr 0.8fr 0.9fr 1fr;
|
||||
gap: 34px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.footer-section h4 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #ffffff;
|
||||
font-size: 15px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.footer-section p,
|
||||
.footer-section a {
|
||||
display: block;
|
||||
margin: 0 0 10px 0;
|
||||
color: #cbd5e1;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-section a:hover {
|
||||
color: #ffffff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
height: 42px;
|
||||
max-width: 220px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
margin-bottom: 18px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
padding: 18px 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-bottom p {
|
||||
margin: 0;
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
@media (max-width: 920px) {
|
||||
.header-content {
|
||||
grid-template-columns: auto auto;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.header-content {
|
||||
min-height: 68px;
|
||||
padding: 0 14px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.logo-escrito {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo-favicon {
|
||||
display: block;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-header {
|
||||
min-height: 38px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 38px 20px 28px 20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-base-site',
|
||||
templateUrl: './base-site.component.html',
|
||||
styleUrls: ['./base-site.component.scss']
|
||||
})
|
||||
export class BaseSiteComponent implements OnInit {
|
||||
|
||||
btnLoginText: string = "Entrar";
|
||||
btnSuperior: string = "Registrar";
|
||||
|
||||
emailContato: string = environment.emailContato;
|
||||
foneContato: string = environment.telefoneContato;
|
||||
currentYear: string = new Date().getFullYear().toString();
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.CheckIsLogged();
|
||||
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
this.CheckIsLogged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CheckIsLogged() {
|
||||
if (localStorage.getItem("Session") == "1") {
|
||||
this.btnLoginText = "Sair";
|
||||
|
||||
if (localStorage.getItem("Role") != "1") {
|
||||
this.btnSuperior = "Meus sistemas";
|
||||
} else {
|
||||
this.btnSuperior = "Painel administrativo";
|
||||
}
|
||||
} else {
|
||||
this.btnLoginText = "Entrar";
|
||||
this.btnSuperior = "Registrar";
|
||||
}
|
||||
}
|
||||
|
||||
btnLoginClick() {
|
||||
if (this.btnLoginText == "Entrar") {
|
||||
this.router.navigate(['login']);
|
||||
} else {
|
||||
this.Logout();
|
||||
}
|
||||
}
|
||||
|
||||
Logout() {
|
||||
localStorage.removeItem("Session");
|
||||
localStorage.removeItem("UserName");
|
||||
localStorage.removeItem("Role");
|
||||
|
||||
this.CheckIsLogged();
|
||||
this.router.navigate(['home']);
|
||||
}
|
||||
|
||||
btnCriarcontaClick() {
|
||||
if (this.btnSuperior == "Registrar") {
|
||||
this.router.navigate(['criarconta']);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.btnSuperior == "Painel administrativo") {
|
||||
this.router.navigate(['dashboard/admin/home']);
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigate(['dashboard/cliente']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<div class="quadro-Branco">
|
||||
<div class="col-md-12" style="margin: auto; margin-bottom: 1em;">
|
||||
<div class="col-md-12">
|
||||
<h3>Sorteios</h3>
|
||||
<div style="float: right; margin-top: -2em;">
|
||||
<i class="material-icons" style="cursor: pointer;" (click)="Voltar()">arrow_back</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row col-md-12 MyHR"></div>
|
||||
|
||||
<div class="row col-md-12">
|
||||
<div class="col-md-7">
|
||||
<label>Descricão</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="FormSorteio.descricao" [disabled]="!Editando && !Novo">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Rodada</label>
|
||||
<input type="number" class="form-control" [(ngModel)]="FormSorteio.rodada" [disabled]="!Editando && !Novo">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label>Data</label>
|
||||
<input type="date" class="form-control" [(ngModel)]="FormSorteio.data_sorteio" [disabled]="!Editando && !Novo">
|
||||
</div>
|
||||
<!--<div class="col-md-2">
|
||||
<label>Bolas</label>
|
||||
<input type="number" class="form-control" [(ngModel)]="FormSorteio.n_max" readonly>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Cartelas</label>
|
||||
<input type="number" class="form-control" [(ngModel)]="FormSorteio.participantes_max" readonly>
|
||||
</div>-->
|
||||
</div>
|
||||
<div class="row col-md-12" style="margin-top: 1em;" [hidden]="!Editando && !Novo">
|
||||
<div class="row col-md-12">
|
||||
<h3 style="cursor: pointer;" (click)="FormSorteio.VerCartelas = !FormSorteio.VerCartelas">Cartelas</h3>
|
||||
</div>
|
||||
<div class="col-md-12" *ngIf="FormSorteio.idbingosorteios == 0">
|
||||
<iframe src="http://zendioninc.mooo.com/Jogos/Bingo/Gerador/" style="border: none; width: 100%; height: 30em; border-radius: 10px;"></iframe>
|
||||
</div>
|
||||
<div class="col-md-12" *ngIf="FormSorteio.idbingosorteios > 0" style="transition: 1s; overflow: auto;" [ngStyle]="FormSorteio.VerCartelas && {'height' : '30em'} || !FormSorteio.VerCartelas && {'height' : '0'}">
|
||||
<div class="row col-md-12" *ngFor="let Cartela of FormSorteio.Cartelas; let i = index">
|
||||
<div class="col-md-2">
|
||||
<label>Canhoto</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="Cartela.canhoto" readonly [ngStyle]="Cartela.nome && {'background' : 'lightgreen'}">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label>Numeros</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="Cartela.numeros" readonly [ngStyle]="Cartela.nome && {'background' : 'lightgreen'}">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Nome</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="Cartela.nome" placeholder="Nome do comprador" [disabled]="!Cartela.Editando">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Telefone</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="Cartela.telefone" placeholder="(00) 00000-0000" [disabled]="!Cartela.Editando">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label>Endereco</label>
|
||||
<input type="text" class="form-control" [(ngModel)]="Cartela.endereco" placeholder="Endereco do comprador" [disabled]="!Cartela.Editando">
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<label>Acão</label>
|
||||
<button class="btn" (click)="SalvarCartela(Cartela)" [ngClass]="{'btn-primary' : !Cartela.Editando, 'btn-success': Cartela.Editando}">{{(Cartela.Editando) ? 'Salvar' : 'Editar'}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row col-md-12" style="margin-top: 1em;">
|
||||
<div class="col-md-6">
|
||||
<button class="btn btn-primary" (click)="NovoBingo()" style="margin-right: 1em;" [disabled]="Editando || Novo">Novo</button>
|
||||
<button class="btn btn-success" (click)="SalvarBingo()" style="margin-right: 1em;" [disabled]="!Editando && !Novo">Salvar</button>
|
||||
<button class="btn btn-danger" (click)="CancelarBingo()" style="margin-right: 1em;" [disabled]="!Editando && !Novo">Cancelar</button>
|
||||
</div>
|
||||
|
||||
<!--<div class="col-md-3">
|
||||
<button class="btn btn-success" (click)="SalvarSorteio()">Salvar Sorteio</button>
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row col-md-12 MyHR"></div>
|
||||
|
||||
<div class="row col-md-12" style="margin: auto;">
|
||||
<h3>Lista</h3>
|
||||
<div class="col-md-12 form-corpo">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Descicão</th>
|
||||
<th>Rodada</th>
|
||||
<th>Data</th>
|
||||
<th>Numeros</th>
|
||||
<th>Cartelas</th>
|
||||
<th style="width: 18em">Ação</th>
|
||||
</tr>
|
||||
<tr *ngFor="let Sorteio of ListaSorteios">
|
||||
<td>{{Sorteio.descricao}}</td>
|
||||
<td>{{Sorteio.rodada}}</td>
|
||||
<td>{{Sorteio.data_sorteio}}</td>
|
||||
<td>{{Sorteio.n_max}}</td>
|
||||
<td>{{Sorteio.participantes_max}}</td>
|
||||
<td style="width: 18em">
|
||||
<button class="btn btn-success" (click)="ExportarCartelas(Sorteio)" style="margin-right: 0.5em" [disabled]="Editando || Novo">Cartelas</button>
|
||||
<button class="btn btn-success" (click)="EditarSorteio(Sorteio)" style="margin-right: 0.5em" [disabled]="Editando || Novo">Editar</button>
|
||||
<button class="btn btn-danger" (click)="RemoverSorteio(Sorteio)" [disabled]="Editando || Novo">Remover</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BingoCartelasModel, BingoSorteiosModel } from '../models/bingoModel';
|
||||
import { BingoService } from '../services/bingoService';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bingo-dashboard',
|
||||
templateUrl: './bingo-dashboard.component.html',
|
||||
styleUrls: ['./bingo-dashboard.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class BingoDashboardComponent implements OnInit {
|
||||
|
||||
FormSorteio: BingoSorteiosModel = new BingoSorteiosModel();
|
||||
ListaSorteios: BingoSorteiosModel[] = new Array<BingoSorteiosModel>();
|
||||
CartelaNumeros: number = 25;
|
||||
AbreCartelas: boolean = false;
|
||||
Novo: boolean = false;
|
||||
Editando: boolean = false;
|
||||
|
||||
constructor(
|
||||
private bingoService: BingoService,
|
||||
private router: Router
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.AtualizarDados();
|
||||
}
|
||||
|
||||
AtualizarDados() {
|
||||
localStorage.setItem("Cartelas", "");
|
||||
localStorage.setItem("NMax", "0");
|
||||
localStorage.setItem("NParticipantes", "0");
|
||||
this.CancelarBingo();
|
||||
this.bingoService.getAllSorteios().then(resSorteios => {
|
||||
this.ListaSorteios = resSorteios;
|
||||
this.GetCartelasSorteio(0);
|
||||
});
|
||||
}
|
||||
|
||||
GetCartelasSorteio(Index) {
|
||||
if (Index < this.ListaSorteios.length) {
|
||||
this.bingoService.getCartelasSorteio(this.ListaSorteios[Index].idbingosorteios).then(resCartelas => {
|
||||
this.ListaSorteios[Index].Cartelas = resCartelas;
|
||||
Index++;
|
||||
this.GetCartelasSorteio(Index);
|
||||
});
|
||||
}
|
||||
else {
|
||||
//console.log(this.ListaSorteios);
|
||||
}
|
||||
}
|
||||
|
||||
NovoBingo() {
|
||||
this.FormSorteio = new BingoSorteiosModel();
|
||||
this.Novo = true;
|
||||
}
|
||||
|
||||
SalvarBingo() {
|
||||
if (this.FormSorteio.idbingosorteios > 0) {
|
||||
this.SalvarSorteio();
|
||||
}
|
||||
else {
|
||||
if (localStorage.getItem("Cartelas") == "") {
|
||||
alert("Gere as cartelas para poder salvar");
|
||||
return;
|
||||
}
|
||||
if (localStorage.getItem("NMax") == "0" || localStorage.getItem("NParticipantes") == "0") {
|
||||
alert("Preencha corretamente os numeros de participantes e cartelas");
|
||||
return;
|
||||
}
|
||||
this.FormSorteio.n_max = parseInt(localStorage.getItem("NMax"));
|
||||
this.FormSorteio.participantes_max = parseInt(localStorage.getItem("NParticipantes"));
|
||||
let CartelasGeradas: CasaCartela[] = JSON.parse(localStorage.getItem("Cartelas"));
|
||||
|
||||
this.FormSorteio.Cartelas = new Array<BingoCartelasModel>();
|
||||
for (let i = 0; i < CartelasGeradas.length; i++) {
|
||||
let Cartela: BingoCartelasModel = new BingoCartelasModel();
|
||||
Cartela.canhoto = this.FormSorteio.Cartelas.length + 1;
|
||||
for (let o = 0; o < this.CartelaNumeros; o++) {
|
||||
if (Cartela.numeros != "")
|
||||
Cartela.numeros += ",";
|
||||
Cartela.numeros += CartelasGeradas[i][o].display;
|
||||
}
|
||||
this.FormSorteio.Cartelas.push(Cartela);
|
||||
}
|
||||
|
||||
console.log(this.FormSorteio);
|
||||
this.SalvarSorteio();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SalvarSorteio() {
|
||||
this.bingoService.SalvarBingoSorteio(this.FormSorteio).then(resSalvar => {
|
||||
if (resSalvar['status'] == 200) {
|
||||
if (this.FormSorteio.idbingosorteios > 0) {
|
||||
alert("Sorteio inserido com sucesso");
|
||||
this.AtualizarDados();
|
||||
}
|
||||
else { // SALVAR AS CARTELAS SE ESTIVER EM MODO DE INSERT
|
||||
this.FormSorteio.idbingosorteios = resSalvar['response']['insertId'];
|
||||
this.bingoService.getAllCartelas().then(resAllCartelas => {
|
||||
for (let i = 0; i < this.FormSorteio.Cartelas.length; i++) {
|
||||
this.FormSorteio.Cartelas[i].canhoto += resAllCartelas.length;
|
||||
}
|
||||
this.bingoService.insertBingoCartela(this.FormSorteio).then(resCartelas => {
|
||||
alert("Sorteio inserido com sucesso");
|
||||
this.AtualizarDados();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("Erro ao inserir Sorteio");
|
||||
console.log(resSalvar['error']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CancelarBingo() {
|
||||
this.FormSorteio = new BingoSorteiosModel();
|
||||
this.Novo = false;
|
||||
this.Editando = false;
|
||||
}
|
||||
|
||||
ExportarCartelas(Sorteio: BingoSorteiosModel) {
|
||||
this.bingoService.exportarExcel(Sorteio).then(resExport => {
|
||||
window.open('http://zendioninc.mooo.com/Jogos/Bingo/Gerador/Cartelas/' + Sorteio.idbingosorteios + '.csv', '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
EditarSorteio(Sorteio: BingoSorteiosModel) {
|
||||
this.FormSorteio = new BingoSorteiosModel();
|
||||
this.FormSorteio.data_sorteio = Sorteio.data_sorteio.split("/")[2] + "-" + Sorteio.data_sorteio.split("/")[1] + "-" + Sorteio.data_sorteio.split("/")[0];
|
||||
this.FormSorteio.descricao = Sorteio.descricao;
|
||||
this.FormSorteio.idbingosorteios = Sorteio.idbingosorteios;
|
||||
this.FormSorteio.n_max = Sorteio.n_max;
|
||||
this.FormSorteio.participantes_max = Sorteio.participantes_max;
|
||||
this.FormSorteio.rodada = Sorteio.rodada;
|
||||
this.FormSorteio.Cartelas = Sorteio.Cartelas;
|
||||
this.FormSorteio.VerCartelas = false;
|
||||
this.Editando = true;
|
||||
}
|
||||
|
||||
RemoverSorteio(Sorteio: BingoSorteiosModel) {
|
||||
if (!confirm("Tem certeza que deseja remover esse sorteio?"))
|
||||
return;
|
||||
|
||||
this.bingoService.deleteBingoSorteio(Sorteio.idbingosorteios).then(resDelete => {
|
||||
alert("Removido com sucesso");
|
||||
this.AtualizarDados();
|
||||
});
|
||||
}
|
||||
|
||||
SalvarCartela(Cartela: BingoCartelasModel) {
|
||||
if (Cartela.Editando) {
|
||||
this.bingoService.updateBingoCartela(Cartela).then(resUpdate => {
|
||||
Cartela.Editando = !Cartela.Editando;
|
||||
});
|
||||
}
|
||||
else {
|
||||
Cartela.Editando = !Cartela.Editando;
|
||||
}
|
||||
}
|
||||
|
||||
Voltar() {
|
||||
this.router.navigate(['dashboard/cliente']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class CasaCartela {
|
||||
display: string;
|
||||
tipo: number;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<div class="FundoCheio" style="font-family: cursive;">
|
||||
<div style="height: calc(100vh - 3em); width: calc(100vw - 2em); text-align: center;">
|
||||
<div class="row col-md-12" *ngIf="!LiberaSorteio">
|
||||
<div class="col-md-12" style="margin-top: 4em;">
|
||||
<h2 class="Cabecalho">SELECIONE O SORTEIO</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<select class="comboBox" [(ngModel)]="SorteioSelecionado.idbingosorteios">
|
||||
<option value="0" disabled>* Selecione um sorteio</option>
|
||||
<option *ngFor="let Sorteio of ListaSorteios" [value]="Sorteio.idbingosorteios">{{Sorteio.descricao}} - Rodada {{Sorteio.rodada}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<button class="btnSorteio" (click)="SelecionarSorteio()">SELECIONAR</button>
|
||||
</div>
|
||||
</div>
|
||||
<iframe [hidden]="!LiberaSorteio" src="http://zendioninc.mooo.com/Jogos/Bingo/index.html" style="border: 1px solid #ddd; border-radius: 1em; height: 100%; width: 90%;"></iframe>
|
||||
</div>
|
||||
|
||||
<div style="height: 2em;">
|
||||
Cartelas faltando 1 numero para bater: {{CartelasParaBater.length}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
.Cabecalho {
|
||||
color: forestgreen;
|
||||
}
|
||||
|
||||
.btnSorteio {
|
||||
background: #90ee90;
|
||||
border-radius: 10em;
|
||||
border: 2px solid forestgreen;
|
||||
width: 10em;
|
||||
height: 3em;
|
||||
font-size: xx-large;
|
||||
color: forestgreen;
|
||||
transition: 0.5s;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.btnSorteio:hover {
|
||||
background: #70c970;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.comboBox {
|
||||
outline: none;
|
||||
padding-left: 1em;
|
||||
height: 3em;
|
||||
width: 25em;
|
||||
font-size: larger;
|
||||
border: 2px solid forestgreen;
|
||||
border-radius: 10em;
|
||||
text-align: center;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { BingoCartelasModel, BingoSorteiosModel } from '../models/bingoModel';
|
||||
import { BingoService } from '../services/bingoService';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bingo-sort',
|
||||
templateUrl: './bingo-sort.component.html',
|
||||
styleUrls: ['./bingo-sort.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class BingoSortComponent implements OnInit {
|
||||
|
||||
Sorteados: string = "";
|
||||
Numeros: number[] = new Array<number>();
|
||||
ListaSorteios: BingoSorteiosModel[] = new Array<BingoSorteiosModel>();
|
||||
LiberaSorteio: boolean = false;
|
||||
SorteioSelecionado: BingoSorteiosModel = new BingoSorteiosModel();
|
||||
CartelasParaBater: BingoCartelasModel[] = new Array<BingoCartelasModel>();
|
||||
Bingo: boolean = false;
|
||||
Cinquina: number = 0;
|
||||
CartelasSorteadas: BingoCartelasModel[] = new Array<BingoCartelasModel>();
|
||||
|
||||
constructor(
|
||||
private bingoService: BingoService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
localStorage.setItem("NumSort", "");
|
||||
this.Numeros = new Array<number>();
|
||||
this.bingoService.getSorteiosRealizar().then(resSorteios => {
|
||||
this.ListaSorteios = resSorteios;
|
||||
});
|
||||
}
|
||||
|
||||
SelecionarSorteio() {
|
||||
for (let i = 0; i < this.ListaSorteios.length; i++) {
|
||||
if (this.ListaSorteios[i].idbingosorteios == this.SorteioSelecionado.idbingosorteios) {
|
||||
this.SorteioSelecionado = this.ListaSorteios[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.bingoService.getCartelasVendidasSorteio(this.SorteioSelecionado.idbingosorteios).then(resCartelas => {
|
||||
this.SorteioSelecionado.Cartelas = resCartelas;
|
||||
this.LiberaSorteio = true;
|
||||
console.log(this.SorteioSelecionado);
|
||||
this.LoopNumeracao();
|
||||
});
|
||||
}
|
||||
|
||||
LoopNumeracao() {
|
||||
setTimeout(() => {
|
||||
if (localStorage.getItem("NumSort") && localStorage.getItem("NumSort") != this.Sorteados) {
|
||||
this.Sorteados = localStorage.getItem("NumSort");
|
||||
const NumVar: string[] = localStorage.getItem("NumSort").split(',');
|
||||
const NumeroAtual: number = parseInt(NumVar[NumVar.length - 1]);
|
||||
this.Numeros.push(NumeroAtual);
|
||||
this.VerificaCartelas(NumeroAtual);
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
if (!this.Bingo)
|
||||
this.LoopNumeracao();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
VerificaCartelas(NSorteado: number) {
|
||||
for (let i = 0; i < this.SorteioSelecionado.Cartelas.length; i++) {
|
||||
let Numeros: string[] = this.SorteioSelecionado.Cartelas[i].numeros.split(',');
|
||||
for (let o = 0; o < Numeros.length; o++) {
|
||||
if (Numeros[o] == NSorteado.toString()) {
|
||||
this.SorteioSelecionado.Cartelas[i].Acertos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.Cinquina < 3 && this.Numeros.length > 3) {
|
||||
this.ConfereCinquina();
|
||||
}
|
||||
|
||||
// CINQUINA 1
|
||||
if (this.Cinquina == 0 && !this.SorteioSelecionado.Cartelas[i].cinquina1 && this.SorteioSelecionado.Cartelas[i].Acertos == 5) {
|
||||
this.SorteioSelecionado.Cartelas[i].cinquina1 = true;
|
||||
this.CartelasSorteadas.push(this.SorteioSelecionado.Cartelas[i]);
|
||||
}
|
||||
|
||||
// CINQUINA 2
|
||||
if (this.Cinquina == 1 && !this.SorteioSelecionado.Cartelas[i].cinquina2 && this.SorteioSelecionado.Cartelas[i].Acertos == 10) {
|
||||
this.SorteioSelecionado.Cartelas[i].cinquina2 = true;
|
||||
this.CartelasSorteadas.push(this.SorteioSelecionado.Cartelas[i]);
|
||||
}
|
||||
|
||||
// CINQUINA 3
|
||||
if (this.Cinquina == 2 && !this.SorteioSelecionado.Cartelas[i].cinquina3 && this.SorteioSelecionado.Cartelas[i].Acertos == 15) {
|
||||
this.SorteioSelecionado.Cartelas[i].cinquina3 = true;
|
||||
this.CartelasSorteadas.push(this.SorteioSelecionado.Cartelas[i]);
|
||||
}
|
||||
|
||||
// CARTELAS COM 1 NUMERO PARA BATER
|
||||
if (this.SorteioSelecionado.Cartelas[i].Acertos == Numeros.length - 1) {
|
||||
let Adicionada: boolean = false;
|
||||
for (let o = 0; o < this.CartelasParaBater.length; o++) {
|
||||
if (this.CartelasParaBater[o].idbingosorteios == this.SorteioSelecionado.Cartelas[i].idbingosorteios) {
|
||||
Adicionada = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Adicionada)
|
||||
this.CartelasParaBater.push(this.SorteioSelecionado.Cartelas[i]);
|
||||
}
|
||||
|
||||
// CARTELA COM QUANTIDADE DE ACERTOS = QUANTIDADE DE NUMEROS, LOGO, BINGO!
|
||||
if (this.SorteioSelecionado.Cartelas[i].Acertos == Numeros.length) {
|
||||
this.SorteioSelecionado.Cartelas[i].bingo = true;
|
||||
this.FinalizaSorteio(true, [this.SorteioSelecionado.Cartelas[i]]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.CartelasSorteadas.length > 0)
|
||||
this.FinalizaSorteio(false, this.CartelasSorteadas);
|
||||
|
||||
}
|
||||
|
||||
FinalizaSorteio(Bingo: boolean, Cartelas: BingoCartelasModel[]) {
|
||||
if (Bingo) { // BINGO
|
||||
this.bingoService.updateBingoCartela(Cartelas[0]).then(resUpdate => {
|
||||
this.SorteioSelecionado.realizado = true;
|
||||
this.SorteioSelecionado.data_sorteio = this.SorteioSelecionado.data_sorteio.replace("T", " ").replace("Z", "");
|
||||
this.bingoService.SalvarBingoSorteio(this.SorteioSelecionado).then(resAtt => {
|
||||
this.Bingo = true;
|
||||
let Mensagem: string = `BINGO!!\r\nCartela: ${Cartelas[0].canhoto} - Ganhador: ${Cartelas[0].nome}\r\nParabens!`;
|
||||
alert(Mensagem);
|
||||
console.log("Cartela vencedora: " + Cartelas[0].canhoto);
|
||||
console.log("Vencedor: " + Cartelas[0].nome);
|
||||
});
|
||||
});
|
||||
}
|
||||
else { // CINQUINAS
|
||||
this.Cinquina++;
|
||||
this.LoopUpdateCinquina(0);
|
||||
}
|
||||
}
|
||||
|
||||
LoopUpdateCinquina(Index: number) {
|
||||
if (Index < this.CartelasSorteadas.length) {
|
||||
this.bingoService.updateBingoCartela(this.CartelasSorteadas[Index]).then(resUpdate => {
|
||||
Index++;
|
||||
this.LoopUpdateCinquina(Index);
|
||||
});
|
||||
}
|
||||
else {
|
||||
let Mensagem: string = "CINQUINA " + this.Cinquina + " sorteada para as seguintes cartelas:\r\n";
|
||||
for (let i = 0; i < this.CartelasSorteadas.length; i++) {
|
||||
Mensagem += `Cartela: ${this.CartelasSorteadas[i].canhoto} - Ganhador: ${this.CartelasSorteadas[i].nome}\r\n`;
|
||||
}
|
||||
Mensagem += "Parabens!!";
|
||||
alert(Mensagem);
|
||||
this.CartelasSorteadas = new Array<BingoCartelasModel>();
|
||||
}
|
||||
}
|
||||
|
||||
ConfereCinquina() {
|
||||
for (let i = 0; i < this.SorteioSelecionado.Cartelas.length; i++) {
|
||||
let CartelaNumeros: string[] = this.SorteioSelecionado.Cartelas[i].numeros.split(",");
|
||||
if (CartelaNumeros.length > 3) {
|
||||
let NIguais: number = 0;
|
||||
for (let o = 0; o < this.Numeros.length; o++) {
|
||||
if (this.SorteioSelecionado.Cartelas[i].numeros.includes(this.Numeros[o].toString())) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<p>bingo works!</p>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bingo',
|
||||
templateUrl: './bingo.component.html',
|
||||
styleUrls: ['./bingo.component.scss']
|
||||
})
|
||||
export class BingoComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
<div class="details-admin-page">
|
||||
|
||||
<!-- LOADING -->
|
||||
<div class="details-loader" *ngIf="!CarregadoSistema || !CarregadoLista">
|
||||
<img src="assets/loader.gif" alt="Carregando">
|
||||
<p>Carregando editor de detalhes...</p>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="CarregadoSistema && CarregadoLista">
|
||||
|
||||
<!-- HERO SISTEMA -->
|
||||
<section class="system-hero">
|
||||
<div class="system-hero-content">
|
||||
|
||||
<div class="system-logo-box">
|
||||
<img
|
||||
[src]="LinkProjeto + '/sistemas/' + Sistema.idsistemas + '/icone.png'"
|
||||
alt="Ícone do sistema"
|
||||
class="system-logo">
|
||||
</div>
|
||||
|
||||
<div class="system-title">
|
||||
<span class="eyebrow">Editor de detalhes</span>
|
||||
|
||||
<h1>{{ Sistema.nome }}</h1>
|
||||
|
||||
<p>{{ Sistema.descricao }}</p>
|
||||
|
||||
<div class="system-tags">
|
||||
<span>Versão {{ Sistema.versaoatual }}</span>
|
||||
<span>{{ Sistema.tiposdesistema }}</span>
|
||||
<span>{{ ListaDetalhes?.length || 0 }} detalhe(s)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- RESUMO -->
|
||||
<section class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">article</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Total de detalhes</span>
|
||||
<strong>{{ ListaDetalhes?.length || 0 }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon active">
|
||||
<i class="material-icons">visibility</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Habilitados</span>
|
||||
<strong>{{ TotalDetalhesHabilitados }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon blocked">
|
||||
<i class="material-icons">visibility_off</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Desabilitados</span>
|
||||
<strong>{{ TotalDetalhesDesabilitados }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- PAINEL PRINCIPAL -->
|
||||
<section class="admin-card details-panel">
|
||||
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Conteúdo da página pública</span>
|
||||
<h2>Detalhes do sistema</h2>
|
||||
<p>
|
||||
Edite os blocos que aparecem na página pública do sistema. Cada detalhe pode ter texto, imagem e status de publicação.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-main" (click)="NovoDetalhe()">
|
||||
<i class="material-icons">note_add</i>
|
||||
Novo detalhe
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- EMPTY -->
|
||||
<div *ngIf="ListaDetalhes.length == 0" class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="material-icons">post_add</i>
|
||||
</div>
|
||||
|
||||
<h3>Nenhum detalhe inserido</h3>
|
||||
|
||||
<p>
|
||||
Clique em “Novo detalhe” para criar o primeiro bloco de apresentação deste sistema.
|
||||
</p>
|
||||
|
||||
<button type="button" class="btn-main empty-btn" (click)="NovoDetalhe()">
|
||||
<i class="material-icons">note_add</i>
|
||||
Criar primeiro detalhe
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- LISTA DETALHES -->
|
||||
<div class="details-list" *ngIf="ListaDetalhes.length > 0">
|
||||
|
||||
<article
|
||||
class="detail-editor-card"
|
||||
*ngFor="let Detalhe of ListaDetalhes; let i = index"
|
||||
[ngClass]="Detalhe.habilitado ? 'enabled' : 'disabled'">
|
||||
|
||||
<div class="detail-card-header">
|
||||
<div class="detail-index">
|
||||
<span>#{{ i + 1 }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-status">
|
||||
<span [ngClass]="Detalhe.habilitado ? 'status-enabled' : 'status-disabled'">
|
||||
{{ Detalhe.habilitado ? 'Habilitado' : 'Desabilitado' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card-body">
|
||||
|
||||
<div class="detail-editor">
|
||||
<label>Descrição / HTML</label>
|
||||
|
||||
<textarea
|
||||
[(ngModel)]="Detalhe.descricao"
|
||||
class="form-control textarea-control"
|
||||
placeholder="Digite o texto deste detalhe. Pode conter HTML simples, como <p>, <strong>, <br>...">
|
||||
</textarea>
|
||||
|
||||
<div class="file-row">
|
||||
<label class="file-label">
|
||||
<i class="material-icons">image</i>
|
||||
Selecionar imagem
|
||||
<input type="file" (change)="onFileChanged($event, i)">
|
||||
</label>
|
||||
|
||||
<small *ngIf="Detalhe.Arquivo">
|
||||
{{ Detalhe.Arquivo.name }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="detail-actions">
|
||||
<button type="button" class="btn-card remove" (click)="RemoverDetalhe(i)">
|
||||
<i class="material-icons">delete</i>
|
||||
Remover
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-card"
|
||||
(click)="HabilitarDetalhe(Detalhe)"
|
||||
[ngClass]="Detalhe.habilitado ? 'disable' : 'enable'">
|
||||
|
||||
<i class="material-icons">
|
||||
{{ Detalhe.habilitado ? 'visibility_off' : 'visibility' }}
|
||||
</i>
|
||||
|
||||
{{ Detalhe.botao }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-preview">
|
||||
<span>Prévia da imagem</span>
|
||||
|
||||
<div class="preview-box">
|
||||
<img
|
||||
*ngIf="Detalhe.imagem"
|
||||
[src]="Detalhe.imagem"
|
||||
alt="Imagem do detalhe">
|
||||
|
||||
<div *ngIf="!Detalhe.imagem" class="preview-empty">
|
||||
<i class="material-icons">image_not_supported</i>
|
||||
<small>Nenhuma imagem selecionada</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- PAINEL INFERIOR -->
|
||||
<section class="secondary-grid">
|
||||
|
||||
<div class="admin-card platform-card">
|
||||
<span class="eyebrow">Disponível para</span>
|
||||
|
||||
<img
|
||||
[src]="LinkProjeto + '/imagens/plataformas/plataforma_' + Sistema.idplataformas + '.png'"
|
||||
alt="Plataforma"
|
||||
class="platform-icon">
|
||||
|
||||
<strong>{{ Sistema.plataforma }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="admin-card update-card">
|
||||
<span class="eyebrow">Notas de atualização</span>
|
||||
|
||||
<small *ngIf="Sistema.update_date">
|
||||
Atualizado em {{ Sistema.update_date | date:'dd/MM/yyyy' }}
|
||||
</small>
|
||||
|
||||
<div [innerHTML]="Sistema.notasdeatualizacao" class="update-text"></div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- SAVE BAR -->
|
||||
<section class="save-bar" *ngIf="ListaDetalhes.length > 0">
|
||||
<div>
|
||||
<strong>Pronto para salvar?</strong>
|
||||
<span>As alterações serão aplicadas na página pública do sistema.</span>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-save" (click)="Salvar()" [disabled]="Salvando">
|
||||
<i class="material-icons">{{ Salvando ? 'hourglass_top' : 'save' }}</i>
|
||||
{{ Salvando ? 'Salvando...' : 'Salvar detalhes' }}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,706 @@
|
|||
.details-admin-page {
|
||||
min-height: calc(100vh - 74px);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* LOADING */
|
||||
|
||||
.details-loader {
|
||||
min-height: 360px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.details-loader img {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
object-fit: contain;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.details-loader p {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
|
||||
.system-hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 22px;
|
||||
padding: 32px;
|
||||
border-radius: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.system-hero::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
right: -120px;
|
||||
top: -120px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.11);
|
||||
}
|
||||
|
||||
.system-hero-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.system-logo-box {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.system-logo {
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.system-hero .eyebrow {
|
||||
color: #bfdbfe;
|
||||
}
|
||||
|
||||
.system-title h1 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #ffffff;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.system-title p {
|
||||
max-width: 760px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.system-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.system-tags span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
/* SUMMARY */
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.summary-icon.active {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.summary-icon.blocked {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.summary-icon .material-icons {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.summary-card span {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.summary-card strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* CARDS */
|
||||
|
||||
.admin-card {
|
||||
padding: 28px;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
|
||||
.details-panel {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 22px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.panel-header h2 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #0f172a;
|
||||
font-size: 26px;
|
||||
line-height: 34px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.panel-header p {
|
||||
max-width: 760px;
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
/* BUTTONS */
|
||||
|
||||
.btn-main,
|
||||
.btn-card,
|
||||
.btn-save {
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-weight: 900;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-main {
|
||||
min-height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 18px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.20);
|
||||
}
|
||||
|
||||
.btn-main:hover,
|
||||
.btn-card:hover,
|
||||
.btn-save:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-main .material-icons,
|
||||
.btn-card .material-icons,
|
||||
.btn-save .material-icons {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
/* EMPTY */
|
||||
|
||||
.empty-state {
|
||||
padding: 42px 20px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px dashed #cbd5e1;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
margin: 0 auto 18px auto;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.empty-icon .material-icons {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
max-width: 560px;
|
||||
margin: 0 auto 22px auto;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
/* DETAIL EDITOR */
|
||||
|
||||
.details-list {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.detail-editor-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.detail-editor-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 7px;
|
||||
height: 100%;
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.detail-editor-card.enabled {
|
||||
border-color: rgba(22, 163, 74, 0.26);
|
||||
background: linear-gradient(90deg, rgba(220, 252, 231, 0.60), #f8fafc 32%);
|
||||
}
|
||||
|
||||
.detail-editor-card.enabled::before {
|
||||
background: #16a34a;
|
||||
}
|
||||
|
||||
.detail-editor-card.disabled {
|
||||
border-color: rgba(220, 38, 38, 0.22);
|
||||
background: linear-gradient(90deg, rgba(254, 226, 226, 0.55), #f8fafc 32%);
|
||||
}
|
||||
|
||||
.detail-editor-card.disabled::before {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.detail-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail-index span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 30px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: #e0f2fe;
|
||||
color: #075985;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.detail-status span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 30px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.status-enabled {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.status-disabled {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.detail-card-body {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 440px;
|
||||
gap: 20px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.detail-editor label,
|
||||
.detail-preview span {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #1e293b;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
border-radius: 14px;
|
||||
border: 1px solid #d7deea;
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #071b63;
|
||||
box-shadow: 0 0 0 4px rgba(7, 27, 99, 0.10);
|
||||
}
|
||||
|
||||
.textarea-control {
|
||||
min-height: 230px;
|
||||
padding: 14px;
|
||||
resize: vertical;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.file-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
min-height: 40px;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5ff;
|
||||
color: #071b63 !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 900 !important;
|
||||
cursor: pointer;
|
||||
border: 1px solid #dbe6ff;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.file-label input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-label .material-icons {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.file-row small {
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.detail-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.btn-card {
|
||||
min-height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 7px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn-card.remove {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.btn-card.enable {
|
||||
background: #15803d;
|
||||
}
|
||||
|
||||
.btn-card.disable {
|
||||
background: #b45309;
|
||||
}
|
||||
|
||||
.detail-preview {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.preview-box {
|
||||
height: 330px;
|
||||
overflow: hidden;
|
||||
border-radius: 18px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dbe6ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview-box img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.preview-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.preview-empty .material-icons {
|
||||
font-size: 42px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* SECONDARY */
|
||||
|
||||
.secondary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 0.75fr 1.25fr;
|
||||
gap: 22px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.platform-card {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.platform-icon {
|
||||
display: block;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: contain;
|
||||
margin: 10px auto 14px auto;
|
||||
}
|
||||
|
||||
.platform-card strong {
|
||||
color: #0f172a;
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.update-card small {
|
||||
display: block;
|
||||
margin-bottom: 14px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.update-text {
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
color: #475569;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
/* SAVE BAR */
|
||||
|
||||
.save-bar {
|
||||
position: sticky;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
padding: 18px 20px;
|
||||
border-radius: 20px;
|
||||
background: rgba(7, 27, 99, 0.96);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.24);
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.save-bar strong {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.save-bar span {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
color: #bfdbfe;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
min-height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 18px;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.btn-save:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.detail-card-body {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.secondary-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.system-hero-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.system-tags {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.btn-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.save-bar {
|
||||
position: static;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.system-hero,
|
||||
.admin-card {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.system-title h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.detail-editor-card {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.preview-box {
|
||||
height: 230px;
|
||||
}
|
||||
|
||||
.detail-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.btn-card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { SistemasDetalhes, SistemasLista } from '../models/sistemasModel';
|
||||
import { SistemasService } from '../services/sistemas.service';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cad-det-sistema',
|
||||
templateUrl: './cad-det-sistema.component.html',
|
||||
styleUrls: ['./cad-det-sistema.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class CadDetSistemaComponent implements OnInit {
|
||||
|
||||
ListaDetalhes: SistemasDetalhes[] = [];
|
||||
Sistema: SistemasLista = new SistemasLista();
|
||||
|
||||
LinkProjeto: string = environment.LinkProjeto;
|
||||
|
||||
CarregadoLista: boolean = false;
|
||||
CarregadoSistema: boolean = false;
|
||||
|
||||
IndexDetalhe: number = 0;
|
||||
ItensNaLista: number = 0;
|
||||
|
||||
Salvando: boolean = false;
|
||||
|
||||
constructor(
|
||||
private sistemasService: SistemasService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.CarregadoLista = false;
|
||||
this.CarregadoSistema = false;
|
||||
this.IndexDetalhe = 0;
|
||||
this.Salvando = false;
|
||||
|
||||
const idSistema = this.route.snapshot.params['idsistemas'];
|
||||
|
||||
this.sistemasService.getSistemaByIDLista(idSistema).then(resSistema => {
|
||||
this.Sistema = resSistema;
|
||||
this.CarregadoSistema = true;
|
||||
});
|
||||
|
||||
this.sistemasService.getDetalhesByID(idSistema).then(resDetalhes => {
|
||||
this.ListaDetalhes = resDetalhes || [];
|
||||
this.ItensNaLista = this.ListaDetalhes.length;
|
||||
|
||||
if (this.ItensNaLista > 0) {
|
||||
this.PreencheLista();
|
||||
} else {
|
||||
this.CarregadoLista = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get TotalDetalhesHabilitados(): number {
|
||||
return (this.ListaDetalhes || []).filter(detalhe => detalhe.habilitado).length;
|
||||
}
|
||||
|
||||
get TotalDetalhesDesabilitados(): number {
|
||||
return (this.ListaDetalhes || []).filter(detalhe => !detalhe.habilitado).length;
|
||||
}
|
||||
|
||||
PreencheLista() {
|
||||
for (let i = 0; i < this.ItensNaLista; i++) {
|
||||
const detalhe = this.ListaDetalhes[i];
|
||||
|
||||
detalhe.botao = detalhe.habilitado ? "Desabilitar" : "Habilitar";
|
||||
|
||||
const ordemImagem = detalhe.ordem != null && detalhe.ordem != undefined ? detalhe.ordem : i;
|
||||
|
||||
detalhe.imagem = this.LinkProjeto +
|
||||
"/sistemas/" +
|
||||
detalhe.idsistemas +
|
||||
"/detalhes/detalhe_" +
|
||||
ordemImagem +
|
||||
".jpg";
|
||||
}
|
||||
|
||||
this.CarregadoLista = true;
|
||||
}
|
||||
|
||||
NovoDetalhe() {
|
||||
const novo = new SistemasDetalhes();
|
||||
|
||||
novo.habilitado = false;
|
||||
novo.idsistemas = this.Sistema.idsistemas;
|
||||
novo.botao = "Habilitar";
|
||||
novo.ordem = this.ListaDetalhes.length;
|
||||
novo.descricao = "";
|
||||
novo.imagem = "";
|
||||
|
||||
this.ListaDetalhes.push(novo);
|
||||
}
|
||||
|
||||
onFileChanged(event, index: number) {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
this.ListaDetalhes[index].Arquivo = event.target.files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.readAsDataURL(event.target.files[0]);
|
||||
|
||||
reader.onload = (event) => {
|
||||
this.ListaDetalhes[index].imagem = <any>event.target['result'];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
RemoverDetalhe(index: number) {
|
||||
if (!confirm("Tem certeza que deseja remover esse item?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const detalhe = this.ListaDetalhes[index];
|
||||
|
||||
if (!detalhe.idsistemasdetalhes) {
|
||||
this.ListaDetalhes.splice(index, 1);
|
||||
this.ReordenarListaLocal();
|
||||
return;
|
||||
}
|
||||
|
||||
this.sistemasService.deleteSistemaDetalhe(detalhe.idsistemasdetalhes, this.Sistema.idsistemas, index).then(resDelete => {
|
||||
if (resDelete['status'] == 200) {
|
||||
this.ListaDetalhes.splice(index, 1);
|
||||
this.ItensNaLista = this.ListaDetalhes.length;
|
||||
this.ReordenarListaLocal();
|
||||
} else {
|
||||
alert("Erro ao remover detalhe");
|
||||
console.log(resDelete);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ReordenarListaLocal() {
|
||||
for (let i = 0; i < this.ListaDetalhes.length; i++) {
|
||||
this.ListaDetalhes[i].ordem = i;
|
||||
}
|
||||
}
|
||||
|
||||
HabilitarDetalhe(Detalhe: SistemasDetalhes) {
|
||||
Detalhe.habilitado = !Detalhe.habilitado;
|
||||
Detalhe.botao = Detalhe.habilitado ? "Desabilitar" : "Habilitar";
|
||||
}
|
||||
|
||||
Salvar() {
|
||||
if (this.Salvando) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.Salvando = true;
|
||||
this.IndexDetalhe = 0;
|
||||
this.SalvarProximo();
|
||||
}
|
||||
|
||||
SalvarProximo() {
|
||||
if (this.IndexDetalhe < this.ListaDetalhes.length) {
|
||||
const Detalhe = new SistemasDetalhes();
|
||||
|
||||
Detalhe.idsistemasdetalhes = this.ListaDetalhes[this.IndexDetalhe].idsistemasdetalhes;
|
||||
Detalhe.habilitado = this.ListaDetalhes[this.IndexDetalhe].habilitado;
|
||||
Detalhe.descricao = this.ListaDetalhes[this.IndexDetalhe].descricao;
|
||||
Detalhe.idsistemas = this.ListaDetalhes[this.IndexDetalhe].idsistemas;
|
||||
Detalhe.ordem = this.IndexDetalhe;
|
||||
|
||||
if (this.IndexDetalhe < this.ItensNaLista) {
|
||||
this.sistemasService.updateDetalhe(Detalhe).then(resUpdate => {
|
||||
if (this.ListaDetalhes[this.IndexDetalhe].Arquivo != null) {
|
||||
this.CopiarImagem(this.IndexDetalhe);
|
||||
}
|
||||
|
||||
this.IndexDetalhe++;
|
||||
this.SalvarProximo();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.sistemasService.insertDetalhe(Detalhe).then(resInsert => {
|
||||
this.ListaDetalhes[this.IndexDetalhe].idsistemasdetalhes = resInsert['response'].insertId;
|
||||
|
||||
if (this.ListaDetalhes[this.IndexDetalhe].Arquivo != null) {
|
||||
this.CopiarImagem(this.IndexDetalhe);
|
||||
}
|
||||
|
||||
this.IndexDetalhe++;
|
||||
this.SalvarProximo();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.sistemasService.atualizarListaDetalhes(this.Sistema.idsistemas).then(resAtualizacao => {
|
||||
console.log("Atualizacao do indice de detalhes:", resAtualizacao);
|
||||
|
||||
alert("Detalhes cadastrados com sucesso!");
|
||||
|
||||
this.IndexDetalhe = 0;
|
||||
this.Salvando = false;
|
||||
this.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
CopiarImagem(index: number) {
|
||||
const req = new XMLHttpRequest();
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("nome", "detalhe_" + this.ListaDetalhes[index].ordem + ".jpg");
|
||||
formData.append("arquivo", this.ListaDetalhes[index].Arquivo);
|
||||
formData.append("idsistemas", this.ListaDetalhes[index].idsistemas.toString());
|
||||
|
||||
req.open("POST", environment.ApiUrl + "/sistemas/copyDetalhe");
|
||||
req.send(formData);
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState === 4) {
|
||||
console.log("Imagem copiada com sucesso");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
<div class="key-page">
|
||||
|
||||
<!-- HERO DO SISTEMA -->
|
||||
<section class="key-hero">
|
||||
<div class="key-hero-content">
|
||||
<div class="system-logo-box" (click)="NavegarSistema()">
|
||||
<img [src]="LinkImagem" alt="Sistema Imagem" class="system-logo">
|
||||
</div>
|
||||
|
||||
<div class="system-title">
|
||||
<span class="eyebrow">Licenças e chaves</span>
|
||||
|
||||
<h1>{{ Sistema.nome }}</h1>
|
||||
|
||||
<p>
|
||||
Gerencie suas chaves de acesso, compre licenças e acompanhe a validade deste sistema.
|
||||
</p>
|
||||
|
||||
<div class="system-tags">
|
||||
<span>Versão {{ Sistema.versaoatual }}</span>
|
||||
<span>Lançamento {{ Sistema.insert_date | date:'dd/MM/yyyy' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- RESUMO -->
|
||||
<section class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">vpn_key</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Chaves geradas</span>
|
||||
<strong>{{ ListaDeChaves?.length || 0 }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">shopping_cart</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Opções de licença</span>
|
||||
<strong>{{ Produtos?.length || 0 }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">verified_user</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Status</span>
|
||||
<strong>Disponível</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- LICENÇAS -->
|
||||
<section class="panel-card license-section">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Comprar licença</span>
|
||||
<h2>Opções disponíveis</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="Produtos != null && Produtos.length > 0" class="license-grid">
|
||||
<article *ngFor="let Produto of Produtos" class="license-card">
|
||||
<div class="license-card-header">
|
||||
<div class="license-icon">
|
||||
<i class="material-icons">workspace_premium</i>
|
||||
</div>
|
||||
|
||||
<span>Licença</span>
|
||||
</div>
|
||||
|
||||
<h3>{{ Produto.descricao }}</h3>
|
||||
|
||||
<div class="license-price">
|
||||
<small>R$</small>
|
||||
<strong>{{ Produto.valor | number:'1.2-2' }}</strong>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Libere uma chave de acesso para utilização do sistema conforme o tipo de licença selecionado.
|
||||
</p>
|
||||
|
||||
<button type="button" class="btn-license" (click)="comprarLicenca(Produto)">
|
||||
Comprar licença
|
||||
</button>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div *ngIf="Produtos != null && Produtos.length == 0" class="empty-state small">
|
||||
<div class="empty-icon">
|
||||
<i class="material-icons">info</i>
|
||||
</div>
|
||||
|
||||
<h3>Nenhuma licença disponível</h3>
|
||||
|
||||
<p>
|
||||
Este sistema não possui versões disponíveis para compra de licenças no momento.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CHAVE DE AVALIAÇÃO -->
|
||||
<section *ngIf="ListaDeChaves != null && ListaDeChaves.length == 0" class="trial-section">
|
||||
<div class="trial-content">
|
||||
<div>
|
||||
<span class="eyebrow">Avaliação</span>
|
||||
<h2>Gerar chave de avaliação</h2>
|
||||
<p>
|
||||
Você ainda não possui chaves para este sistema. Gere uma chave de avaliação para testar o acesso.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-trial" (click)="btnGerarClick()">
|
||||
<i class="material-icons">add_box</i>
|
||||
Gerar chave de avaliação
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CHAVES -->
|
||||
<section class="panel-card keys-section">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Acessos</span>
|
||||
<h2>Chaves do sistema</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="ListaDeChaves != null && ListaDeChaves.length > 0" class="keys-list">
|
||||
<article
|
||||
class="key-card"
|
||||
*ngFor="let Chave of ListaDeChaves"
|
||||
[ngClass]="getKeyCardClass(Chave)">
|
||||
|
||||
<div class="key-status-ribbon">
|
||||
<span>{{ getKeyStatusLabel(Chave) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="key-main">
|
||||
<span class="key-label">Chave de acesso</span>
|
||||
|
||||
<div class="key-value" title="Clique para copiar" (click)="copyToClipboard(Chave.Chave)">
|
||||
<input type="text" readonly [value]="Chave.Chave">
|
||||
<i class="material-icons">content_copy</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="key-meta">
|
||||
<div class="meta-item">
|
||||
<span>Criação</span>
|
||||
<strong>{{ Chave.DataCriacao | date:'dd/MM/yyyy' }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="meta-item">
|
||||
<span>Validade</span>
|
||||
<strong>{{ Chave.DataValidade | date:'dd/MM/yyyy' }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="meta-item">
|
||||
<span>Status</span>
|
||||
<strong>{{ Chave.Status }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="meta-item">
|
||||
<span>Ativada</span>
|
||||
<strong>{{ Chave.Ativada }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div *ngIf="ListaDeChaves != null && ListaDeChaves.length == 0" class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="material-icons">vpn_key_off</i>
|
||||
</div>
|
||||
|
||||
<h3>Nenhuma chave gerada</h3>
|
||||
|
||||
<p>
|
||||
Gere uma chave de avaliação ou compre uma licença para liberar o acesso ao sistema.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,672 @@
|
|||
.key-page {
|
||||
min-height: calc(100vh - 74px);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
|
||||
.key-hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 22px;
|
||||
padding: 32px;
|
||||
border-radius: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.key-hero::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
right: -120px;
|
||||
top: -120px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.11);
|
||||
}
|
||||
|
||||
.key-hero-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.system-logo-box {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.system-logo {
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.system-title {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.key-hero .eyebrow,
|
||||
.trial-section .eyebrow {
|
||||
color: #bfdbfe;
|
||||
}
|
||||
|
||||
.system-title h1 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #ffffff;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.system-title p {
|
||||
max-width: 680px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.system-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.system-tags span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
/* SUMMARY */
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.summary-icon .material-icons {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.summary-card span {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.summary-card strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* PANELS */
|
||||
|
||||
.panel-card {
|
||||
margin-bottom: 22px;
|
||||
padding: 28px;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.panel-header h2 {
|
||||
margin: 0;
|
||||
color: #0f172a;
|
||||
font-size: 26px;
|
||||
line-height: 34px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
/* LICENSES */
|
||||
|
||||
.license-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.license-card {
|
||||
padding: 22px;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.license-card:hover {
|
||||
transform: translateY(-3px);
|
||||
border-color: rgba(7, 27, 99, 0.22);
|
||||
box-shadow: 0 18px 42px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.license-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.license-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.license-card-header span {
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.license-card h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #0f172a;
|
||||
font-size: 20px;
|
||||
line-height: 27px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.license-price {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.license-price small {
|
||||
margin-top: 6px;
|
||||
color: #071b63;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.license-price strong {
|
||||
color: #071b63;
|
||||
font-size: 34px;
|
||||
line-height: 38px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.license-card p {
|
||||
min-height: 68px;
|
||||
margin: 0 0 18px 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.btn-license {
|
||||
width: 100%;
|
||||
min-height: 44px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.20);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-license:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 30px rgba(7, 27, 99, 0.26);
|
||||
}
|
||||
|
||||
/* TRIAL */
|
||||
|
||||
.trial-section {
|
||||
margin-bottom: 22px;
|
||||
padding: 28px;
|
||||
border-radius: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.12), transparent 34%),
|
||||
linear-gradient(145deg, #15803d, #166534);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(21, 128, 61, 0.16);
|
||||
}
|
||||
|
||||
.trial-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.trial-content h2 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #ffffff;
|
||||
font-size: 26px;
|
||||
line-height: 34px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.trial-content p {
|
||||
max-width: 680px;
|
||||
margin: 0;
|
||||
color: #dcfce7;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.btn-trial {
|
||||
min-height: 46px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 18px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
color: #166534;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.16);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-trial:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-trial .material-icons {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* KEYS */
|
||||
|
||||
.keys-list {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.key-card {
|
||||
padding: 20px;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.key-main {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.key-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.key-value {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dbe6ff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.key-value:hover {
|
||||
border-color: rgba(7, 27, 99, 0.28);
|
||||
box-shadow: 0 0 0 4px rgba(7, 27, 99, 0.08);
|
||||
}
|
||||
|
||||
.key-value input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
color: #0f172a;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.key-value .material-icons {
|
||||
color: #071b63;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.key-meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.key-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.key-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 7px;
|
||||
height: 100%;
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.key-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 18px 42px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.key-status-ribbon {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.key-status-ribbon span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
/* Verde: válida e ativada */
|
||||
.key-card-active {
|
||||
background: linear-gradient(90deg, rgba(220, 252, 231, 0.75), #f8fafc 34%);
|
||||
border-color: rgba(22, 163, 74, 0.28);
|
||||
}
|
||||
|
||||
.key-card-active::before {
|
||||
background: #16a34a;
|
||||
}
|
||||
|
||||
.key-card-active .key-status-ribbon span {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
/* Amarelo: válida, mas não ativada */
|
||||
.key-card-pending {
|
||||
background: linear-gradient(90deg, rgba(254, 249, 195, 0.82), #f8fafc 34%);
|
||||
border-color: rgba(202, 138, 4, 0.28);
|
||||
}
|
||||
|
||||
.key-card-pending::before {
|
||||
background: #ca8a04;
|
||||
}
|
||||
|
||||
.key-card-pending .key-status-ribbon span {
|
||||
background: #fef9c3;
|
||||
color: #854d0e;
|
||||
}
|
||||
|
||||
/* Vermelho: expirada/vencida/inválida */
|
||||
.key-card-expired {
|
||||
background: linear-gradient(90deg, rgba(254, 226, 226, 0.82), #f8fafc 34%);
|
||||
border-color: rgba(220, 38, 38, 0.28);
|
||||
}
|
||||
|
||||
.key-card-expired::before {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.key-card-expired .key-status-ribbon span {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
/* Neutra */
|
||||
.key-card-neutral {
|
||||
background: linear-gradient(90deg, rgba(226, 232, 240, 0.72), #f8fafc 34%);
|
||||
border-color: rgba(100, 116, 139, 0.22);
|
||||
}
|
||||
|
||||
.key-card-neutral::before {
|
||||
background: #64748b;
|
||||
}
|
||||
|
||||
.key-card-neutral .key-status-ribbon span {
|
||||
background: #e2e8f0;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.meta-item span {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.meta-item strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* EMPTY */
|
||||
|
||||
.empty-state {
|
||||
padding: 42px 20px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px dashed #cbd5e1;
|
||||
}
|
||||
|
||||
.empty-state.small {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 66px;
|
||||
height: 66px;
|
||||
margin: 0 auto 18px auto;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.empty-icon .material-icons {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
max-width: 520px;
|
||||
margin: 0 auto;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
|
||||
@media (max-width: 1040px) {
|
||||
.license-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.key-meta {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.key-hero-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.system-tags {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.summary-grid,
|
||||
.license-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.trial-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.btn-trial {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.panel-card,
|
||||
.trial-section,
|
||||
.key-hero {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.panel-header h2,
|
||||
.trial-content h2 {
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.system-title h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.key-meta {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.key-value {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.key-value .material-icons {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.license-price strong {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { SistemasService } from '../services/sistemas.service';
|
||||
import { Chaves, Sistemas, ListChaves } from '../models/sistemasModel';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { UsuariosService } from '../services/usuarios.service';
|
||||
import { Usuarios } from '../models/usuariosModel';
|
||||
import { ProdutosService } from '../services/produtosService';
|
||||
import { ProdutosModel } from '../models/produtosModel';
|
||||
|
||||
@Component({
|
||||
selector: 'app-chaves',
|
||||
templateUrl: './chaves.component.html',
|
||||
styleUrls: ['./chaves.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class ChavesComponent implements OnInit {
|
||||
|
||||
FormChaves: Chaves = new Chaves();
|
||||
Sistema: Sistemas = new Sistemas();
|
||||
ListaDeChaves: ListChaves[];
|
||||
Usuario: Usuarios = new Usuarios();
|
||||
UserID: number = parseInt(localStorage.getItem("UserID"));
|
||||
idsistemas: number = this.route.snapshot.params['idsistemas'];
|
||||
LinkImagem: string;
|
||||
Produtos: ProdutosModel[] = [];
|
||||
|
||||
constructor(
|
||||
private sistemasService: SistemasService,
|
||||
private route: ActivatedRoute,
|
||||
private usuariosService: UsuariosService,
|
||||
private router: Router,
|
||||
private produtosService: ProdutosService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.sistemasService.getSistemaByID(this.idsistemas).then(resSistema => {
|
||||
this.Sistema = resSistema;
|
||||
this.LinkImagem = environment.LinkProjeto + "/sistemas/" + this.idsistemas + "/icone.png";
|
||||
});
|
||||
this.usuariosService.getUsuarioByID(this.UserID).then(resUsuario => {
|
||||
this.Usuario = resUsuario;
|
||||
});
|
||||
this.produtosService.getProdutosSell(this.idsistemas).then(resProdutos => {
|
||||
this.Produtos = resProdutos;
|
||||
});
|
||||
this.AtualizaChaves();
|
||||
}
|
||||
|
||||
AtualizaChaves() {
|
||||
this.sistemasService.getChavesSistemaLista(this.idsistemas, this.UserID).then(resChave => {
|
||||
this.ListaDeChaves = resChave;
|
||||
})
|
||||
}
|
||||
|
||||
btnGerarClick() {
|
||||
let Mensagem: string;
|
||||
if (this.ListaDeChaves.length == 0) {
|
||||
Mensagem = "A primeira chave do sistema é gerada gratuitamente com validade de 30 dias a partir de sua data de geração! Deseja gerar sua chave de avaliação agora?";
|
||||
}
|
||||
else {
|
||||
//this.Pagamento = true;
|
||||
//this.GerarChave(30);
|
||||
if (confirm("Deseja solicitar uma nova chave de sistema?")) {
|
||||
this.produtosService.buySistema(this.idsistemas, this.UserID, 1).then(res => {
|
||||
//console.log(res);
|
||||
alert("Você será redirecionado para a tela de pagamentos do Mercado Pago.\rQuando o pagamento for confirmado, a licença será gerada automaticamente e já aparecerá na sua lista de chaves!");
|
||||
const paymentUrl = res['url'];
|
||||
window.open(paymentUrl, '_blank');
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (confirm(Mensagem)) {
|
||||
this.GerarChave(30);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
//this.GerarChave(30);
|
||||
}
|
||||
|
||||
DataValidade(Dias: number) {
|
||||
let DataAtual = new Date();
|
||||
DataAtual.setDate(DataAtual.getDate() + Dias);
|
||||
let DataFix =
|
||||
DataAtual.toLocaleDateString()[0] +
|
||||
DataAtual.toLocaleDateString()[1] +
|
||||
DataAtual.toLocaleDateString()[3] +
|
||||
DataAtual.toLocaleDateString()[4] +
|
||||
DataAtual.toLocaleDateString()[6] +
|
||||
DataAtual.toLocaleDateString()[7] +
|
||||
DataAtual.toLocaleDateString()[8] +
|
||||
DataAtual.toLocaleDateString()[9];
|
||||
return DataFix;
|
||||
}
|
||||
|
||||
GerarChave(Dias: number) {
|
||||
let SerialKey: string;
|
||||
let CPF = this.CryptText(this.Usuario.cpf);
|
||||
let Validade = this.CryptText(this.DataValidade(Dias));
|
||||
SerialKey =
|
||||
Validade[0].toString() +
|
||||
CPF[13].toString() +
|
||||
CPF[0].toString() +
|
||||
Validade[1].toString() +
|
||||
CPF[12].toString() +
|
||||
CPF[1].toString() +
|
||||
Validade[2].toString() +
|
||||
CPF[11].toString() +
|
||||
CPF[2].toString() +
|
||||
Validade[3].toString() +
|
||||
CPF[10].toString() +
|
||||
CPF[3].toString() +
|
||||
Validade[4].toString() +
|
||||
CPF[9].toString() +
|
||||
CPF[4].toString() +
|
||||
Validade[5].toString() +
|
||||
CPF[8].toString() +
|
||||
CPF[5].toString() +
|
||||
Validade[6].toString() +
|
||||
CPF[7].toString() +
|
||||
CPF[6].toString() +
|
||||
Validade[7].toString();
|
||||
|
||||
let DatValidade = new Date();
|
||||
DatValidade.setDate(DatValidade.getDate() + Dias);
|
||||
|
||||
this.FormChaves.licenca = SerialKey;
|
||||
this.FormChaves.idusuarios = this.UserID;
|
||||
this.FormChaves.idsistemas = this.idsistemas;
|
||||
this.FormChaves.data_validade = DatValidade;
|
||||
|
||||
this.sistemasService.insertChave(this.FormChaves).then(resInsert => {
|
||||
if (resInsert['status'] == 200) {
|
||||
alert("Chave de licença gerada com sucesso!");
|
||||
this.AtualizaChaves();
|
||||
}
|
||||
else {
|
||||
alert("Erro ao gerar chave! Por favor tente novamente mais tarde!");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
CryptText(Texto: string)
|
||||
{
|
||||
let RandNumber: number;
|
||||
let NewChar: string;
|
||||
let FinalString: string = "";
|
||||
let SwitchChar: string = "";
|
||||
for (let i = 0; i <= Texto.length; i++)
|
||||
{
|
||||
RandNumber = Math.floor(Math.random() * 2);
|
||||
SwitchChar = Texto.substring(i, 1)[Texto.substring(i, 1).length - 1];
|
||||
if (SwitchChar != undefined) {
|
||||
switch (SwitchChar)
|
||||
{
|
||||
case "0":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "q";
|
||||
else
|
||||
NewChar = "3";
|
||||
break;
|
||||
case "1":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "w";
|
||||
else
|
||||
NewChar = "5";
|
||||
break;
|
||||
case "2":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "r";
|
||||
else
|
||||
NewChar = "4";
|
||||
break;
|
||||
case "3":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "D";
|
||||
else
|
||||
NewChar = "6";
|
||||
break;
|
||||
case "4":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "H";
|
||||
else
|
||||
NewChar = "9";
|
||||
break;
|
||||
case "5":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "b";
|
||||
else
|
||||
NewChar = "7";
|
||||
break;
|
||||
case "6":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "U";
|
||||
else
|
||||
NewChar = "8";
|
||||
break;
|
||||
case "7":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "k";
|
||||
else
|
||||
NewChar = "1";
|
||||
break;
|
||||
case "8":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "I";
|
||||
else
|
||||
NewChar = "0";
|
||||
break;
|
||||
case "9":
|
||||
if (RandNumber == 0)
|
||||
NewChar = "p";
|
||||
else
|
||||
NewChar = "2";
|
||||
break;
|
||||
default:
|
||||
NewChar = "-";
|
||||
break;
|
||||
}
|
||||
FinalString += NewChar;
|
||||
}
|
||||
}
|
||||
return FinalString;
|
||||
}
|
||||
|
||||
|
||||
comprarLicenca(Produto: ProdutosModel) {
|
||||
if (confirm("Deseja solicitar uma nova chave de sistema na versão " + Produto.descricao + "?")) {
|
||||
this.produtosService.buySistema(Produto.idprodutos, this.UserID, 1).then(res => {
|
||||
//console.log(res);
|
||||
if (res['chave'] != null) {
|
||||
alert("Chave gerada com sucesso!");
|
||||
this.AtualizaChaves();
|
||||
}
|
||||
else {
|
||||
alert("Você será redirecionado para a tela de pagamentos do Mercado Pago.\rQuando o pagamento for confirmado, a licença será gerada automaticamente e já aparecerá na sua lista de chaves!");
|
||||
const paymentUrl = res['url'];
|
||||
window.open(paymentUrl, '_blank');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
copyToClipboard(chave: string) {
|
||||
navigator.clipboard.writeText(chave).then(() => {
|
||||
alert("Chave copiada para a área de transferência!");
|
||||
});
|
||||
}
|
||||
|
||||
NavegarSistema() {
|
||||
const url = this.router.serializeUrl(
|
||||
this.router.createUrlTree(['/detalhes/' + this.idsistemas])
|
||||
);
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
getKeyCardClass(Chave: any): string {
|
||||
const hoje = new Date();
|
||||
hoje.setHours(0, 0, 0, 0);
|
||||
|
||||
const validade = new Date(Chave.DataValidade);
|
||||
validade.setHours(0, 0, 0, 0);
|
||||
|
||||
const status = (Chave.Status || '').toString().toLowerCase();
|
||||
const ativada = (Chave.Ativada || '').toString().toLowerCase();
|
||||
|
||||
const expirou = validade < hoje;
|
||||
const estaAtivada =
|
||||
ativada === 'sim' ||
|
||||
ativada === 'true' ||
|
||||
ativada === '1' ||
|
||||
ativada === 'ativada';
|
||||
|
||||
const estaValida =
|
||||
!expirou &&
|
||||
(
|
||||
status.includes('válida') ||
|
||||
status.includes('valid') ||
|
||||
status.includes('ativa') ||
|
||||
status.includes('vigente') ||
|
||||
status === 'ok'
|
||||
);
|
||||
|
||||
//console.log("status: " + status + ", ativada: " + ativada + ", expirou: " + expirou + ", estaAtivada: " + estaAtivada + ", estaValida: " + estaValida)
|
||||
|
||||
if (expirou || status.includes('expir') || status.includes('venc')) {
|
||||
return 'key-card-expired';
|
||||
}
|
||||
|
||||
if (estaValida && estaAtivada) {
|
||||
return 'key-card-active';
|
||||
}
|
||||
|
||||
if (estaValida && !estaAtivada) {
|
||||
return 'key-card-pending';
|
||||
}
|
||||
|
||||
return 'key-card-neutral';
|
||||
}
|
||||
|
||||
getKeyStatusLabel(Chave: any): string {
|
||||
const cardClass = this.getKeyCardClass(Chave);
|
||||
|
||||
if (cardClass === 'key-card-expired') {
|
||||
return 'Expirada';
|
||||
}
|
||||
|
||||
if (cardClass === 'key-card-active') {
|
||||
return 'Válida e ativada';
|
||||
}
|
||||
|
||||
if (cardClass === 'key-card-pending') {
|
||||
return 'Válida, aguardando ativação';
|
||||
}
|
||||
|
||||
return 'Status indefinido';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
<div class="client-page">
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="client-hero">
|
||||
<div class="client-hero-text">
|
||||
<span class="eyebrow">Área do cliente</span>
|
||||
|
||||
<h1>Bem-vindo, {{ NomeUsuario }}!</h1>
|
||||
|
||||
<p>
|
||||
Gerencie seus sistemas, acompanhe suas licenças e gere chaves de acesso em um só lugar.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="client-hero-card">
|
||||
<span>Sistemas ativos</span>
|
||||
<strong>{{ SistemasDoUsuario?.length || 0 }}</strong>
|
||||
<small>Disponíveis na sua conta</small>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SUMMARY -->
|
||||
<section class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">apps</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Total de sistemas</span>
|
||||
<strong>{{ SistemasDoUsuario?.length || 0 }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">vpn_key</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Chaves válidas</span>
|
||||
<strong>{{ TotalChavesValidas }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">verified_user</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Status</span>
|
||||
<strong>Ativo</strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SISTEMAS -->
|
||||
<section class="systems-panel" *ngIf="JanelaModo.Visualizar">
|
||||
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Meus sistemas</span>
|
||||
<h2>Soluções vinculadas à sua conta</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="SistemasDoUsuario && SistemasDoUsuario.length > 0" class="client-systems-grid">
|
||||
|
||||
<article class="client-system-card" *ngFor="let Sistema of SistemasDoUsuario">
|
||||
|
||||
<div class="system-card-top">
|
||||
<div class="system-logo-box" (click)="NavegarSistema(Sistema.idsistemas)">
|
||||
<img
|
||||
[src]="LinkImagem(Sistema.idsistemas)"
|
||||
alt="Ícone do sistema"
|
||||
class="system-logo">
|
||||
</div>
|
||||
|
||||
<div class="system-title-block">
|
||||
<h3>{{ Sistema.nome }}</h3>
|
||||
|
||||
<span class="system-status">
|
||||
{{ Sistema.gratis ? 'Gratuito' : 'Licenciado' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="system-description">
|
||||
{{ Sistema.descricao }}
|
||||
</p>
|
||||
|
||||
<div class="system-meta-grid">
|
||||
<div class="meta-item">
|
||||
<span>Data download</span>
|
||||
<strong>{{ Sistema.data_download | date:'dd/MM/yyyy' }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="meta-item">
|
||||
<span>Chaves válidas</span>
|
||||
<strong>{{ Sistema.chavesValidas }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="system-actions">
|
||||
<button
|
||||
*ngIf="!Sistema.gratis"
|
||||
type="button"
|
||||
class="btn-card btn-key"
|
||||
(click)="GerarChave(Sistema)">
|
||||
|
||||
<i class="material-icons">add</i>
|
||||
Gerar chave
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-card btn-details"
|
||||
(click)="NavegarSistema(Sistema.idsistemas)">
|
||||
|
||||
<i class="material-icons">open_in_new</i>
|
||||
Detalhes
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-card btn-remove"
|
||||
(click)="RemoverSistema(Sistema)">
|
||||
|
||||
<i class="material-icons">delete</i>
|
||||
Remover
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="!SistemasDoUsuario || SistemasDoUsuario.length == 0" class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="material-icons">inventory_2</i>
|
||||
</div>
|
||||
|
||||
<h3>Nenhum sistema vinculado ainda</h3>
|
||||
|
||||
<p>
|
||||
Você ainda não possui sistemas na sua conta. Acesse a página inicial para conhecer as soluções disponíveis.
|
||||
</p>
|
||||
|
||||
<button type="button" class="btn-empty" (click)="router.navigate(['/home'])">
|
||||
Conhecer sistemas
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,452 @@
|
|||
.client-page {
|
||||
min-height: calc(100vh - 74px);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
|
||||
.client-hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 230px;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
margin-bottom: 22px;
|
||||
padding: 32px;
|
||||
border-radius: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.client-hero::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
right: -120px;
|
||||
top: -120px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.11);
|
||||
}
|
||||
|
||||
.client-hero-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.client-hero .eyebrow {
|
||||
color: #bfdbfe;
|
||||
}
|
||||
|
||||
.client-hero h1 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #ffffff;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.client-hero p {
|
||||
max-width: 660px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.client-hero-card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 22px;
|
||||
border-radius: 22px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.client-hero-card span,
|
||||
.client-hero-card small {
|
||||
display: block;
|
||||
color: #bfdbfe;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.client-hero-card strong {
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
color: #ffffff;
|
||||
font-size: 42px;
|
||||
line-height: 46px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* SUMMARY */
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.summary-icon .material-icons {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.summary-card span {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.summary-card strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* PANEL */
|
||||
|
||||
.systems-panel {
|
||||
padding: 28px;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.panel-header h2 {
|
||||
margin: 0;
|
||||
color: #0f172a;
|
||||
font-size: 26px;
|
||||
line-height: 34px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
/* SYSTEM CARDS */
|
||||
|
||||
.client-systems-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.client-system-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 280px;
|
||||
padding: 22px;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.client-system-card:hover {
|
||||
transform: translateY(-3px);
|
||||
border-color: rgba(7, 27, 99, 0.22);
|
||||
box-shadow: 0 18px 42px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.system-card-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.system-logo-box {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dbe6ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.system-logo {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.system-title-block {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.system-title-block h3 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #0f172a;
|
||||
font-size: 20px;
|
||||
line-height: 27px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.system-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: #e0f2fe;
|
||||
color: #075985;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.system-description {
|
||||
flex: 1;
|
||||
margin: 0 0 18px 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.system-meta-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
padding: 14px;
|
||||
border-radius: 16px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.meta-item span {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #64748b;
|
||||
font-size: 11px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.meta-item strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.system-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn-card {
|
||||
min-height: 40px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 7px;
|
||||
padding: 0 14px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-card .material-icons {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.btn-card:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-key {
|
||||
background: #15803d;
|
||||
box-shadow: 0 10px 20px rgba(21, 128, 61, 0.20);
|
||||
}
|
||||
|
||||
.btn-details {
|
||||
background: #071b63;
|
||||
box-shadow: 0 10px 20px rgba(7, 27, 99, 0.20);
|
||||
}
|
||||
|
||||
.btn-remove {
|
||||
background: #dc2626;
|
||||
box-shadow: 0 10px 20px rgba(220, 38, 38, 0.18);
|
||||
}
|
||||
|
||||
/* EMPTY */
|
||||
|
||||
.empty-state {
|
||||
padding: 42px 20px;
|
||||
text-align: center;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px dashed #cbd5e1;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
margin: 0 auto 18px auto;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.empty-icon .material-icons {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 22px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
max-width: 520px;
|
||||
margin: 0 auto 22px auto;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.btn-empty {
|
||||
min-height: 44px;
|
||||
padding: 0 18px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: #071b63;
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.client-hero {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.client-hero-card {
|
||||
max-width: 260px;
|
||||
}
|
||||
|
||||
.client-systems-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.summary-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.systems-panel {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.panel-header h2 {
|
||||
font-size: 22px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.system-meta-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.system-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.btn-card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.client-hero {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.client-hero h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.client-system-card {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.system-card-top {
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { UsuariosService } from '../services/usuarios.service';
|
||||
import { SistemasDoUsuario } from '../models/usuariosModel';
|
||||
import { Modos } from '../models/variaveisModel';
|
||||
import { Router } from '@angular/router';
|
||||
import { SistemasService } from '../services/sistemas.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-client',
|
||||
templateUrl: './client.component.html',
|
||||
styleUrls: ['./client.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class ClientComponent implements OnInit {
|
||||
|
||||
NomeUsuario: string = localStorage.getItem("UserName") || "Usuário";
|
||||
idusuarios: number = parseInt(localStorage.getItem("UserID") || "0");
|
||||
|
||||
SistemasDoUsuario: SistemasDoUsuario[] = [];
|
||||
|
||||
JanelaModo: Modos = new Modos();
|
||||
|
||||
constructor(
|
||||
private usuariosService: UsuariosService,
|
||||
private sistemasService: SistemasService,
|
||||
public router: Router
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.JanelaModo.Visualizar = true;
|
||||
this.CarregarSistemas();
|
||||
}
|
||||
|
||||
get TotalChavesValidas(): number {
|
||||
if (!this.SistemasDoUsuario) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.SistemasDoUsuario.reduce((total, sistema) => {
|
||||
return total + Number(sistema["chavesValidas"] || 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
CarregarSistemas() {
|
||||
this.usuariosService.getSistemasDoUsuario(this.idusuarios).then(resSistemas => {
|
||||
this.SistemasDoUsuario = resSistemas || [];
|
||||
});
|
||||
}
|
||||
|
||||
GerarChave(Sistema: SistemasDoUsuario) {
|
||||
this.router.navigate(['dashboard/cliente/chave/' + Sistema.idsistemas]);
|
||||
}
|
||||
|
||||
RemoverSistema(Sistema: SistemasDoUsuario) {
|
||||
if (confirm("Tem certeza que deseja remover esse sistema de sua lista?")) {
|
||||
this.sistemasService.deleteSistemaUsuario(Sistema.idsistemas, Sistema.idusuarios).then(resDelete => {
|
||||
this.SistemasDoUsuario = this.SistemasDoUsuario.filter(item => item.idsistemas !== Sistema.idsistemas);
|
||||
alert("Sistema removido com sucesso!");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LinkImagem(idsistemas: number): string {
|
||||
return environment.LinkProjeto + "/sistemas/" + idsistemas + "/icone.png";
|
||||
}
|
||||
|
||||
NavegarSistema(idsistemas: number) {
|
||||
this.router.navigate(['detalhes/' + idsistemas]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<div class="register-page">
|
||||
<div class="register-shell">
|
||||
|
||||
<div class="register-brand-panel">
|
||||
<div class="brand-content">
|
||||
<img src="assets/logo_escrito.png" alt="Zendion, INC." class="brand-logo">
|
||||
|
||||
<h1>Crie sua conta</h1>
|
||||
|
||||
<p>
|
||||
Acesse os sistemas da Zendion, INC. com segurança e acompanhe suas soluções em um só lugar.
|
||||
</p>
|
||||
|
||||
<div class="brand-badges">
|
||||
<span>Conta segura</span>
|
||||
<span>Ativação por e-mail</span>
|
||||
<span>Acesso rápido</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="register-card">
|
||||
<div class="register-header">
|
||||
<span class="eyebrow">Cadastro</span>
|
||||
<h2>{{ TituloJanela }}</h2>
|
||||
<p *ngIf="!Sucesso">
|
||||
Preencha seus dados para criar sua conta. Depois enviaremos um link de ativação para seu e-mail.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="register-body">
|
||||
|
||||
<div *ngIf="!Sucesso" class="register-form">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="nome">Nome completo</label>
|
||||
<input
|
||||
id="nome"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Digite seu nome"
|
||||
[(ngModel)]="FormUsuario.nome"
|
||||
(change)="MensagemForm = ''">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">E-mail</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
placeholder="seuemail@exemplo.com"
|
||||
[(ngModel)]="FormUsuario.email"
|
||||
(change)="MensagemForm = ''">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cpf">CPF</label>
|
||||
<input
|
||||
id="cpf"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="000.000.000-00"
|
||||
[(ngModel)]="FormUsuario.cpf"
|
||||
maxlength="14"
|
||||
(keyup)="MascaraCPF($event)"
|
||||
(change)="MensagemForm = ''">
|
||||
|
||||
<small class="field-hint" *ngIf="FormUsuario.cpf && !CPFValido">
|
||||
Digite um CPF válido para liberar o cadastro.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="usuario">Usuário</label>
|
||||
<input
|
||||
id="usuario"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Escolha um nome de usuário"
|
||||
[(ngModel)]="FormUsuario.usuario"
|
||||
(change)="MensagemForm = ''">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="senha">Senha</label>
|
||||
<input
|
||||
id="senha"
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="Crie uma senha"
|
||||
[(ngModel)]="FormUsuario.senha"
|
||||
(change)="MensagemForm = ''">
|
||||
</div>
|
||||
|
||||
<div *ngIf="MensagemForm != ''" class="register-message">
|
||||
<small>{{ MensagemForm }}</small>
|
||||
</div>
|
||||
|
||||
<button
|
||||
[disabled]="!CPFValido"
|
||||
type="submit"
|
||||
class="btn-register"
|
||||
(click)="btnCriarcontaClick()">
|
||||
{{ TextoBotao }}
|
||||
</button>
|
||||
|
||||
<p class="terms-text">
|
||||
Ao criar sua conta, você confirma que seus dados estão corretos e aceita receber o e-mail de ativação.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div *ngIf="Sucesso" class="success-box">
|
||||
<div class="success-icon">✓</div>
|
||||
|
||||
<h3>Cadastro criado com sucesso</h3>
|
||||
|
||||
<p>
|
||||
Enviamos um link de ativação para o seu e-mail. Verifique sua caixa de entrada e também a pasta de spam.
|
||||
</p>
|
||||
|
||||
<button type="button" class="btn-register" (click)="btnCriarcontaClick()">
|
||||
{{ TextoBotao }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="register-footer">
|
||||
<a [routerLink]="'/home'">Voltar ao site</a>
|
||||
<span></span>
|
||||
<a [routerLink]="'/login'">Já tenho conta</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
.register-page {
|
||||
min-height: calc(100vh - 80px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 18px;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(7, 27, 99, 0.14), transparent 34%),
|
||||
linear-gradient(135deg, #f4f6fb 0%, #eef3ff 45%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.register-shell {
|
||||
width: 100%;
|
||||
max-width: 1040px;
|
||||
display: grid;
|
||||
grid-template-columns: 0.95fr 1.05fr;
|
||||
background: #ffffff;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.16);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.register-brand-panel {
|
||||
position: relative;
|
||||
min-height: 620px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 42px;
|
||||
background:
|
||||
linear-gradient(145deg, rgba(7, 27, 99, 0.96), rgba(18, 47, 132, 0.94)),
|
||||
url('/assets/logo_escrito.png');
|
||||
color: #ffffff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.register-brand-panel::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 340px;
|
||||
height: 340px;
|
||||
right: -120px;
|
||||
top: -100px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.register-brand-panel::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
left: -80px;
|
||||
bottom: -70px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.brand-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 54px;
|
||||
max-width: 240px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
margin-bottom: 34px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.brand-content h1 {
|
||||
margin: 0 0 14px 0;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.brand-content p {
|
||||
max-width: 390px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.brand-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.brand-badges span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.13);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.register-card {
|
||||
padding: 44px 48px;
|
||||
}
|
||||
|
||||
.register-header {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.register-header h2 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 30px;
|
||||
line-height: 38px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.register-header p {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.register-body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 7px;
|
||||
color: #1e293b;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d7deea;
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
font-size: 15px;
|
||||
outline: none;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control::placeholder {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #071b63;
|
||||
box-shadow: 0 0 0 4px rgba(7, 27, 99, 0.10);
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.field-hint {
|
||||
display: block;
|
||||
margin-top: 7px;
|
||||
color: #b45309;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.btn-register {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
margin-top: 6px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.22);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-register:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 30px rgba(7, 27, 99, 0.28);
|
||||
}
|
||||
|
||||
.btn-register:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-register:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.terms-text {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 19px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.register-footer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-top: 26px;
|
||||
padding-top: 22px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.register-footer span {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 999px;
|
||||
background: #cbd5e1;
|
||||
}
|
||||
|
||||
.register-footer a {
|
||||
color: #071b63;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.register-footer a:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.register-footer a:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.register-footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.register-message {
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
background: #fef2f2;
|
||||
border: 1px solid #fecaca;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.register-message small {
|
||||
display: block;
|
||||
color: #b91c1c;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.success-box {
|
||||
text-align: center;
|
||||
padding: 18px 0 4px 0;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 0 auto 18px auto;
|
||||
border-radius: 999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #dcfce7;
|
||||
color: #15803d;
|
||||
font-size: 34px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.success-box h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.success-box p {
|
||||
margin: 0 0 24px 0;
|
||||
color: #64748b;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.register-shell {
|
||||
grid-template-columns: 1fr;
|
||||
max-width: 560px;
|
||||
}
|
||||
|
||||
.register-brand-panel {
|
||||
min-height: auto;
|
||||
padding: 30px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 44px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.brand-content h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.register-card {
|
||||
padding: 34px 26px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.register-page {
|
||||
padding: 22px 12px;
|
||||
}
|
||||
|
||||
.register-shell {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.register-brand-panel {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.brand-badges {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.register-card {
|
||||
padding: 28px 20px;
|
||||
}
|
||||
|
||||
.register-header h2 {
|
||||
font-size: 25px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.register-footer {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.register-footer span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.register-footer a,
|
||||
.register-footer a:first-child,
|
||||
.register-footer a:last-child {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Usuarios, Email } from '../models/usuariosModel';
|
||||
import { UsuariosService } from '../services/usuarios.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-criarconta',
|
||||
templateUrl: './criarconta.component.html',
|
||||
styleUrls: ['./criarconta.component.scss']
|
||||
})
|
||||
export class CriarcontaComponent implements OnInit {
|
||||
|
||||
FormUsuario: Usuarios = new Usuarios();
|
||||
ListUsuarios: Usuarios[];
|
||||
MensagemForm: String;
|
||||
TituloJanela: String = "Cadastre-se";
|
||||
TextoBotao: String = "Criar conta";
|
||||
FormEmail: Email = new Email();
|
||||
Sucesso: boolean = false;
|
||||
CPFValido: boolean = false;
|
||||
|
||||
constructor(
|
||||
private usuariosSerivce: UsuariosService,
|
||||
private router: Router,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.FormUsuario.idtiposdeusuario = 2;
|
||||
this.FormUsuario.habilitado = false;
|
||||
this.ListUsuarios = [];
|
||||
|
||||
this.usuariosSerivce.getUsuarios().then(resUsuarios => {
|
||||
this.ListUsuarios = resUsuarios || [];
|
||||
});
|
||||
}
|
||||
|
||||
EnviarEmail(link: string) {
|
||||
const nomeUsuario = this.FormUsuario.nome || 'usuário';
|
||||
|
||||
const text = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ativação de conta Zendion, INC.</title>
|
||||
</head>
|
||||
<body style="margin:0; padding:0; background-color:#f4f6fb; font-family:Arial, Helvetica, sans-serif; color:#1f2937;">
|
||||
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f6fb; padding:32px 12px;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="max-width:620px; background-color:#ffffff; border-radius:14px; overflow:hidden; box-shadow:0 6px 24px rgba(15, 23, 42, 0.08);">
|
||||
|
||||
<!-- Header -->
|
||||
<tr>
|
||||
<td style="background-color:#071b63; padding:26px 32px; text-align:center;">
|
||||
<img src="https://zendioninc.com.br/assets/logo_escrito.png" alt="Zendion, INC." style="height:54px; max-width:220px; display:inline-block;">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Title -->
|
||||
<tr>
|
||||
<td style="padding:34px 34px 10px 34px; text-align:left;">
|
||||
<h1 style="margin:0; color:#111827; font-size:24px; line-height:32px; font-weight:700;">
|
||||
Olá, ${nomeUsuario}!
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Content -->
|
||||
<tr>
|
||||
<td style="padding:8px 34px 0 34px;">
|
||||
<p style="margin:0 0 18px 0; font-size:16px; line-height:26px; color:#374151;">
|
||||
Sua conta na <strong>Zendion, INC.</strong> foi criada com sucesso.
|
||||
</p>
|
||||
|
||||
<p style="margin:0 0 24px 0; font-size:16px; line-height:26px; color:#374151;">
|
||||
Para ativar sua conta e começar a usar o sistema, clique no botão abaixo:
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Button -->
|
||||
<tr>
|
||||
<td align="center" style="padding:8px 34px 30px 34px;">
|
||||
<a href="${link}" target="_blank" style="display:inline-block; background-color:#071b63; color:#ffffff; text-decoration:none; font-size:16px; font-weight:700; padding:14px 28px; border-radius:8px;">
|
||||
Ativar minha conta
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Fallback link -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 30px 34px;">
|
||||
<p style="margin:0 0 8px 0; font-size:13px; line-height:21px; color:#6b7280;">
|
||||
Se o botão não funcionar, copie e cole este link no navegador:
|
||||
</p>
|
||||
|
||||
<p style="margin:0; font-size:13px; line-height:21px; word-break:break-all;">
|
||||
<a href="${link}" target="_blank" style="color:#071b63; text-decoration:underline;">
|
||||
${link}
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Security note -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 32px 34px;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f8fafc; border-left:4px solid #071b63; border-radius:8px;">
|
||||
<tr>
|
||||
<td style="padding:16px 18px;">
|
||||
<p style="margin:0; font-size:14px; line-height:22px; color:#4b5563;">
|
||||
Se você não criou uma conta na Zendion, INC., ignore este e-mail.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Signature -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 32px 34px;">
|
||||
<p style="margin:0; font-size:15px; line-height:24px; color:#374151;">
|
||||
Atenciosamente,<br>
|
||||
<strong>Equipe Zendion, INC.</strong>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr>
|
||||
<td style="background-color:#071b63; padding:22px 34px; text-align:center;">
|
||||
<p style="margin:0 0 8px 0; font-size:13px; line-height:20px; color:#ffffff;">
|
||||
Zendion, INC.
|
||||
</p>
|
||||
|
||||
<p style="margin:0; font-size:12px; line-height:20px; color:#cbd5e1;">
|
||||
+55 19 99871-7560<br>
|
||||
contato@zendioninc.com.br<br>
|
||||
<a href="https://zendioninc.com.br" target="_blank" style="color:#ffffff; text-decoration:none;">
|
||||
zendioninc.com.br
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<!-- Legal bottom -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="max-width:620px;">
|
||||
<tr>
|
||||
<td style="padding:18px 12px 0 12px; text-align:center;">
|
||||
<p style="margin:0; font-size:11px; line-height:18px; color:#9ca3af;">
|
||||
Este é um e-mail automático. Por favor, não responda esta mensagem.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
this.FormEmail.Assunto = 'Ative sua conta na Zendion, INC.';
|
||||
this.FormEmail.Conteudo = text;
|
||||
this.FormEmail.Para = this.FormUsuario.email;
|
||||
|
||||
this.usuariosSerivce.EnviarEmail(this.FormEmail).then(response => {
|
||||
this.Sucesso = true;
|
||||
this.TextoBotao = "Voltar ao site";
|
||||
|
||||
if (response != null && response["sucesso"] == true) {
|
||||
this.TituloJanela = "Um link de ativação foi enviado para seu e-mail. Verifique sua caixa de entrada para ativar sua conta!";
|
||||
} else {
|
||||
this.TituloJanela = "Ocorreu um erro ao enviar o link de ativação para seu endereço de e-mail. Verifique suas informações ou entre em contato com o administrador do sistema.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
btnCriarcontaClick() {
|
||||
if (this.TextoBotao == "Voltar ao site") {
|
||||
this.router.navigate(['home']);
|
||||
return;
|
||||
}
|
||||
|
||||
this.MensagemForm = "";
|
||||
|
||||
if (!this.FormUsuario.nome || this.FormUsuario.nome.trim() == "") {
|
||||
this.MensagemForm = "O campo nome é obrigatório.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.FormUsuario.email || this.FormUsuario.email.trim() == "") {
|
||||
this.MensagemForm = "O campo e-mail é obrigatório.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.FormUsuario.cpf || this.FormUsuario.cpf.trim() == "") {
|
||||
this.MensagemForm = "O campo CPF é obrigatório.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.CPFValido) {
|
||||
this.MensagemForm = "Digite um CPF válido para continuar.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.FormUsuario.usuario || this.FormUsuario.usuario.trim() == "") {
|
||||
this.MensagemForm = "O campo usuário é obrigatório.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.FormUsuario.senha || this.FormUsuario.senha.trim() == "") {
|
||||
this.MensagemForm = "O campo senha é obrigatório.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ListUsuarios && this.ListUsuarios.length > 0) {
|
||||
for (let i = 0; i < this.ListUsuarios.length; i++) {
|
||||
if (this.ListUsuarios[i].usuario == this.FormUsuario.usuario) {
|
||||
this.MensagemForm = "Nome de usuário indisponível.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ListUsuarios[i].email == this.FormUsuario.email) {
|
||||
this.MensagemForm = "Este e-mail já está cadastrado.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ListUsuarios[i].cpf == this.FormUsuario.cpf) {
|
||||
this.MensagemForm = "Este CPF já está cadastrado.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.usuariosSerivce.insertUsuarios(this.FormUsuario).then(resInsert => {
|
||||
if (resInsert['status'] == 200) {
|
||||
this.EnviarEmail(environment.ApiUrl + "/users/ativarUsuario/" + resInsert['response'].insertId);
|
||||
} else {
|
||||
this.MensagemForm = "Erro ao criar usuário.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MascaraCPF(event: KeyboardEvent): void {
|
||||
|
||||
if (!((event.keyCode >= 48 && event.keyCode <= 58) || (event.keyCode >= 96 && event.keyCode <= 106))) {
|
||||
if (event.keyCode == 8 || (event.keyCode >= 37 && event.keyCode <= 40) || event.keyCode == 46) {
|
||||
return;
|
||||
}
|
||||
this.FormUsuario.cpf = this.FormUsuario.cpf.substr(0, this.FormUsuario.cpf.length - 1);
|
||||
}
|
||||
if (this.FormUsuario.cpf.length == 3 || this.FormUsuario.cpf.length == 7)
|
||||
this.FormUsuario.cpf += ".";
|
||||
if (this.FormUsuario.cpf.length == 11)
|
||||
this.FormUsuario.cpf += "-";
|
||||
if (this.FormUsuario.cpf.length == 14)
|
||||
this.ValidaCPF();
|
||||
}
|
||||
|
||||
ValidaCPF() {
|
||||
const cpf =
|
||||
this.FormUsuario.cpf[0] +
|
||||
this.FormUsuario.cpf[1] +
|
||||
this.FormUsuario.cpf[2] +
|
||||
this.FormUsuario.cpf[4] +
|
||||
this.FormUsuario.cpf[5] +
|
||||
this.FormUsuario.cpf[6] +
|
||||
this.FormUsuario.cpf[8] +
|
||||
this.FormUsuario.cpf[9] +
|
||||
this.FormUsuario.cpf[10] +
|
||||
this.FormUsuario.cpf[12] +
|
||||
this.FormUsuario.cpf[13];
|
||||
if (cpf) {
|
||||
let numbers, digits, sum, i, result, equalDigits;
|
||||
equalDigits = 1;
|
||||
if (cpf.length < 11) {
|
||||
this.CPFValido = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
for (i = 0; i < cpf.length - 1; i++) {
|
||||
if (cpf.charAt(i) !== cpf.charAt(i + 1)) {
|
||||
equalDigits = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!equalDigits) {
|
||||
numbers = cpf.substring(0, 9);
|
||||
digits = cpf.substring(9);
|
||||
sum = 0;
|
||||
for (i = 10; i > 1; i--) {
|
||||
sum += numbers.charAt(10 - i) * i;
|
||||
}
|
||||
|
||||
result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
||||
|
||||
if (result !== Number(digits.charAt(0))) {
|
||||
this.CPFValido = false;
|
||||
this.MensagemForm = "CPF digitado é inválido!";
|
||||
return { cpfNotValid: true };
|
||||
}
|
||||
numbers = cpf.substring(0, 10);
|
||||
sum = 0;
|
||||
|
||||
for (i = 11; i > 1; i--) {
|
||||
sum += numbers.charAt(11 - i) * i;
|
||||
}
|
||||
result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
|
||||
|
||||
if (result !== Number(digits.charAt(1))) {
|
||||
this.CPFValido = false;
|
||||
this.MensagemForm = "CPF digitado é inválido!";
|
||||
return { cpfNotValid: true };
|
||||
}
|
||||
this.CPFValido = true;
|
||||
this.MensagemForm = "";
|
||||
return null;
|
||||
} else {
|
||||
this.CPFValido = false;
|
||||
this.MensagemForm = "CPF digitado é inválido!";
|
||||
return { cpfNotValid: true };
|
||||
}
|
||||
}
|
||||
this.MensagemForm = "";
|
||||
this.CPFValido = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<div class="dashboard-layout">
|
||||
|
||||
<!-- HEADER -->
|
||||
<header class="dashboard-header">
|
||||
<div class="header-left">
|
||||
<a [routerLink]="'/home'" class="brand-link">
|
||||
<img src="assets/logo_escrito.png" class="logo logo-escrito" alt="Zendion, INC.">
|
||||
<img src="assets/logo.png" class="logo logo-favicon" alt="Zendion, INC.">
|
||||
</a>
|
||||
|
||||
<div class="header-divider"></div>
|
||||
|
||||
<div class="header-title">
|
||||
<span>Painel</span>
|
||||
<strong>Zendion, INC.</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<div class="user-pill">
|
||||
<i class="material-icons">account_circle</i>
|
||||
<span>{{UserName || 'Usuário'}}</span>
|
||||
</div>
|
||||
|
||||
<button type="button" class="logout-btn" (click)="Sair()" title="Sair">
|
||||
<i class="material-icons">exit_to_app</i>
|
||||
<span>Sair</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- SIDEBAR -->
|
||||
<aside *ngIf="BotoesMenuLateral.length > 0" class="dashboard-sidebar">
|
||||
<div class="sidebar-title">
|
||||
<span>Menu</span>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<div *ngFor="let Botao of BotoesMenuLateral; let i = index" class="menu-item">
|
||||
|
||||
<button class="dropdown-btn" type="button" (click)="DropMenuItem(Botao.index)">
|
||||
<span class="menu-main">
|
||||
<i class="material-icons menu-icon">{{Botao.icon}}</i>
|
||||
<span>{{Botao.texto}}</span>
|
||||
</span>
|
||||
|
||||
<i *ngIf="Botao.havesub" class="material-icons dropdown-icon">
|
||||
{{Botao.dropicon}}
|
||||
</i>
|
||||
</button>
|
||||
|
||||
<div *ngIf="Botao.havesub" class="dropdown-container">
|
||||
<a
|
||||
*ngFor="let Sub of Botao.sub"
|
||||
[routerLink]="Sub.link"
|
||||
routerLinkActive="active-submenu"
|
||||
class="submenu-item">
|
||||
|
||||
<i class="material-icons submenu-icon">{{Sub.icon}}</i>
|
||||
<span>{{Sub.texto}}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<main
|
||||
class="dashboard-main"
|
||||
[ngClass]="BotoesMenuLateral.length > 0 ? 'with-sidebar' : 'without-sidebar'">
|
||||
|
||||
<div class="dashboard-content-card">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,385 @@
|
|||
.dashboard-layout {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(7, 27, 99, 0.08), transparent 34%),
|
||||
linear-gradient(135deg, #f4f6fb 0%, #eef3ff 50%, #ffffff 100%);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
HEADER
|
||||
========================= */
|
||||
|
||||
.dashboard-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 74px;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24px;
|
||||
background: rgba(7, 27, 99, 0.95);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
box-shadow: 0 14px 38px rgba(15, 23, 42, 0.22);
|
||||
backdrop-filter: blur(14px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.header-left,
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.brand-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.logo-escrito {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.logo-favicon {
|
||||
display: none;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.header-divider {
|
||||
width: 1px;
|
||||
height: 34px;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.header-title span {
|
||||
color: #bfdbfe;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.header-title strong {
|
||||
color: #ffffff;
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.user-pill {
|
||||
min-height: 38px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.10);
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.user-pill .material-icons {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.user-pill span {
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
max-width: 160px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
min-height: 38px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 14px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.logout-btn .material-icons {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.logout-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
background: #f8fafc;
|
||||
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.20);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
SIDEBAR
|
||||
========================= */
|
||||
|
||||
.dashboard-sidebar {
|
||||
position: fixed;
|
||||
top: 74px;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 270px;
|
||||
z-index: 900;
|
||||
padding: 22px 14px;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(255, 255, 255, 0.10), transparent 34%),
|
||||
linear-gradient(180deg, #071b63 0%, #04113f 100%);
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.10);
|
||||
box-shadow: 14px 0 34px rgba(15, 23, 42, 0.12);
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
padding: 0 12px 16px 12px;
|
||||
}
|
||||
|
||||
.sidebar-title span {
|
||||
color: #bfdbfe;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-btn {
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
padding: 0 12px;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
background: transparent;
|
||||
color: #dbeafe;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.dropdown-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.10);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.menu-main {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.menu-main span {
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 22px;
|
||||
color: #bfdbfe;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
font-size: 22px;
|
||||
color: #bfdbfe;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
display: block;
|
||||
margin: 6px 0 10px 0;
|
||||
padding: 6px;
|
||||
border-radius: 16px;
|
||||
background: rgba(2, 6, 23, 0.22);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.submenu-item {
|
||||
min-height: 40px;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-radius: 12px;
|
||||
color: #cbd5e1;
|
||||
text-decoration: none;
|
||||
transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.submenu-item span {
|
||||
font-size: 13px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.submenu-icon {
|
||||
font-size: 19px;
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
||||
.submenu-item:hover,
|
||||
.active-submenu {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.submenu-item:hover {
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
CONTENT
|
||||
========================= */
|
||||
|
||||
.dashboard-main {
|
||||
min-height: 100vh;
|
||||
padding-top: 74px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dashboard-main.with-sidebar {
|
||||
padding-left: 270px;
|
||||
}
|
||||
|
||||
.dashboard-main.without-sidebar {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.dashboard-content-card {
|
||||
min-height: calc(100vh - 74px);
|
||||
padding: 28px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
RESPONSIVE
|
||||
========================= */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.dashboard-sidebar {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.dashboard-main.with-sidebar {
|
||||
padding-left: 230px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard-header {
|
||||
height: 68px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.dashboard-sidebar {
|
||||
position: relative;
|
||||
top: 68px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
min-height: auto;
|
||||
padding: 12px;
|
||||
display: block;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.dashboard-main,
|
||||
.dashboard-main.with-sidebar,
|
||||
.dashboard-main.without-sidebar {
|
||||
padding-left: 0;
|
||||
padding-top: 68px;
|
||||
}
|
||||
|
||||
.dashboard-main.with-sidebar {
|
||||
padding-top: 68px;
|
||||
}
|
||||
|
||||
.dashboard-content-card {
|
||||
padding: 18px 14px;
|
||||
}
|
||||
|
||||
.logo-escrito {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logo-favicon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.user-pill {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logout-btn span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 40px;
|
||||
padding: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.dashboard-content-card {
|
||||
padding: 14px 10px;
|
||||
}
|
||||
|
||||
.dropdown-btn {
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.menu-main span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { MenuItem } from '../models/dashboardModel';
|
||||
import { Router } from '@angular/router';
|
||||
import { FuncoesGlobais } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.scss']
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
|
||||
BotoesMenuLateral: MenuItem[];
|
||||
UserName: string = localStorage.getItem("UserName") || "";
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private FuncoesGlobais: FuncoesGlobais,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (localStorage.getItem("Role") == "1") {
|
||||
this.PreencherMenuItensAdmin();
|
||||
}
|
||||
else if (localStorage.getItem("Role") == "2") {
|
||||
this.PreencherMenuItensCliente();
|
||||
}
|
||||
else {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PreencherMenuItensAdmin() {
|
||||
this.BotoesMenuLateral = [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Página inicial",
|
||||
link: "dashboard/admin/home",
|
||||
havesub: false,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "home",
|
||||
issub: false,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Usuários",
|
||||
link: "",
|
||||
havesub: true,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "person",
|
||||
issub: false,
|
||||
sub: [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Cadastrar",
|
||||
link: "usuarios/cadastro",
|
||||
icon: "person_add",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Visualizar",
|
||||
link: "usuarios/visualizar",
|
||||
icon: "pageview",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
texto: "Sistemas",
|
||||
link: "",
|
||||
havesub: true,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "extension",
|
||||
issub: false,
|
||||
sub: [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Cadastro",
|
||||
link: "sistemas/cadastro",
|
||||
icon: "add_to_queue",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Visualizar",
|
||||
link: "sistemas/visualizar",
|
||||
icon: "pageview",
|
||||
havesub: null,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
texto: "Ambiente cliente",
|
||||
link: "/dashboard/cliente",
|
||||
havesub: false,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "home",
|
||||
issub: false,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
texto: "Bingo",
|
||||
link: "",
|
||||
havesub: true,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "extension",
|
||||
issub: false,
|
||||
sub: [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Dashboard",
|
||||
link: "/bingo/dashboard",
|
||||
icon: "add_to_queue",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Sorteio",
|
||||
link: "/bingo/sorteio",
|
||||
icon: "pageview",
|
||||
havesub: null,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
index: 5,
|
||||
texto: "OrionTard Pro",
|
||||
link: "/orion-dashboard",
|
||||
havesub: false,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "home",
|
||||
issub: false,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 6,
|
||||
texto: "AgroBase",
|
||||
link: "",
|
||||
havesub: true,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "agriculture",
|
||||
issub: false,
|
||||
sub: [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Versionamento",
|
||||
link: "/agrobase/versionamento",
|
||||
icon: "update",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
this.CriaEventoClickSubItens();
|
||||
}
|
||||
|
||||
PreencherMenuItensCliente() {
|
||||
this.BotoesMenuLateral = [
|
||||
/*{
|
||||
index: 0,
|
||||
texto: "Página inicial",
|
||||
link: "/home",
|
||||
havesub: false,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "home",
|
||||
issub: false,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Meus Sistemas",
|
||||
link: "/dashboard/cliente",
|
||||
havesub: false,
|
||||
dropicon: "arrow_drop_down",
|
||||
icon: "extension",
|
||||
issub: false,
|
||||
sub: [
|
||||
{
|
||||
index: 0,
|
||||
texto: "Machining Price Simulator",
|
||||
link: "sistemas/MPS",
|
||||
icon: "assessment",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
texto: "Casco-Tubo",
|
||||
link: "sistemas/Casco-Tubo",
|
||||
icon: "assessment",
|
||||
havesub: false,
|
||||
dropicon: "",
|
||||
issub: true,
|
||||
sub: null,
|
||||
},
|
||||
],
|
||||
},*/
|
||||
];
|
||||
this.CriaEventoClickSubItens();
|
||||
}
|
||||
|
||||
CriaEventoClickSubItens() {
|
||||
setTimeout(() => {
|
||||
var dropdown = document.getElementsByClassName("dropdown-btn");
|
||||
for (let i = 0; i < dropdown.length; i++) {
|
||||
if (this.BotoesMenuLateral[i].havesub) {
|
||||
dropdown[i].addEventListener("click", function() {
|
||||
this.classList.toggle("active");
|
||||
var dropdownContent = this.nextElementSibling;
|
||||
if (dropdownContent.style.display === "block") {
|
||||
dropdownContent.style.display = "none";
|
||||
} else {
|
||||
dropdownContent.style.display = "block";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
DropMenuItem(indexBtnMenu) {
|
||||
if (this.BotoesMenuLateral[indexBtnMenu].havesub) {
|
||||
if (this.BotoesMenuLateral[indexBtnMenu].dropicon == "arrow_drop_down")
|
||||
this.BotoesMenuLateral[indexBtnMenu].dropicon = "arrow_drop_up";
|
||||
else
|
||||
this.BotoesMenuLateral[indexBtnMenu].dropicon = "arrow_drop_down";
|
||||
}
|
||||
else {
|
||||
this.router.navigate([this.BotoesMenuLateral[indexBtnMenu].link]);
|
||||
}
|
||||
}
|
||||
|
||||
Sair() {
|
||||
localStorage.removeItem("Session");
|
||||
localStorage.removeItem("UserName");
|
||||
localStorage.removeItem("UserID");
|
||||
localStorage.removeItem("Role");
|
||||
localStorage.removeItem("LastRouteBeforeLogin");
|
||||
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
<div class="details-page">
|
||||
|
||||
<!-- LOADING -->
|
||||
<div class="details-loader" *ngIf="!Carregado">
|
||||
<img src="assets/loader.gif" class="loader" alt="Carregando">
|
||||
<p>Carregando detalhes do sistema...</p>
|
||||
</div>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="details-wrapper" *ngIf="Carregado">
|
||||
|
||||
<!-- HERO -->
|
||||
<section class="system-hero">
|
||||
<div class="system-hero-glow"></div>
|
||||
|
||||
<div class="system-hero-content">
|
||||
<div class="system-icon-card">
|
||||
<img
|
||||
[src]="LinkProjeto + '/sistemas/' + idsistemas + '/icone.png'"
|
||||
class="system-icon"
|
||||
alt="Ícone do sistema">
|
||||
</div>
|
||||
|
||||
<div class="system-hero-text">
|
||||
<span class="eyebrow">Sistema Zendion</span>
|
||||
|
||||
<h1>{{ Sistema.nome }}</h1>
|
||||
|
||||
<p>{{ Sistema.descricao }}</p>
|
||||
|
||||
<div class="system-badges">
|
||||
<span>{{ Sistema.tiposdesistema }}</span>
|
||||
<span>{{ Sistema.tiposlicenca }}</span>
|
||||
<span>{{ Sistema.plataforma }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="system-action-card">
|
||||
<small>Versão atual</small>
|
||||
<strong>{{ Sistema.versaoatual }}</strong>
|
||||
|
||||
<button type="button" class="btn-main-action" (click)="btnBaixarClick()">
|
||||
{{ btnBaixar }}
|
||||
</button>
|
||||
|
||||
<p>
|
||||
{{ Sistema.plataforma }} • {{ Sistema.versaoatual }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- INFO CARDS -->
|
||||
<section class="info-grid">
|
||||
<div class="info-card">
|
||||
<span>Versão</span>
|
||||
<strong>{{ Sistema.versaoatual }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<span>Lançamento</span>
|
||||
<strong>{{ Sistema.insert_date | date:'dd/MM/yyyy' }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<span>Categoria</span>
|
||||
<strong>{{ Sistema.tiposdesistema }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="info-card">
|
||||
<span>Licença</span>
|
||||
<strong>{{ Sistema.tiposlicenca }}</strong>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- DETAILS -->
|
||||
<section class="details-sections" *ngIf="Detalhes && Detalhes.length > 0">
|
||||
<div class="section-header">
|
||||
<span class="eyebrow">Detalhes</span>
|
||||
<h2>Conheça melhor o sistema</h2>
|
||||
<p>Recursos, telas e informações importantes sobre esta solução.</p>
|
||||
</div>
|
||||
|
||||
<article
|
||||
class="detail-card"
|
||||
*ngFor="let Detalhe of Detalhes; let i = index"
|
||||
[ngClass]="i % 2 == 0 ? 'normal' : 'reverse'">
|
||||
|
||||
<div class="detail-text">
|
||||
<div [innerHTML]="Detalhe.descricao"></div>
|
||||
</div>
|
||||
|
||||
<div class="detail-image-wrapper">
|
||||
<img
|
||||
[src]="LinkProjeto + '/sistemas/' + idsistemas + '/detalhes/detalhe_' + Detalhe.ordem + '.jpg'"
|
||||
class="detail-image"
|
||||
alt="Detalhe do sistema"
|
||||
(click)="ImageClick($event)">
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- PLATFORM + UPDATE -->
|
||||
<section class="secondary-grid">
|
||||
|
||||
<div class="panel-card availability-section">
|
||||
<span class="panel-label">Disponível para</span>
|
||||
|
||||
<img
|
||||
[src]="LinkProjeto + '/imagens/plataformas/plataforma_' + Sistema.idplataformas + '.png'"
|
||||
class="platform-icon"
|
||||
alt="Plataforma">
|
||||
|
||||
<strong>{{ Sistema.plataforma }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="panel-card update-notes">
|
||||
<span class="panel-label">Notas de atualização</span>
|
||||
|
||||
<small *ngIf="Sistema.update_date">
|
||||
Atualizado em {{ Sistema.update_date | date:'dd/MM/yyyy' }}
|
||||
</small>
|
||||
|
||||
<div [innerHTML]="Sistema.notasdeatualizacao" class="update-text"></div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- VERSIONS -->
|
||||
<section *ngIf="Sistema.idplataformas != 6 && Adiquirido" class="panel-card list-panel">
|
||||
<div class="list-header">
|
||||
<div>
|
||||
<span class="panel-label">Histórico</span>
|
||||
<h3>Versões anteriores</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="resource-list">
|
||||
<li *ngFor="let versao of Sistema.versoes">
|
||||
<div>
|
||||
<strong>{{ versao.split('versoes/')[1].split('/')[0] }}</strong>
|
||||
<small>{{ versao.split('¬')[1] | date:'dd/MM/yyyy HH:mm' }}</small>
|
||||
</div>
|
||||
|
||||
<a [href]="versao.split('¬')[0]" target="_blank">
|
||||
Baixar
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- DOWNLOADS -->
|
||||
<section *ngIf="Adiquirido" class="panel-card list-panel">
|
||||
<div class="list-header">
|
||||
<div>
|
||||
<span class="panel-label">Arquivos</span>
|
||||
<h3>Materiais para download</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="resource-list">
|
||||
<li *ngFor="let download of Sistema.mdownloads">
|
||||
<div>
|
||||
<strong>{{ download.split('downloads/')[1].split('¬')[0] }}</strong>
|
||||
<small>{{ download.split('¬')[1] | date:'dd/MM/yyyy HH:mm' }}</small>
|
||||
</div>
|
||||
|
||||
<a [href]="download.split('¬')[0]" target="_blank">
|
||||
Abrir
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- FINAL CTA -->
|
||||
<section class="final-cta">
|
||||
<div>
|
||||
<span class="eyebrow">Pronto para continuar?</span>
|
||||
<h2>{{ Sistema.nome }}</h2>
|
||||
<p>{{ Sistema.plataforma }} • {{ Sistema.versaoatual }}</p>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-main-action" (click)="btnBaixarClick()">
|
||||
{{ btnBaixar }}
|
||||
</button>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- MODAL -->
|
||||
<div id="myModal" class="image-modal" (click)="btnFecharModal()">
|
||||
<span class="close" (click)="btnFecharModal()">×</span>
|
||||
<img class="modal-content" id="img01">
|
||||
<div id="caption"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,628 @@
|
|||
.details-page {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(7, 27, 99, 0.14), transparent 32%),
|
||||
linear-gradient(135deg, #f4f6fb 0%, #eef3ff 45%, #ffffff 100%);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.details-loader {
|
||||
min-height: 360px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
object-fit: contain;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.details-loader p {
|
||||
color: #64748b;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.details-wrapper {
|
||||
width: 100%;
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 44px 22px 64px 22px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
|
||||
.system-hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 28px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255,255,255,0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.system-hero-glow {
|
||||
position: absolute;
|
||||
width: 360px;
|
||||
height: 360px;
|
||||
right: -130px;
|
||||
top: -130px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
}
|
||||
|
||||
.system-hero-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr 260px;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
padding: 42px;
|
||||
}
|
||||
|
||||
.system-icon-card {
|
||||
width: 126px;
|
||||
height: 126px;
|
||||
border-radius: 28px;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.system-icon {
|
||||
width: 82px;
|
||||
height: 82px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 12px;
|
||||
color: #bfdbfe;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.system-hero-text h1 {
|
||||
margin: 0 0 14px 0;
|
||||
font-size: 42px;
|
||||
line-height: 50px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.045em;
|
||||
}
|
||||
|
||||
.system-hero-text p {
|
||||
max-width: 600px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.system-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.system-badges span {
|
||||
padding: 8px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.system-action-card {
|
||||
padding: 22px;
|
||||
border-radius: 22px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
border: 1px solid rgba(255,255,255,0.18);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.system-action-card small {
|
||||
display: block;
|
||||
color: #bfdbfe;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.system-action-card strong {
|
||||
display: block;
|
||||
margin: 8px 0 18px 0;
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.system-action-card p {
|
||||
margin: 14px 0 0 0;
|
||||
color: #dbeafe;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.btn-main-action {
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 14px 26px rgba(0,0,0,0.16);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-main-action:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 18px 34px rgba(0,0,0,0.20);
|
||||
}
|
||||
|
||||
/* INFO */
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.info-card span {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.info-card strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* SECTION HEADER */
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin: 54px 0 34px 0;
|
||||
}
|
||||
|
||||
.section-header .eyebrow {
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
max-width: 620px;
|
||||
margin: 0 auto;
|
||||
color: #64748b;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
/* DETAILS CARDS */
|
||||
|
||||
.details-sections {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
overflow: hidden;
|
||||
margin-bottom: 26px;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.detail-card.reverse .detail-text {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.detail-card.reverse .detail-image-wrapper {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.detail-text {
|
||||
padding: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #475569;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.detail-text h1,
|
||||
.detail-text h2,
|
||||
.detail-text h3,
|
||||
.detail-text h4 {
|
||||
color: #0f172a;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.detail-text p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.detail-image-wrapper {
|
||||
min-height: 340px;
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.detail-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 340px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
cursor: zoom-in;
|
||||
transition: transform 0.22s ease;
|
||||
}
|
||||
|
||||
.detail-image:hover {
|
||||
transform: scale(1.025);
|
||||
}
|
||||
|
||||
/* SECONDARY PANELS */
|
||||
|
||||
.secondary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 0.75fr 1.25fr;
|
||||
gap: 22px;
|
||||
margin-top: 42px;
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.availability-section {
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel-label {
|
||||
display: block;
|
||||
margin-bottom: 14px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.10em;
|
||||
}
|
||||
|
||||
.platform-icon {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
object-fit: contain;
|
||||
margin: 8px 0 16px 0;
|
||||
}
|
||||
|
||||
.availability-section strong {
|
||||
color: #0f172a;
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.update-notes {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.update-notes small {
|
||||
display: block;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.update-text {
|
||||
color: #475569;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
padding: 18px;
|
||||
border-radius: 16px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
/* LISTS */
|
||||
|
||||
.list-panel {
|
||||
margin-top: 24px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.list-header h3 {
|
||||
margin: 0;
|
||||
color: #0f172a;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.resource-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.resource-list li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.resource-list strong {
|
||||
display: block;
|
||||
color: #0f172a;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
font-weight: 900;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.resource-list small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.resource-list a {
|
||||
flex: 0 0 auto;
|
||||
padding: 10px 14px;
|
||||
border-radius: 12px;
|
||||
background: #071b63;
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.resource-list a:hover {
|
||||
background: #12358f;
|
||||
}
|
||||
|
||||
/* FINAL CTA */
|
||||
|
||||
.final-cta {
|
||||
margin-top: 34px;
|
||||
padding: 32px;
|
||||
border-radius: 24px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 220px;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255,255,255,0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.final-cta h2 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #ffffff;
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.final-cta p {
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.final-cta .btn-main-action {
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
/* MODAL */
|
||||
|
||||
.image-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
inset: 0;
|
||||
overflow: auto;
|
||||
background-color: rgba(2, 6, 23, 0.92);
|
||||
padding: 56px 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
margin: auto;
|
||||
display: block;
|
||||
width: auto;
|
||||
max-width: 92%;
|
||||
max-height: 82vh;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 24px 70px rgba(0,0,0,0.45);
|
||||
}
|
||||
|
||||
#caption {
|
||||
margin: 16px auto 0 auto;
|
||||
width: 80%;
|
||||
max-width: 760px;
|
||||
text-align: center;
|
||||
color: #cbd5e1;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: fixed;
|
||||
top: 18px;
|
||||
right: 30px;
|
||||
color: #ffffff;
|
||||
font-size: 42px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.system-hero-content {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
.system-action-card {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.detail-card.reverse .detail-text,
|
||||
.detail-card.reverse .detail-image-wrapper {
|
||||
order: unset;
|
||||
}
|
||||
|
||||
.secondary-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.final-cta {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.details-wrapper {
|
||||
padding: 28px 14px 46px 14px;
|
||||
}
|
||||
|
||||
.system-hero-content {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 28px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.system-icon-card {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.system-hero-text h1 {
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.system-badges {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.detail-text {
|
||||
padding: 26px;
|
||||
}
|
||||
|
||||
.detail-image,
|
||||
.detail-image-wrapper {
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
.resource-list li {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.resource-list a {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.final-cta {
|
||||
padding: 26px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Sistemas, Download, SistemasDetalhes, SistemasLista } from '../models/sistemasModel';
|
||||
import { SistemasService } from '../services/sistemas.service';
|
||||
import { UsuariosService } from '../services/usuarios.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-detalhes-sistema',
|
||||
templateUrl: './detalhes-sistema.component.html',
|
||||
styleUrls: ['./detalhes-sistema.component.scss']
|
||||
})
|
||||
export class DetalhesSistemaComponent implements OnInit {
|
||||
|
||||
Sistema: SistemasLista = new SistemasLista();
|
||||
|
||||
idsistemas: number = parseInt(this.route.snapshot.params['idsistemas']);
|
||||
idusuarios: number = parseInt(localStorage.getItem("UserID") || "0");
|
||||
|
||||
FormDownload: Download = new Download();
|
||||
|
||||
Logado: boolean = false;
|
||||
Adiquirido: boolean = false;
|
||||
|
||||
btnBaixar: string = "Adquirir";
|
||||
|
||||
Detalhes: SistemasDetalhes[] = [];
|
||||
|
||||
LinkProjeto: string = environment.LinkProjeto;
|
||||
|
||||
Carregado: boolean = false;
|
||||
|
||||
x86: boolean = false;
|
||||
x64: boolean = true;
|
||||
|
||||
constructor(
|
||||
private sistemasService: SistemasService,
|
||||
private usuariosService: UsuariosService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.FormDownload.idsistemas = this.idsistemas;
|
||||
this.FormDownload.idusuarios = this.idusuarios;
|
||||
|
||||
this.sistemasService.getSistemaByIDLista(this.idsistemas).then(resSistema => {
|
||||
this.Sistema = resSistema;
|
||||
|
||||
if (!this.Sistema.versoes) {
|
||||
this.Sistema.versoes = [];
|
||||
}
|
||||
|
||||
if (!this.Sistema.mdownloads) {
|
||||
this.Sistema.mdownloads = [];
|
||||
}
|
||||
|
||||
this.CarregarVersoesEDownloads();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('[DetalhesSistema] Erro ao carregar sistema:', error);
|
||||
this.Carregado = true;
|
||||
});
|
||||
}
|
||||
|
||||
CarregarVersoesEDownloads() {
|
||||
this.sistemasService.getSistemaVersoes(this.idsistemas).then(resVersoes => {
|
||||
this.Sistema.versoes = [];
|
||||
|
||||
if (resVersoes) {
|
||||
resVersoes.forEach(versao => {
|
||||
this.Sistema.versoes.push(versao.replace("/var/www/html", this.LinkProjeto));
|
||||
});
|
||||
}
|
||||
|
||||
this.CarregarDownloads();
|
||||
})
|
||||
.catch(error => {
|
||||
this.CarregarDownloads();
|
||||
});
|
||||
}
|
||||
|
||||
CarregarDownloads() {
|
||||
this.sistemasService.getSistemaDownloads(this.idsistemas).then(resDownloads => {
|
||||
this.Sistema.mdownloads = [];
|
||||
|
||||
if (resDownloads) {
|
||||
resDownloads.forEach(download => {
|
||||
this.Sistema.mdownloads.push(download.replace("/var/www/html", this.LinkProjeto));
|
||||
});
|
||||
}
|
||||
|
||||
this.CarregaDetalhesSistema();
|
||||
})
|
||||
.catch(error => {
|
||||
this.CarregaDetalhesSistema();
|
||||
});
|
||||
}
|
||||
|
||||
CarregaDetalhesSistema() {
|
||||
if (localStorage.getItem("Session") == "1") {
|
||||
this.Logado = true;
|
||||
|
||||
this.usuariosService.getSistemasDoUsuario(this.idusuarios).then(resSistemas => {
|
||||
if (resSistemas) {
|
||||
resSistemas.forEach(sistema => {
|
||||
if (sistema.idsistemas == this.Sistema.idsistemas) {
|
||||
this.Adiquirido = true;
|
||||
this.btnBaixar = (this.Sistema.idtiposdesistema == 6) ? "Acessar" : "Baixar";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.CarregarDetalhes();
|
||||
})
|
||||
.catch(error => {
|
||||
this.CarregarDetalhes();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.CarregarDetalhes();
|
||||
}
|
||||
|
||||
CarregarDetalhes() {
|
||||
this.sistemasService.getDetalhesByIDEn(this.idsistemas).then(resDetalhes => {
|
||||
this.Detalhes = resDetalhes || [];
|
||||
this.Carregado = true;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('[DetalhesSistema] Erro ao carregar detalhes:', error);
|
||||
this.Detalhes = [];
|
||||
this.Carregado = true;
|
||||
});
|
||||
}
|
||||
|
||||
btnBaixarClick() {
|
||||
if (localStorage.getItem("Session") == "1") {
|
||||
this.Baixar();
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("LastRouteBeforeLogin", "/detalhes/" + this.idsistemas);
|
||||
this.router.navigate(['/criarconta']);
|
||||
}
|
||||
|
||||
Baixar() {
|
||||
if (this.btnBaixar == "Adquirir") {
|
||||
this.sistemasService.downloadSistema(this.FormDownload).then(resDownload => {
|
||||
this.sistemasService.insertSistemaUsuario(this.FormDownload).then(resInsertSistema => {
|
||||
if (this.Sistema.idplataformas == 6) {
|
||||
this.btnBaixar = "Acessar";
|
||||
} else {
|
||||
this.btnBaixar = "Baixar";
|
||||
}
|
||||
|
||||
this.Adiquirido = true;
|
||||
alert("Acesso liberado! Clique em " + this.btnBaixar + " para continuar.");
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.btnBaixar == "Acessar") {
|
||||
window.open(this.Sistema.nome_install, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.btnBaixar == "Baixar") {
|
||||
window.open(
|
||||
environment.LinkProjeto + "/sistemas/" + this.idsistemas + "/versoes/" + this.Sistema.versaoatual + "/" + this.Sistema.nome_install,
|
||||
'_blank'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImageClick(event) {
|
||||
const modal = document.getElementById("myModal");
|
||||
const modalImg = document.getElementById("img01") as HTMLImageElement;
|
||||
const captionText = document.getElementById("caption");
|
||||
|
||||
const target = event.target as HTMLImageElement;
|
||||
|
||||
if (!modal || !modalImg || !captionText || !target) {
|
||||
return;
|
||||
}
|
||||
|
||||
modal.style.display = "block";
|
||||
modalImg.src = target.currentSrc || target.src;
|
||||
captionText.innerHTML = target.alt || "";
|
||||
}
|
||||
|
||||
btnFecharModal() {
|
||||
const modal = document.getElementById("myModal");
|
||||
|
||||
if (modal) {
|
||||
modal.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<div class="Corpo">
|
||||
<h2>EasyAVA</h2>
|
||||
|
||||
<label>Cole a pergunta na área abaixo</label> <br>
|
||||
<textarea [(ngModel)]="Questao" style="width: 50%; height: 300px;"></textarea> <br> <br>
|
||||
<button (click)="Procurar()" class="button" type="button">Pesquisar resposta</button> <br> <br>
|
||||
<span style="font-size: 30px;">A resposta correta é:</span> <span style="font-size: 30px; color: green;"> {{Resposta}}</span>
|
||||
|
||||
<br> <br>
|
||||
|
||||
<iframe src="http://myrobotlab.com.br"></iframe>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
.Corpo {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
color: #fff;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { EasyAVAService } from '../services/easy-ava.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-easy-ava',
|
||||
templateUrl: './easy-ava.component.html',
|
||||
styleUrls: ['./easy-ava.component.scss']
|
||||
})
|
||||
export class EasyAVAComponent implements OnInit {
|
||||
|
||||
Questao: string = "";
|
||||
Resposta: string = "";
|
||||
|
||||
constructor(
|
||||
private easyAvaService: EasyAVAService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
|
||||
Procurar() {
|
||||
this.easyAvaService.ProcurarResposta().then(resResposta => {
|
||||
console.log(resResposta);
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
<div class="edit-home-page">
|
||||
|
||||
<!-- HEADER -->
|
||||
<section class="admin-hero">
|
||||
<div>
|
||||
<span class="eyebrow">Backoffice</span>
|
||||
<h1>Painel administrativo</h1>
|
||||
<p>
|
||||
Gerencie as configurações principais da página inicial, identidade visual,
|
||||
endereços do projeto, slider e conteúdo público.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CONFIGURAÇÕES GERAIS -->
|
||||
<section class="admin-card">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Configurações</span>
|
||||
<h2>Cabeçalho e endereços</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-grid">
|
||||
|
||||
<!-- TÍTULO -->
|
||||
<div class="setting-card">
|
||||
<div class="setting-info">
|
||||
<div class="setting-icon">
|
||||
<i class="material-icons">title</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Título do site</h3>
|
||||
<p>Nome exibido nas configurações principais da aplicação.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-control">
|
||||
<input
|
||||
class="form-control"
|
||||
[(ngModel)]="Titulo"
|
||||
placeholder="Título do site">
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main"
|
||||
[disabled]="Titulo == TituloAnterior"
|
||||
(click)="Editar('Título')">
|
||||
<i class="material-icons">save</i>
|
||||
Salvar título
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- URL PROJETO -->
|
||||
<div class="setting-card">
|
||||
<div class="setting-info">
|
||||
<div class="setting-icon">
|
||||
<i class="material-icons">public</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>URL do projeto</h3>
|
||||
<p>Endereço público utilizado pelo site para montar links e recursos.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-control">
|
||||
<input
|
||||
class="form-control"
|
||||
[(ngModel)]="ProjetoUrl"
|
||||
placeholder="https://zendioninc.com.br">
|
||||
|
||||
<label class="confirm-check">
|
||||
<input type="checkbox" [(ngModel)]="ProjetoUrlCheck">
|
||||
<span>Confirmar alteração sensível</span>
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main"
|
||||
[disabled]="ProjetoUrl == ProjetoUrlAnterior || !ProjetoUrlCheck"
|
||||
(click)="Editar('URL do projeto')">
|
||||
<i class="material-icons">save</i>
|
||||
Salvar URL do projeto
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- URL API -->
|
||||
<div class="setting-card">
|
||||
<div class="setting-info">
|
||||
<div class="setting-icon">
|
||||
<i class="material-icons">api</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>URL da API</h3>
|
||||
<p>Endereço usado pelo frontend para se comunicar com o servidor.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-control">
|
||||
<input
|
||||
class="form-control"
|
||||
[(ngModel)]="APIUrl"
|
||||
placeholder="https://api.zendioninc.com.br">
|
||||
|
||||
<label class="confirm-check">
|
||||
<input type="checkbox" [(ngModel)]="APIUrlCheck">
|
||||
<span>Confirmar alteração sensível</span>
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main"
|
||||
[disabled]="APIUrl == APIUrlAnterior || !APIUrlCheck"
|
||||
(click)="Editar('URL da API')">
|
||||
<i class="material-icons">save</i>
|
||||
Salvar URL da API
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- IDENTIDADE VISUAL -->
|
||||
<section class="admin-card">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Identidade visual</span>
|
||||
<h2>Arquivos do site</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="assets-grid">
|
||||
|
||||
<!-- LOGO -->
|
||||
<article class="asset-card">
|
||||
<div class="asset-preview logo-preview">
|
||||
<img [src]="CaminhoLogo" alt="Logo">
|
||||
</div>
|
||||
|
||||
<div class="asset-body">
|
||||
<h3>Logo escrita</h3>
|
||||
<p>Arquivo principal exibido no cabeçalho e rodapé do site.</p>
|
||||
|
||||
<label class="file-label">
|
||||
<i class="material-icons">upload_file</i>
|
||||
Selecionar PNG
|
||||
<input type="file" (change)="onFileChangedLogo($event)" accept=".png">
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main asset-btn"
|
||||
[disabled]="!Logo"
|
||||
(click)="CopiarArquivos('logo_escrito.png', Logo, 'assets/')">
|
||||
<i class="material-icons">save</i>
|
||||
Editar logo
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- FAVICON -->
|
||||
<article class="asset-card">
|
||||
<div class="asset-preview favicon-preview">
|
||||
<img [src]="CaminhoFavicon" alt="Favicon">
|
||||
</div>
|
||||
|
||||
<div class="asset-body">
|
||||
<h3>Favicon</h3>
|
||||
<p>Ícone exibido na aba do navegador.</p>
|
||||
|
||||
<label class="file-label">
|
||||
<i class="material-icons">upload_file</i>
|
||||
Selecionar ICO
|
||||
<input type="file" (change)="onFileChangedFavicon($event)" accept=".ico">
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main asset-btn"
|
||||
[disabled]="!Favicon"
|
||||
(click)="CopiarArquivos('favicon.ico', Favicon, '')">
|
||||
<i class="material-icons">save</i>
|
||||
Editar favicon
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- BACKGROUND -->
|
||||
<article class="asset-card">
|
||||
<div class="asset-preview background-preview">
|
||||
<img [src]="CaminhoBackground" alt="Background">
|
||||
</div>
|
||||
|
||||
<div class="asset-body">
|
||||
<h3>Background</h3>
|
||||
<p>Imagem de fundo usada no site.</p>
|
||||
|
||||
<label class="file-label">
|
||||
<i class="material-icons">upload_file</i>
|
||||
Selecionar PNG
|
||||
<input type="file" (change)="onFileChangedBackground($event)" accept=".png,.jpg,.jpeg">
|
||||
</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn-main asset-btn"
|
||||
[disabled]="!Background"
|
||||
(click)="CopiarArquivos('background.jpg', Background, 'assets/')">
|
||||
<i class="material-icons">save</i>
|
||||
Editar background
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ATALHOS -->
|
||||
<section class="shortcut-grid">
|
||||
|
||||
<article class="admin-card shortcut-card">
|
||||
<div class="shortcut-icon">
|
||||
<i class="material-icons">collections</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="eyebrow">Slider</span>
|
||||
<h2>Slides da página inicial</h2>
|
||||
<p>Cadastre, edite e visualize os banners exibidos na home.</p>
|
||||
</div>
|
||||
|
||||
<div class="shortcut-actions">
|
||||
<button type="button" class="btn-secondary" (click)="Cadastrar('slides')">
|
||||
Cadastrar slides
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn-main form-submit" (click)="Visualizar('slides')">
|
||||
Visualizar slides
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="admin-card shortcut-card">
|
||||
<div class="shortcut-icon">
|
||||
<i class="material-icons">article</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="eyebrow">Conteúdo</span>
|
||||
<h2>Notícias da página inicial</h2>
|
||||
<p>Gerencie os conteúdos publicados na área de notícias do site.</p>
|
||||
</div>
|
||||
|
||||
<div class="shortcut-actions">
|
||||
<button type="button" class="btn-secondary" (click)="Cadastrar('noticias')">
|
||||
Cadastrar notícias
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn-main form-submit" (click)="Visualizar('noticias')">
|
||||
Visualizar notícias
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
.edit-home-page {
|
||||
min-height: calc(100vh - 74px);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
|
||||
.admin-hero {
|
||||
margin-bottom: 22px;
|
||||
padding: 32px;
|
||||
border-radius: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.14), transparent 34%),
|
||||
linear-gradient(145deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 22px 55px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.admin-hero .eyebrow {
|
||||
color: #bfdbfe;
|
||||
}
|
||||
|
||||
.admin-hero h1 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #ffffff;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.admin-hero p {
|
||||
max-width: 760px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
/* BASE CARDS */
|
||||
|
||||
.admin-card {
|
||||
margin-bottom: 22px;
|
||||
padding: 28px;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.panel-header h2,
|
||||
.shortcut-card h2 {
|
||||
margin: 0;
|
||||
color: #0f172a;
|
||||
font-size: 26px;
|
||||
line-height: 34px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
/* BUTTONS */
|
||||
|
||||
.btn-main,
|
||||
.btn-secondary {
|
||||
min-height: 44px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 0 18px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-main {
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.20);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #f1f5f9;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.btn-main:hover:not(:disabled),
|
||||
.btn-secondary:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-main:disabled,
|
||||
.btn-secondary:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* SETTINGS */
|
||||
|
||||
.settings-grid {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.setting-card {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 420px;
|
||||
gap: 22px;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.setting-info {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.setting-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
}
|
||||
|
||||
.setting-icon .material-icons {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.setting-info h3,
|
||||
.asset-body h3 {
|
||||
margin: 0 0 6px 0;
|
||||
color: #0f172a;
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.setting-info p,
|
||||
.asset-body p,
|
||||
.shortcut-card p {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.setting-control {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d7deea;
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
font-size: 15px;
|
||||
outline: none;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #071b63;
|
||||
box-shadow: 0 0 0 4px rgba(7, 27, 99, 0.10);
|
||||
}
|
||||
|
||||
.confirm-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.confirm-check input {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
/* ASSETS */
|
||||
|
||||
.assets-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.asset-card {
|
||||
overflow: hidden;
|
||||
border-radius: 22px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.asset-preview {
|
||||
height: 150px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(7, 27, 99, 0.12), transparent 34%),
|
||||
#ffffff;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.asset-preview img {
|
||||
max-width: 76%;
|
||||
max-height: 90px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.favicon-preview img {
|
||||
max-width: 64px;
|
||||
max-height: 64px;
|
||||
}
|
||||
|
||||
.background-preview img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.asset-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
min-height: 42px;
|
||||
margin-top: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
border: 1px solid #dbe6ff;
|
||||
}
|
||||
|
||||
.file-label input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-label .material-icons {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.asset-btn {
|
||||
width: 100%;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
/* SHORTCUTS */
|
||||
|
||||
.shortcut-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.shortcut-card {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.shortcut-icon {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
border-radius: 18px;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.shortcut-icon .material-icons {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.shortcut-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.setting-card {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.assets-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.admin-hero,
|
||||
.admin-card {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.admin-hero h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.shortcut-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.shortcut-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.shortcut-actions button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { environment, FuncoesGlobais } from 'src/environments/environment';
|
||||
import { GeralService } from '../services/geral.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-home',
|
||||
templateUrl: './edit-home.component.html',
|
||||
styleUrls: ['./edit-home.component.scss', './../app.component.scss']
|
||||
})
|
||||
export class EditHomeComponent implements OnInit {
|
||||
|
||||
LinkProjeto: string = environment.LinkProjeto;
|
||||
|
||||
Logo: File = null;
|
||||
Favicon: File = null;
|
||||
Background: File = null;
|
||||
|
||||
CaminhoLogo: string = environment.LinkProjeto + "/assets/logo_escrito.png";
|
||||
CaminhoFavicon: string = "/favicon.ico";
|
||||
CaminhoBackground: string = "/assets/background.jpg";
|
||||
|
||||
TituloAnterior: string = "";
|
||||
Titulo: string = "";
|
||||
|
||||
APIUrl: string = "";
|
||||
APIUrlAnterior: string = "";
|
||||
APIUrlCheck: boolean = false;
|
||||
|
||||
ProjetoUrl: string = "";
|
||||
ProjetoUrlAnterior: string = "";
|
||||
ProjetoUrlCheck: boolean = false;
|
||||
|
||||
StringConfig: string = "";
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private geralService: GeralService,
|
||||
private funcoesGlobais: FuncoesGlobais,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.funcoesGlobais.CheckAdminRoute();
|
||||
|
||||
this.geralService.readEnderecos().then(resGeral => {
|
||||
this.StringConfig = resGeral || "";
|
||||
|
||||
const partes = this.StringConfig.split(';');
|
||||
|
||||
this.ProjetoUrlAnterior = partes[0].split('=')[1] || "";
|
||||
this.ProjetoUrl = this.ProjetoUrlAnterior;
|
||||
|
||||
this.APIUrlAnterior = partes[1].split('=')[1] || "";
|
||||
this.APIUrl = this.APIUrlAnterior;
|
||||
|
||||
this.TituloAnterior = partes[2].split('=')[1] || "";
|
||||
this.Titulo = this.TituloAnterior;
|
||||
});
|
||||
}
|
||||
|
||||
Visualizar(Janela: string) {
|
||||
this.router.navigate(['/dashboard/admin/' + Janela + '/visualizar']);
|
||||
}
|
||||
|
||||
Cadastrar(Janela: string) {
|
||||
this.router.navigate(['/dashboard/admin/' + Janela]);
|
||||
}
|
||||
|
||||
onFileChangedLogo(event) {
|
||||
this.CarregarPreviewArquivo(event, 'logo');
|
||||
}
|
||||
|
||||
onFileChangedFavicon(event) {
|
||||
this.CarregarPreviewArquivo(event, 'favicon');
|
||||
}
|
||||
|
||||
onFileChangedBackground(event) {
|
||||
this.CarregarPreviewArquivo(event, 'background');
|
||||
}
|
||||
|
||||
CarregarPreviewArquivo(event, tipo: string) {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
const arquivo = event.target.files[0];
|
||||
|
||||
if (tipo === 'logo') {
|
||||
this.Logo = arquivo;
|
||||
}
|
||||
|
||||
if (tipo === 'favicon') {
|
||||
this.Favicon = arquivo;
|
||||
}
|
||||
|
||||
if (tipo === 'background') {
|
||||
this.Background = arquivo;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(arquivo);
|
||||
|
||||
reader.onload = (event) => {
|
||||
const result = event.target['result'].toString();
|
||||
|
||||
if (tipo === 'logo') {
|
||||
this.CaminhoLogo = result;
|
||||
}
|
||||
|
||||
if (tipo === 'favicon') {
|
||||
this.CaminhoFavicon = result;
|
||||
}
|
||||
|
||||
if (tipo === 'background') {
|
||||
this.CaminhoBackground = result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CopiarArquivos(Nome: string, Arquivo: File, Caminho: string) {
|
||||
if (!Arquivo) {
|
||||
alert("Selecione um arquivo antes de salvar.");
|
||||
return;
|
||||
}
|
||||
|
||||
const req = new XMLHttpRequest();
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("nome", Nome);
|
||||
formData.append("arquivo", Arquivo);
|
||||
formData.append("caminho", Caminho);
|
||||
|
||||
req.open("POST", environment.ApiUrl + "/arquivos/copy");
|
||||
req.send(formData);
|
||||
|
||||
req.onreadystatechange = () => {
|
||||
if (req.readyState === 4) {
|
||||
alert(Nome + " alterado com sucesso!");
|
||||
|
||||
if (Nome === 'logo_escrito.png') {
|
||||
this.Logo = null;
|
||||
}
|
||||
|
||||
if (Nome === 'favicon.ico') {
|
||||
this.Favicon = null;
|
||||
}
|
||||
|
||||
if (Nome === 'background.jpg') {
|
||||
this.Background = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Editar(Item: string) {
|
||||
this.StringConfig = `Dominio=${this.ProjetoUrl};API=${this.APIUrl};Título=${this.Titulo}`;
|
||||
|
||||
const form = {
|
||||
content: this.StringConfig
|
||||
};
|
||||
|
||||
this.geralService.writeEnderecos(form).then(resEdit => {
|
||||
if (resEdit == true) {
|
||||
alert(Item + " alterado com sucesso!");
|
||||
|
||||
this.ProjetoUrlAnterior = this.ProjetoUrl;
|
||||
this.APIUrlAnterior = this.APIUrl;
|
||||
this.TituloAnterior = this.Titulo;
|
||||
|
||||
this.ProjetoUrlCheck = false;
|
||||
this.APIUrlCheck = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<div class="home-page">
|
||||
|
||||
<!-- HERO / SLIDER -->
|
||||
<section class="hero-section">
|
||||
<div class="hero-background-glow"></div>
|
||||
|
||||
<div class="hero-content">
|
||||
<div class="hero-text">
|
||||
<span class="eyebrow">Zendion, INC.</span>
|
||||
|
||||
<h1>
|
||||
Soluções digitais para negócios mais inteligentes.
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
Sistemas, automações e tecnologia sob medida para simplificar processos,
|
||||
conectar informações e impulsionar operações.
|
||||
</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<a href="/home#sistemas" class="btn-hero-primary">
|
||||
Conhecer sistemas
|
||||
</a>
|
||||
|
||||
<a href="/home#noticias" class="btn-hero-secondary">
|
||||
Ver novidades
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-slider-card">
|
||||
<swiper [config]="config" class="hero-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" *ngFor="let Slide of ListaDeSlides; let i = index">
|
||||
<img
|
||||
[src]="LinkProjeto + '/imagens/slides/slide_' + Slide.idslides + '.jpg'"
|
||||
class="slider-image"
|
||||
alt="Slide Zendion">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="swiper-pagination"></div>
|
||||
<div class="swiper-button-next" id="slideNext"></div>
|
||||
<div class="swiper-button-prev" id="slidePreview"></div>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SISTEMAS -->
|
||||
<section class="systems-section" id="sistemas">
|
||||
<div class="section-header">
|
||||
<span class="eyebrow">Nossas soluções</span>
|
||||
|
||||
<h2>Sistemas</h2>
|
||||
|
||||
<p>
|
||||
Conheça os sistemas disponíveis na plataforma Zendion.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="systems-grid">
|
||||
<div class="system-card" *ngFor="let Sistema of ListaDeSistemas; let i = index;">
|
||||
<div class="system-icon-wrapper">
|
||||
<img
|
||||
[src]="LinkProjeto + '/sistemas/' + Sistema.idsistemas + '/icone.png'"
|
||||
class="system-icon"
|
||||
alt="Ícone do sistema">
|
||||
</div>
|
||||
|
||||
<h3>{{ Sistema.nome }}</h3>
|
||||
|
||||
<p>{{ Sistema.descricao }}</p>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="system-btn"
|
||||
(click)="AbrirDetalhesSistema(Sistema)">
|
||||
Ver detalhes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- NOTÍCIAS -->
|
||||
<section class="news-section" id="noticias" *ngIf="ListaDeNoticias && ListaDeNoticias.length > 0">
|
||||
<div class="section-header">
|
||||
<span class="eyebrow">Atualizações</span>
|
||||
|
||||
<h2>Notícias</h2>
|
||||
|
||||
<p>
|
||||
Acompanhe novidades, comunicados e informações da Zendion.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="news-list">
|
||||
<article
|
||||
class="news-card"
|
||||
*ngFor="let Noticia of ListaDeNoticias; let i = index"
|
||||
[ngClass]="i % 2 == 0 ? 'normal' : 'reverse'">
|
||||
|
||||
<div class="news-image-wrapper">
|
||||
<img
|
||||
[src]="LinkProjeto + '/imagens/noticias/noticia_' + Noticia.idnoticias + '.jpg'"
|
||||
class="news-image"
|
||||
alt="Imagem da notícia">
|
||||
</div>
|
||||
|
||||
<div class="news-content">
|
||||
<span class="news-label">Notícia</span>
|
||||
|
||||
<h3>{{ Noticia.titulo }}</h3>
|
||||
|
||||
<div [innerHTML]="Noticia.descricao" class="news-description"></div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,478 @@
|
|||
.home-page {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(7, 27, 99, 0.18), transparent 30%),
|
||||
linear-gradient(135deg, #f4f6fb 0%, #eef3ff 45%, #ffffff 100%);
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
HERO
|
||||
========================= */
|
||||
|
||||
.hero-section {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 64px 22px 52px 22px;
|
||||
}
|
||||
|
||||
.hero-background-glow {
|
||||
position: absolute;
|
||||
width: 420px;
|
||||
height: 420px;
|
||||
right: -140px;
|
||||
top: -140px;
|
||||
border-radius: 999px;
|
||||
background: rgba(7, 27, 99, 0.16);
|
||||
filter: blur(8px);
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 0.9fr 1.1fr;
|
||||
align-items: center;
|
||||
gap: 42px;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
padding: 18px 0;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 12px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hero-text h1 {
|
||||
margin: 0 0 18px 0;
|
||||
max-width: 520px;
|
||||
color: #0f172a;
|
||||
font-size: 48px;
|
||||
line-height: 58px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.045em;
|
||||
}
|
||||
|
||||
.hero-text p {
|
||||
margin: 0;
|
||||
max-width: 520px;
|
||||
color: #475569;
|
||||
font-size: 17px;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.btn-hero-primary,
|
||||
.btn-hero-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 46px;
|
||||
padding: 0 22px;
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
text-decoration: none;
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-hero-primary {
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 14px 28px rgba(7, 27, 99, 0.24);
|
||||
}
|
||||
|
||||
.btn-hero-secondary {
|
||||
background: #ffffff;
|
||||
color: #071b63;
|
||||
border: 1px solid #d7deea;
|
||||
}
|
||||
|
||||
.btn-hero-primary:hover,
|
||||
.btn-hero-secondary:hover {
|
||||
transform: translateY(-1px);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.hero-slider-card {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
border-radius: 24px;
|
||||
padding: 14px;
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.16);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-swiper {
|
||||
width: 100%;
|
||||
height: 430px;
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.slider-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Swiper buttons */
|
||||
:host ::ng-deep .swiper-button-next,
|
||||
:host ::ng-deep .swiper-button-prev {
|
||||
color: #ffffff;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 999px;
|
||||
background: rgba(7, 27, 99, 0.78);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
:host ::ng-deep .swiper-button-next::after,
|
||||
:host ::ng-deep .swiper-button-prev::after {
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
:host ::ng-deep .swiper-pagination-bullet {
|
||||
background: #ffffff;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
:host ::ng-deep .swiper-pagination-bullet-active {
|
||||
background: #071b63;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
SECTIONS
|
||||
========================= */
|
||||
|
||||
.systems-section,
|
||||
.news-section {
|
||||
width: 100%;
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 48px 22px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
margin: 0 auto;
|
||||
max-width: 620px;
|
||||
color: #64748b;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
SISTEMAS
|
||||
========================= */
|
||||
|
||||
.systems-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.system-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 310px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 28px;
|
||||
border-radius: 22px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
|
||||
.system-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
right: -80px;
|
||||
top: -80px;
|
||||
border-radius: 999px;
|
||||
background: rgba(7, 27, 99, 0.08);
|
||||
}
|
||||
|
||||
.system-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.16);
|
||||
border-color: rgba(7, 27, 99, 0.22);
|
||||
}
|
||||
|
||||
.system-icon-wrapper {
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 22px;
|
||||
border-radius: 18px;
|
||||
background: #f1f5ff;
|
||||
border: 1px solid #dbe6ff;
|
||||
}
|
||||
|
||||
.system-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.system-card h3 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #0f172a;
|
||||
font-size: 21px;
|
||||
line-height: 28px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.system-card p {
|
||||
flex: 1;
|
||||
margin: 0 0 24px 0;
|
||||
color: #64748b;
|
||||
font-size: 14px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.system-btn {
|
||||
width: 100%;
|
||||
min-height: 44px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.20);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.system-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 30px rgba(7, 27, 99, 0.26);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
NOTÍCIAS
|
||||
========================= */
|
||||
|
||||
.news-list {
|
||||
display: grid;
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.news-card {
|
||||
display: grid;
|
||||
grid-template-columns: 0.92fr 1.08fr;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 24px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.10);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.news-card.reverse {
|
||||
grid-template-columns: 1.08fr 0.92fr;
|
||||
}
|
||||
|
||||
.news-card.reverse .news-image-wrapper {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.news-card.reverse .news-content {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.news-image-wrapper {
|
||||
min-height: 320px;
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.news-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 320px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.news-content {
|
||||
padding: 36px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.news-label {
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
margin-bottom: 14px;
|
||||
padding: 7px 11px;
|
||||
border-radius: 999px;
|
||||
background: #f1f5ff;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.news-content h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #0f172a;
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.035em;
|
||||
}
|
||||
|
||||
.news-description {
|
||||
color: #475569;
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.news-description p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.news-description p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
RESPONSIVO
|
||||
========================= */
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.hero-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-text h1,
|
||||
.hero-text p {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.systems-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.news-card,
|
||||
.news-card.reverse {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.news-card.reverse .news-image-wrapper,
|
||||
.news-card.reverse .news-content {
|
||||
order: unset;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.hero-section {
|
||||
padding: 42px 14px 34px 14px;
|
||||
}
|
||||
|
||||
.hero-text h1 {
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
.hero-text p {
|
||||
font-size: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.hero-swiper {
|
||||
height: 280px;
|
||||
}
|
||||
|
||||
.systems-section,
|
||||
.news-section {
|
||||
padding: 38px 14px;
|
||||
}
|
||||
|
||||
.systems-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.news-content {
|
||||
padding: 26px;
|
||||
}
|
||||
|
||||
.news-content h3 {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.news-image,
|
||||
.news-image-wrapper {
|
||||
min-height: 230px;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.btn-hero-primary,
|
||||
.btn-hero-secondary {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Sistemas } from '../models/sistemasModel';
|
||||
import { SistemasService } from '../services/sistemas.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Slides } from '../models/sliderModel';
|
||||
import { SliderService } from '../services/slider.service';
|
||||
import { Noticias } from '../models/noticiasModel';
|
||||
import { NoticiasService } from '../services/noticias.service';
|
||||
import { SwiperOptions } from 'swiper';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
|
||||
config: SwiperOptions = {
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true
|
||||
},
|
||||
navigation: {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev'
|
||||
},
|
||||
spaceBetween: 24,
|
||||
loop: true,
|
||||
speed: 700,
|
||||
autoplay: {
|
||||
delay: 8000,
|
||||
disableOnInteraction: false
|
||||
}
|
||||
};
|
||||
|
||||
ListaDeSlides: Slides[] = [];
|
||||
ListaDeSistemas: Sistemas[] = [];
|
||||
ListaDeNoticias: Noticias[] = [];
|
||||
|
||||
LinkProjeto: string = environment.LinkProjeto;
|
||||
|
||||
constructor(
|
||||
private sistemasService: SistemasService,
|
||||
private router: Router,
|
||||
private sliderService: SliderService,
|
||||
private noticiasService: NoticiasService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.sliderService.getSlidesEn().then(resSlides => {
|
||||
this.ListaDeSlides = resSlides || [];
|
||||
});
|
||||
|
||||
this.sistemasService.getSistemasEn().then(resSistemas => {
|
||||
this.ListaDeSistemas = resSistemas || [];
|
||||
});
|
||||
|
||||
this.noticiasService.getNoticiasEn().then(resNoticias => {
|
||||
this.ListaDeNoticias = resNoticias || [];
|
||||
});
|
||||
}
|
||||
|
||||
AbrirDetalhesSistema(Sistema: Sistemas) {
|
||||
this.router.navigate(['/detalhes/' + Sistema.idsistemas]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
<div class="login-page">
|
||||
<div class="login-shell">
|
||||
|
||||
<div class="login-brand-panel">
|
||||
<div class="brand-content">
|
||||
<img src="assets/logo_escrito.png" alt="Zendion, INC." class="brand-logo">
|
||||
|
||||
<h1>Bem-vindo de volta</h1>
|
||||
|
||||
<p>
|
||||
Acesse sua conta para gerenciar seus sistemas, licenças e recursos da Zendion, INC.
|
||||
</p>
|
||||
|
||||
<div class="brand-badges">
|
||||
<span>Acesso seguro</span>
|
||||
<span>Gestão centralizada</span>
|
||||
<span>Suporte Zendion</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<span class="eyebrow">
|
||||
<ng-container *ngIf="JanelaModo.Visualizar">Login</ng-container>
|
||||
<ng-container *ngIf="JanelaModo.Cadastro">Recuperação</ng-container>
|
||||
<ng-container *ngIf="JanelaModo.Editar">Nova senha</ng-container>
|
||||
</span>
|
||||
|
||||
<h2>{{ TituloJanela }}</h2>
|
||||
|
||||
<p *ngIf="JanelaModo.Visualizar">
|
||||
Entre com seu usuário e senha para acessar sua conta.
|
||||
</p>
|
||||
|
||||
<p *ngIf="JanelaModo.Cadastro">
|
||||
Informe seu usuário e e-mail para receber as instruções de redefinição de senha.
|
||||
</p>
|
||||
|
||||
<p *ngIf="JanelaModo.Editar">
|
||||
Crie uma nova senha para sua conta. Escolha uma senha segura e fácil de lembrar.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="login-body">
|
||||
|
||||
<!-- Modo login -->
|
||||
<div *ngIf="JanelaModo.Visualizar" class="login-form">
|
||||
<div class="form-group">
|
||||
<label for="usuario">Usuário</label>
|
||||
<input
|
||||
id="usuario"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Digite seu usuário"
|
||||
[(ngModel)]="LoginModel.usuario"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="senha">Senha</label>
|
||||
<input
|
||||
id="senha"
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="Digite sua senha"
|
||||
[(ngModel)]="LoginModel.senha"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modo esqueci senha -->
|
||||
<div *ngIf="JanelaModo.Cadastro" class="login-form">
|
||||
<div class="form-group">
|
||||
<label for="usuario-recuperacao">Usuário</label>
|
||||
<input
|
||||
id="usuario-recuperacao"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Digite seu usuário"
|
||||
[(ngModel)]="LoginModel.usuario"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email-recuperacao">E-mail</label>
|
||||
<input
|
||||
id="email-recuperacao"
|
||||
type="email"
|
||||
class="form-control"
|
||||
placeholder="seuemail@exemplo.com"
|
||||
[(ngModel)]="LoginModel.email"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modo trocar senha -->
|
||||
<div *ngIf="JanelaModo.Editar" class="login-form">
|
||||
<div class="form-group">
|
||||
<label for="nova-senha">Nova senha</label>
|
||||
<input
|
||||
id="nova-senha"
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="Digite sua nova senha"
|
||||
[(ngModel)]="LoginModel.senha"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmar-senha">Confirmar senha</label>
|
||||
<input
|
||||
id="confirmar-senha"
|
||||
type="password"
|
||||
class="form-control"
|
||||
placeholder="Confirme sua nova senha"
|
||||
[(ngModel)]="LoginModel.novasenha"
|
||||
[ngClass]="LoginError ? 'Danger' : 'Normal'">
|
||||
</div>
|
||||
|
||||
<small class="field-hint">
|
||||
Use uma senha que você não utiliza em outros serviços.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div *ngIf="MenssagemForm != ''" class="login-message">
|
||||
<small>{{ MenssagemForm }}</small>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-login"
|
||||
(click)="btnEntrarClick()"
|
||||
[disabled]="DesabilitaBotao">
|
||||
{{ BotaoText }}
|
||||
</button>
|
||||
|
||||
<div class="login-footer">
|
||||
<a *ngIf="JanelaModo.Visualizar" [routerLink]="'/login/esqueci'">
|
||||
Esqueci a senha
|
||||
</a>
|
||||
|
||||
<a *ngIf="JanelaModo.Visualizar" [routerLink]="'/criarconta'">
|
||||
Criar conta
|
||||
</a>
|
||||
|
||||
<a *ngIf="!JanelaModo.Visualizar" [routerLink]="'/login'">
|
||||
Voltar ao login
|
||||
</a>
|
||||
|
||||
<a [routerLink]="'/home'">
|
||||
Voltar ao site
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
.login-page {
|
||||
min-height: calc(100vh - 80px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 18px;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(7, 27, 99, 0.14), transparent 34%),
|
||||
linear-gradient(135deg, #f4f6fb 0%, #eef3ff 45%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.login-shell {
|
||||
width: 100%;
|
||||
max-width: 980px;
|
||||
display: grid;
|
||||
grid-template-columns: 0.95fr 1.05fr;
|
||||
background: #ffffff;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.16);
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
}
|
||||
|
||||
.login-brand-panel {
|
||||
position: relative;
|
||||
min-height: 560px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 42px;
|
||||
background:
|
||||
linear-gradient(145deg, rgba(7, 27, 99, 0.96), rgba(18, 47, 132, 0.94));
|
||||
color: #ffffff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-brand-panel::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 340px;
|
||||
height: 340px;
|
||||
right: -120px;
|
||||
top: -100px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.login-brand-panel::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
left: -80px;
|
||||
bottom: -70px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.brand-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 54px;
|
||||
max-width: 240px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
margin-bottom: 34px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.brand-content h1 {
|
||||
margin: 0 0 14px 0;
|
||||
font-size: 34px;
|
||||
line-height: 42px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.brand-content p {
|
||||
max-width: 390px;
|
||||
margin: 0;
|
||||
color: #dbeafe;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.brand-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.brand-badges span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.13);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.login-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 44px 48px;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
color: #071b63;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.login-header h2 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #0f172a;
|
||||
font-size: 30px;
|
||||
line-height: 38px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.login-header p {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.login-body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 7px;
|
||||
color: #1e293b;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
padding: 0 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d7deea;
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
font-size: 15px;
|
||||
outline: none;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control::placeholder {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #071b63;
|
||||
box-shadow: 0 0 0 4px rgba(7, 27, 99, 0.10);
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.field-hint {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
margin-top: 22px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #071b63, #12358f);
|
||||
color: #ffffff;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 12px 24px rgba(7, 27, 99, 0.22);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
|
||||
}
|
||||
|
||||
.btn-login:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 16px 30px rgba(7, 27, 99, 0.28);
|
||||
}
|
||||
|
||||
.btn-login:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-login:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px 16px;
|
||||
margin-top: 26px;
|
||||
padding-top: 22px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.login-footer a {
|
||||
color: #071b63;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.login-footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.login-message {
|
||||
margin-top: 18px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
background: #fef2f2;
|
||||
border: 1px solid #fecaca;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.login-message small {
|
||||
display: block;
|
||||
color: #b91c1c;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Estados de erro herdados do seu TS */
|
||||
.Danger {
|
||||
border-color: #ef4444 !important;
|
||||
background-color: #fff7f7;
|
||||
}
|
||||
|
||||
.Danger:focus {
|
||||
border-color: #ef4444 !important;
|
||||
box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.12);
|
||||
}
|
||||
|
||||
.Normal {
|
||||
border-color: #d7deea;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.login-shell {
|
||||
grid-template-columns: 1fr;
|
||||
max-width: 560px;
|
||||
}
|
||||
|
||||
.login-brand-panel {
|
||||
min-height: auto;
|
||||
padding: 30px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 44px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.brand-content h1 {
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
padding: 34px 26px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.login-page {
|
||||
padding: 22px 12px;
|
||||
}
|
||||
|
||||
.login-shell {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.login-brand-panel {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.brand-badges {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
padding: 28px 20px;
|
||||
}
|
||||
|
||||
.login-header h2 {
|
||||
font-size: 25px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { UsuariosService } from '../services/usuarios.service';
|
||||
import { Login, Usuarios, Email, RecuperarSenha } from '../models/usuariosModel';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Modos } from '../models/variaveisModel';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
|
||||
LoginModel: Login = new Login;
|
||||
LoginError = false;
|
||||
MenssagemForm: string;
|
||||
BotaoText: string;
|
||||
TituloJanela: string;
|
||||
JanelaModo: Modos = new Modos();
|
||||
ListaDeUsuarios: Usuarios[];
|
||||
FormEmail: Email = new Email();
|
||||
FormTrocaSenha: RecuperarSenha = new RecuperarSenha();
|
||||
DesabilitaBotao: boolean = false;
|
||||
ListaTrocaSenha: RecuperarSenha[];
|
||||
LinkProjeto: string = environment.LinkProjeto;
|
||||
|
||||
constructor(
|
||||
private usuariosSerive: UsuariosService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (this.router.url.includes('esqueci')) {
|
||||
this.usuariosSerive.getUsuarios().then(resUsuarios => {
|
||||
this.ListaDeUsuarios = resUsuarios;
|
||||
})
|
||||
this.usuariosSerive.getTrocasenha().then(resTrocasenha => {
|
||||
this.ListaTrocaSenha = resTrocasenha;
|
||||
})
|
||||
this.BotaoText = "Enviar e-mail";
|
||||
this.TituloJanela = "Esqueci a senha";
|
||||
this.JanelaModo.Cadastro = true;
|
||||
}
|
||||
else if (this.router.url.includes('trocar')) {
|
||||
this.usuariosSerive.getTrocasenhaByTag(this.route.snapshot.params['tag']).then(resTag => {
|
||||
if (resTag.length > 0) {
|
||||
this.FormTrocaSenha = resTag[0];
|
||||
this.usuariosSerive.setExpirado(resTag[0]).then(resExpirado => {
|
||||
console.log("certo");
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.MenssagemForm = "Este link de redefinição de senha expirou";
|
||||
this.DesabilitaBotao = true;
|
||||
}
|
||||
})
|
||||
this.BotaoText = "Alterar senha";
|
||||
this.TituloJanela = "Digite a nova senha";
|
||||
this.JanelaModo.Editar = true;
|
||||
}
|
||||
else {
|
||||
this.BotaoText = "Entrar";
|
||||
this.TituloJanela = "Login";
|
||||
this.JanelaModo.Visualizar = true;
|
||||
}
|
||||
}
|
||||
|
||||
btnEntrarClick() {
|
||||
if (this.BotaoText == "Voltar") {
|
||||
this.router.navigate(['login']);
|
||||
return;
|
||||
}
|
||||
if (this.JanelaModo.Visualizar) { // entrar
|
||||
this.usuariosSerive.AuthUser(this.LoginModel).then(resLogin => {
|
||||
if (resLogin['response'].length > 0) {
|
||||
if (resLogin['response'][0]['habilitado'] == 0) {
|
||||
this.MenssagemForm = "Usuário ainda não ativado! Acesse a caixa de entrada de seu e-mail e ative sua conta para entrar!";
|
||||
this.LoginError = true;
|
||||
return;
|
||||
}
|
||||
localStorage.setItem("UserID", resLogin['response'][0]['idusuarios']);
|
||||
localStorage.setItem("UserName", resLogin['response'][0]['nome']);
|
||||
localStorage.setItem("Role", resLogin['response'][0]['idtiposdeusuario']);
|
||||
localStorage.setItem("Session", "1");
|
||||
|
||||
if (localStorage.getItem("Role") == "1" || localStorage.getItem("Role") == "2") {
|
||||
if (localStorage.getItem("LastRouteBeforeLogin")) {
|
||||
this.router.navigate([localStorage.getItem("LastRouteBeforeLogin")]);
|
||||
localStorage.removeItem("LastRouteBeforeLogin");
|
||||
}
|
||||
else {
|
||||
this.router.navigate(['dashboard/cliente']);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.MenssagemForm = "Usuário ou senha incorretos";
|
||||
this.LoginError = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
else if (this.JanelaModo.Cadastro) { // enviar email
|
||||
let EmailCorreto = false;
|
||||
let UsuarioCorreto = false;
|
||||
let idusuariosU: number;
|
||||
let idusuariosE: number;
|
||||
let nomeUsuario: string;
|
||||
for (let i = 0; i < this.ListaDeUsuarios.length; i++) {
|
||||
if (this.LoginModel.email == this.ListaDeUsuarios[i].email) {
|
||||
idusuariosU = this.ListaDeUsuarios[i].idusuarios;
|
||||
EmailCorreto = true;
|
||||
nomeUsuario = this.ListaDeUsuarios[i].nome;
|
||||
}
|
||||
if (this.LoginModel.usuario == this.ListaDeUsuarios[i].usuario) {
|
||||
idusuariosE = this.ListaDeUsuarios[i].idusuarios;
|
||||
UsuarioCorreto = true;
|
||||
}
|
||||
}
|
||||
if (EmailCorreto && UsuarioCorreto && (idusuariosE == idusuariosU)) {
|
||||
for (let i = 0; i < this.ListaTrocaSenha.length; i++) {
|
||||
if (this.ListaTrocaSenha[i].idusuarios == idusuariosE) {
|
||||
this.MenssagemForm = "Este usuário já tem um link de redefinição de senha pendente";
|
||||
this.BotaoText = "Voltar";
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.FormTrocaSenha.idusuarios = idusuariosE;
|
||||
this.FormEmail.Para = this.LoginModel.email;
|
||||
this.FormEmail.Assunto = "Redefinição de senha Zendion, Inc.";
|
||||
this.FormEmail.Conteudo = this.MensagemEmail(nomeUsuario);
|
||||
this.usuariosSerive.insertTrocasenha(this.FormTrocaSenha).then(resTrocasenha => {
|
||||
if (resTrocasenha['status'] == 200) {
|
||||
this.usuariosSerive.EnviarEmail(this.FormEmail).then(resEmail => {
|
||||
if (resEmail != null && resEmail['sucesso'] == true) {
|
||||
this.MenssagemForm = "Link de redefinição de senha enviado com sucesso!";
|
||||
this.BotaoText = "Voltar";
|
||||
}
|
||||
else {
|
||||
this.MenssagemForm = "Erro ao enviar e-mail";
|
||||
this.LoginError = true;
|
||||
this.BotaoText = "Voltar";
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.MenssagemForm = "Erro ao gerar link de redefinição de senha";
|
||||
this.LoginError = true;
|
||||
this.BotaoText = "Voltar";
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.LoginError = true;
|
||||
if (!EmailCorreto)
|
||||
this.MenssagemForm = "E-mail incorreto";
|
||||
if (!UsuarioCorreto)
|
||||
this.MenssagemForm = "Usuário incorreto";
|
||||
if (!EmailCorreto && !UsuarioCorreto)
|
||||
this.MenssagemForm = "Usuário e E-mail incorretos";
|
||||
if (idusuariosE != idusuariosU)
|
||||
this.MenssagemForm = "Usuário ou E-mail incorreto";
|
||||
}
|
||||
}
|
||||
else if (this.JanelaModo.Editar) { // inserir nova senha
|
||||
if (this.LoginModel.senha != this.LoginModel.novasenha) {
|
||||
this.LoginError = true;
|
||||
this.MenssagemForm = "As senhas digitadas não são iguais";
|
||||
return;
|
||||
}
|
||||
let formUsuario: Usuarios = new Usuarios();
|
||||
formUsuario.idusuarios = this.FormTrocaSenha.idusuarios;
|
||||
formUsuario.senha = this.LoginModel.senha;
|
||||
this.usuariosSerive.trocaSenha(formUsuario).then(resUpdate => {
|
||||
if (resUpdate['status'] == 200) {
|
||||
this.MenssagemForm = "Senha alterada com sucesso";
|
||||
}
|
||||
else {
|
||||
this.MenssagemForm = "Erro ao alterar senha";
|
||||
}
|
||||
this.BotaoText = "Voltar";
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
MensagemEmail(nomeUsuario: string) {
|
||||
let Mensagem: string;
|
||||
|
||||
const nome = nomeUsuario || 'usuário';
|
||||
|
||||
// Melhor que Math.random para token simples no frontend
|
||||
const array = new Uint32Array(4);
|
||||
window.crypto.getRandomValues(array);
|
||||
|
||||
const Tag = Array.from(array)
|
||||
.map(x => x.toString(16))
|
||||
.join('');
|
||||
|
||||
this.FormTrocaSenha.tag = Tag;
|
||||
|
||||
const linkTrocaSenha = `${this.LinkProjeto}/login/trocar/${Tag}`;
|
||||
|
||||
Mensagem = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Redefinição de senha Zendion, INC.</title>
|
||||
</head>
|
||||
|
||||
<body style="margin:0; padding:0; background-color:#f4f6fb; font-family:Arial, Helvetica, sans-serif; color:#1f2937;">
|
||||
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f6fb; padding:32px 12px;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="max-width:620px; background-color:#ffffff; border-radius:14px; overflow:hidden; box-shadow:0 6px 24px rgba(15, 23, 42, 0.08);">
|
||||
|
||||
<!-- Header -->
|
||||
<tr>
|
||||
<td style="background-color:#071b63; padding:26px 32px; text-align:center;">
|
||||
<img src="${this.LinkProjeto}/assets/logo_escrito.png" alt="Zendion, INC." style="height:54px; max-width:220px; display:inline-block;">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Title -->
|
||||
<tr>
|
||||
<td style="padding:34px 34px 10px 34px;">
|
||||
<h1 style="margin:0; color:#111827; font-size:24px; line-height:32px; font-weight:700;">
|
||||
Redefinição de senha
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Greeting -->
|
||||
<tr>
|
||||
<td style="padding:8px 34px 0 34px;">
|
||||
<p style="margin:0 0 18px 0; font-size:16px; line-height:26px; color:#374151;">
|
||||
Olá, <strong>${nome}</strong>!
|
||||
</p>
|
||||
|
||||
<p style="margin:0 0 18px 0; font-size:16px; line-height:26px; color:#374151;">
|
||||
Recebemos uma solicitação para redefinir a senha da sua conta na <strong>Zendion, INC.</strong>.
|
||||
</p>
|
||||
|
||||
<p style="margin:0 0 24px 0; font-size:16px; line-height:26px; color:#374151;">
|
||||
Para criar uma nova senha, clique no botão abaixo:
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Button -->
|
||||
<tr>
|
||||
<td align="center" style="padding:8px 34px 30px 34px;">
|
||||
<a href="${linkTrocaSenha}" target="_blank" style="display:inline-block; background-color:#071b63; color:#ffffff; text-decoration:none; font-size:16px; font-weight:700; padding:14px 28px; border-radius:8px;">
|
||||
Redefinir minha senha
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Expiration notice -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 28px 34px;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#fff7ed; border-left:4px solid #f97316; border-radius:8px;">
|
||||
<tr>
|
||||
<td style="padding:16px 18px;">
|
||||
<p style="margin:0; font-size:14px; line-height:22px; color:#7c2d12;">
|
||||
Este link é válido por <strong>24 horas</strong>. Após esse período, será necessário solicitar uma nova redefinição de senha.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Fallback link -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 30px 34px;">
|
||||
<p style="margin:0 0 8px 0; font-size:13px; line-height:21px; color:#6b7280;">
|
||||
Se o botão não funcionar, copie e cole este link no navegador:
|
||||
</p>
|
||||
|
||||
<p style="margin:0; font-size:13px; line-height:21px; word-break:break-all;">
|
||||
<a href="${linkTrocaSenha}" target="_blank" style="color:#071b63; text-decoration:underline;">
|
||||
${linkTrocaSenha}
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Security note -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 32px 34px;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f8fafc; border-left:4px solid #071b63; border-radius:8px;">
|
||||
<tr>
|
||||
<td style="padding:16px 18px;">
|
||||
<p style="margin:0; font-size:14px; line-height:22px; color:#4b5563;">
|
||||
Se você não solicitou a redefinição de senha, ignore este e-mail. Sua senha atual continuará a mesma.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Signature -->
|
||||
<tr>
|
||||
<td style="padding:0 34px 32px 34px;">
|
||||
<p style="margin:0; font-size:15px; line-height:24px; color:#374151;">
|
||||
Atenciosamente,<br>
|
||||
<strong>Equipe Zendion, INC.</strong>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr>
|
||||
<td style="background-color:#071b63; padding:22px 34px; text-align:center;">
|
||||
<p style="margin:0 0 8px 0; font-size:13px; line-height:20px; color:#ffffff;">
|
||||
Zendion, INC.
|
||||
</p>
|
||||
|
||||
<p style="margin:0; font-size:12px; line-height:20px; color:#cbd5e1;">
|
||||
${environment.telefoneContato}<br>
|
||||
${environment.emailContato}<br>
|
||||
<a href="${this.LinkProjeto}" target="_blank" style="color:#ffffff; text-decoration:none;">
|
||||
${this.LinkProjeto}
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<!-- Legal bottom -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="max-width:620px;">
|
||||
<tr>
|
||||
<td style="padding:18px 12px 0 12px; text-align:center;">
|
||||
<p style="margin:0; font-size:11px; line-height:18px; color:#9ca3af;">
|
||||
Este é um e-mail automático. Por favor, não responda esta mensagem.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return Mensagem;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
export class AgrobaseVersionFileModel {
|
||||
id: number;
|
||||
Diretorio: string;
|
||||
Arquivo: string;
|
||||
Extensao: string;
|
||||
Versao: string;
|
||||
ArquivoDownload: string;
|
||||
TipoArquivo: TiposArquivos;
|
||||
}
|
||||
|
||||
export enum TiposArquivos {
|
||||
ModeloIA_StreetDetector = 0,
|
||||
ModeloIA_WeedDetector = 1,
|
||||
ParametrosModulo_ATU = 2,
|
||||
ParametrosModulo_MVD = 3,
|
||||
ParametrosModulo_SEN = 4,
|
||||
ParametrosModulo_KNT = 5,
|
||||
PinoutModulo_ATU = 6,
|
||||
PinoutModulo_SEN = 7,
|
||||
Script_StreetDetector = 8,
|
||||
Script_WeedDetector = 9,
|
||||
Script_GreenDetector = 10,
|
||||
Script_MapLoad = 11,
|
||||
Script_MapFollow = 12,
|
||||
Script_GpsViewer = 13,
|
||||
ArquivoModelo3D = 14,
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
export class BingoSorteiosModel {
|
||||
idbingosorteios: number = 0;
|
||||
descricao: string = "";
|
||||
rodada: number = 1;
|
||||
data_sorteio: string;
|
||||
n_max: number = 75;
|
||||
participantes_max: number = 0;
|
||||
realizado: boolean = false;
|
||||
Cartelas: BingoCartelasModel[];
|
||||
VerCartelas: boolean = false;
|
||||
}
|
||||
|
||||
export class BingoCartelasModel {
|
||||
canhoto: number = 0;
|
||||
idbingosorteios: number = 0;
|
||||
numeros: string = "";
|
||||
nome: string = "";
|
||||
endereco: string = "";
|
||||
telefone: string = "";
|
||||
bingo: boolean = false;
|
||||
cinquina1: boolean = false;
|
||||
cinquina2: boolean = false;
|
||||
cinquina3: boolean = false;
|
||||
Valida: boolean = true;
|
||||
Editando: boolean = false;
|
||||
Acertos: number = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export class MenuItem {
|
||||
index: number;
|
||||
texto: string;
|
||||
link: string;
|
||||
havesub: boolean;
|
||||
dropicon: string;
|
||||
icon: string;
|
||||
issub: boolean;
|
||||
sub: MenuItem[];
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
export class Noticias {
|
||||
idnoticias: number;
|
||||
titulo: string;
|
||||
descricao: string;
|
||||
habilitado: boolean;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export class NoticiasList {
|
||||
idnoticias: number;
|
||||
titulo: string;
|
||||
descricao: string;
|
||||
habilitado: string;
|
||||
link: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
export class OrionLogsModel {
|
||||
dataLog: Date;
|
||||
nome: string;
|
||||
coordenadas: string;
|
||||
perfil: string;
|
||||
log: string;
|
||||
logObj: OrionLogsDetalhesModel;
|
||||
}
|
||||
|
||||
export class OrionLogsDetalhesModel {
|
||||
data: Date;
|
||||
firmwareVersao: number;
|
||||
robotNs: number;
|
||||
modelo: string;
|
||||
versao: string;
|
||||
cpf: string;
|
||||
usuario: string;
|
||||
perfil: string;
|
||||
camera: string;
|
||||
servico: OrionLogServicoModel;
|
||||
odometroTotal: number;
|
||||
odometroConectado: number;
|
||||
odometroMotores: number;
|
||||
odometroMotoresParcial: number;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
altitude: number;
|
||||
tempoTotal: number;
|
||||
tempoConectado: number;
|
||||
sensores: OrionLogSensorModel[];
|
||||
portaCOM: string;
|
||||
baudRate: number;
|
||||
conectado: boolean;
|
||||
distancia: number;
|
||||
|
||||
HoraInicio: string;
|
||||
HoraFim: string;
|
||||
Duracao: string;
|
||||
Coordenadas: string;
|
||||
Localizacao: string;
|
||||
}
|
||||
|
||||
export class OrionLogServicoModel {
|
||||
Nome: string;
|
||||
Cidade: string;
|
||||
Responsavel: string;
|
||||
Servico: string;
|
||||
Path: string;
|
||||
DataCadastro: Date;
|
||||
}
|
||||
|
||||
export class OrionLogSensorModel {
|
||||
sensor: number;
|
||||
descricao: string;
|
||||
minimo: number;
|
||||
maximo: number;
|
||||
media: number;
|
||||
moda: number;
|
||||
mediana: number;
|
||||
lista: number[];
|
||||
}
|
||||
|
||||
export class GeoCoordenadasResponseModel {
|
||||
data: GeoCoordenadasModel[];
|
||||
}
|
||||
|
||||
export class GeoCoordenadasModel {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
type: string;
|
||||
distance: number;
|
||||
name: string;
|
||||
number: string;
|
||||
postal_code: string;
|
||||
street: string;
|
||||
confidence: number;
|
||||
region: string;
|
||||
region_code: string;
|
||||
county: string;
|
||||
lacality: string;
|
||||
administrative_area: string;
|
||||
neighborhood: string;
|
||||
country: string;
|
||||
country_code: string;
|
||||
continent: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export class LogAgrupado {
|
||||
key: string;
|
||||
value: OrionLogsDetalhesModel[];
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export class ProdutosModel {
|
||||
idprodutos: number;
|
||||
idsistemas: number;
|
||||
idtiposlicenca: number;
|
||||
valor: number;
|
||||
ativado: boolean;
|
||||
descricao: string;
|
||||
vendas: number;
|
||||
compensados: number;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
export class Sistemas {
|
||||
idsistemas: number;
|
||||
nome: string;
|
||||
descricao: string;
|
||||
versaoatual: string;
|
||||
habilitado: boolean;
|
||||
downloads: number;
|
||||
idtiposdesistema: number;
|
||||
idplataformas: number;
|
||||
nome_install: string;
|
||||
notasdeatualizacao: string;
|
||||
idtiposlicenca: number;
|
||||
|
||||
insert_date: Date;
|
||||
}
|
||||
|
||||
export class SistemasLista {
|
||||
idsistemas: number;
|
||||
nome: string;
|
||||
descricao: string;
|
||||
versaoatual: string;
|
||||
habilitado: boolean;
|
||||
downloads: number;
|
||||
idtiposdesistema: number;
|
||||
tiposdesistema: string;
|
||||
idplataformas: number;
|
||||
plataforma: string;
|
||||
nome_install: string;
|
||||
notasdeatualizacao: string;
|
||||
idtiposlicenca: number;
|
||||
licenca: string;
|
||||
custo: number;
|
||||
versoes: string[];
|
||||
mdownloads: string[];
|
||||
|
||||
tiposlicenca: string;
|
||||
insert_date: Date;
|
||||
update_date: Date;
|
||||
}
|
||||
|
||||
export class TiposDeLicenca {
|
||||
idtiposlicenca: number;
|
||||
descricao: string;
|
||||
}
|
||||
|
||||
|
||||
export class TiposDeSistema {
|
||||
idtiposdesistema: number;
|
||||
descricao: string;
|
||||
}
|
||||
|
||||
export class Plataformas {
|
||||
idplataformas: number;
|
||||
descricao: string;
|
||||
}
|
||||
|
||||
export class Download {
|
||||
idsistemas: number;
|
||||
idusuarios: number;
|
||||
}
|
||||
|
||||
export class Chaves {
|
||||
idchaves: number;
|
||||
licenca: string;
|
||||
data_criacao: Date;
|
||||
data_validade: Date;
|
||||
idusuarios: number;
|
||||
usada: boolean;
|
||||
idsistemas: number;
|
||||
}
|
||||
|
||||
export class ListChaves {
|
||||
idchaves: number;
|
||||
Chave: string;
|
||||
DataCriacao: Date;
|
||||
DataValidade: Date;
|
||||
Status: string;
|
||||
Ativada: string;
|
||||
}
|
||||
|
||||
export class SistemasDetalhes {
|
||||
idsistemasdetalhes: number;
|
||||
idsistemas: number;
|
||||
descricao: string;
|
||||
ordem: number;
|
||||
habilitado: boolean;
|
||||
imagem: string;
|
||||
botao: string;
|
||||
Arquivo: File;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
export class Slides {
|
||||
idslides: number;
|
||||
descricao: string;
|
||||
habilitado: boolean;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export class SlidesList {
|
||||
idslides: number;
|
||||
descricao: string;
|
||||
habilitado: string;
|
||||
link: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
export class Usuarios {
|
||||
idusuarios: number;
|
||||
nome: string;
|
||||
usuario: string;
|
||||
senha: string;
|
||||
data_cadastro: Date;
|
||||
cpf: string;
|
||||
habilitado: boolean;
|
||||
email: string;
|
||||
idtiposdeusuario: number;
|
||||
}
|
||||
|
||||
export class Login {
|
||||
usuario: string;
|
||||
senha: string;
|
||||
email: string;
|
||||
novasenha: string;
|
||||
}
|
||||
|
||||
export class TiposDeUsuario {
|
||||
idtiposdeusuario: string;
|
||||
descricao: string;
|
||||
}
|
||||
|
||||
export class Email {
|
||||
Para: string;
|
||||
Assunto: string;
|
||||
Conteudo: string;
|
||||
}
|
||||
|
||||
export class SistemasDoUsuario {
|
||||
idsistemas: number;
|
||||
nome: string;
|
||||
descricao: string;
|
||||
data_download: Date;
|
||||
idusuarios: number;
|
||||
licensasValidas: number;
|
||||
gratis: boolean;
|
||||
}
|
||||
|
||||
export class RecuperarSenha {
|
||||
idtrocasenha: number;
|
||||
idusuarios: number;
|
||||
tag: string;
|
||||
usada: boolean;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export class Variaveis {
|
||||
LinkAPI: string;
|
||||
LinkProjeto: string;
|
||||
}
|
||||
|
||||
export class Modos {
|
||||
Cadastro: boolean = false;
|
||||
Editar: boolean = false;
|
||||
Visualizar: boolean = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
<div class="news-admin-page">
|
||||
|
||||
<!-- HEADER -->
|
||||
<section class="admin-hero">
|
||||
<div>
|
||||
<span class="eyebrow">Backoffice</span>
|
||||
<h1>{{ TituloJanela }}</h1>
|
||||
<p>
|
||||
Gerencie as notícias exibidas na página inicial do site.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="admin-hero-actions" *ngIf="JanelaModo.Visualizar">
|
||||
<button type="button" class="btn-main" (click)="NovaNoticia()">
|
||||
<i class="material-icons">post_add</i>
|
||||
Nova notícia
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FORM CADASTRO / EDIÇÃO -->
|
||||
<section class="admin-card form-panel" *ngIf="JanelaModo.Cadastro || JanelaModo.Editar">
|
||||
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Conteúdo editorial</span>
|
||||
<h2>{{ JanelaModo.Cadastro ? 'Cadastrar notícia' : 'Editar notícia' }}</h2>
|
||||
</div>
|
||||
|
||||
<label class="status-toggle">
|
||||
<input type="checkbox" [(ngModel)]="FormNoticias.habilitado">
|
||||
|
||||
<span class="toggle-box">
|
||||
<i class="material-icons">{{ FormNoticias.habilitado ? 'check_circle' : 'block' }}</i>
|
||||
{{ FormNoticias.habilitado ? 'Habilitada' : 'Desabilitada' }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-grid">
|
||||
<div class="form-group full">
|
||||
<label>Título</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Título da notícia"
|
||||
[(ngModel)]="FormNoticias.titulo">
|
||||
</div>
|
||||
|
||||
<div class="form-group full">
|
||||
<label>Descrição / conteúdo</label>
|
||||
<textarea
|
||||
[(ngModel)]="FormNoticias.descricao"
|
||||
class="form-control textarea-control"
|
||||
placeholder="Digite o conteúdo da notícia. Pode conter HTML simples, como <p>, <strong>, <br>...">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group full">
|
||||
<label>Link</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="Link opcional relacionado à notícia"
|
||||
[(ngModel)]="FormNoticias.link">
|
||||
</div>
|
||||
|
||||
<div class="form-group full">
|
||||
<label>Imagem</label>
|
||||
|
||||
<label class="file-label">
|
||||
<i class="material-icons">upload_file</i>
|
||||
Selecionar imagem
|
||||
<input type="file" (change)="onFileChangedIcone($event)" accept=".jpg,.jpeg,.png">
|
||||
</label>
|
||||
|
||||
<small class="field-hint">
|
||||
Recomendado: imagem horizontal em boa resolução, preferencialmente JPG.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="news-preview-section" *ngIf="CaminhoImagem != null">
|
||||
<span>Prévia da notícia</span>
|
||||
|
||||
<article class="news-preview-card">
|
||||
<div class="news-preview-image">
|
||||
<img [src]="CaminhoImagem" alt="Prévia da notícia">
|
||||
</div>
|
||||
|
||||
<div class="news-preview-content">
|
||||
<small>{{ FormNoticias.habilitado ? 'Publicada' : 'Oculta' }}</small>
|
||||
|
||||
<h3>{{ FormNoticias.titulo || 'Título da notícia' }}</h3>
|
||||
|
||||
<div
|
||||
class="news-preview-description"
|
||||
[innerHTML]="FormNoticias.descricao || 'A descrição da notícia aparecerá aqui.'">
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div *ngIf="MensagemForm" class="form-message">
|
||||
<i class="material-icons">info</i>
|
||||
<span>{{ MensagemForm }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn-secondary" (click)="VoltarLista()">
|
||||
Cancelar
|
||||
</button>
|
||||
|
||||
<button type="submit" class="btn-main form-submit" (click)="btnCadastrarClick()">
|
||||
<i class="material-icons">{{ JanelaModo.Cadastro ? 'save' : 'edit' }}</i>
|
||||
{{ TextoBotao }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- VISUALIZAR -->
|
||||
<section class="admin-list" *ngIf="JanelaModo.Visualizar">
|
||||
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon">
|
||||
<i class="material-icons">article</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Total de notícias</span>
|
||||
<strong>{{ ListaNoticias?.length || 0 }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon active">
|
||||
<i class="material-icons">visibility</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Habilitadas</span>
|
||||
<strong>{{ TotalHabilitadas }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="summary-icon blocked">
|
||||
<i class="material-icons">visibility_off</i>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>Desabilitadas</span>
|
||||
<strong>{{ TotalDesabilitadas }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-card news-panel">
|
||||
<div class="panel-header">
|
||||
<div>
|
||||
<span class="eyebrow">Notícias</span>
|
||||
<h2>Notícias cadastradas</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="ListaNoticias && ListaNoticias.length > 0" class="news-grid">
|
||||
|
||||
<article
|
||||
class="news-card"
|
||||
*ngFor="let Noticia of ListaNoticias"
|
||||
[ngClass]="Noticia.habilitado ? 'news-enabled' : 'news-disabled'">
|
||||
|
||||
<div class="news-image-wrapper">
|
||||
<img
|
||||
[src]="LinkImagemNoticia(Noticia)"
|
||||
alt="Imagem da notícia"
|
||||
class="news-image">
|
||||
</div>
|
||||
|
||||
<div class="news-card-body">
|
||||
<div class="news-card-header">
|
||||
<span class="id-pill">#{{ Noticia.idnoticias }}</span>
|
||||
|
||||
<span class="status-badge" [ngClass]="Noticia.habilitado ? 'enabled' : 'disabled'">
|
||||
{{ Noticia.habilitado ? 'Habilitada' : 'Desabilitada' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3>{{ Noticia.titulo || 'Notícia sem título' }}</h3>
|
||||
|
||||
<div class="news-description" [innerHTML]="Noticia.descricao"></div>
|
||||
|
||||
<div class="news-link" *ngIf="Noticia.link">
|
||||
<i class="material-icons">link</i>
|
||||
<span>{{ Noticia.link }}</span>
|
||||
</div>
|
||||
|
||||
<div class="news-actions">
|
||||
<button type="button" class="btn-card edit" (click)="EditarNoticia(Noticia)">
|
||||
<i class="material-icons">edit</i>
|
||||
Editar
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn-card remove" (click)="RemoverNoticia(Noticia)">
|
||||
<i class="material-icons">delete</i>
|
||||
Remover
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="!ListaNoticias || ListaNoticias.length == 0" class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<i class="material-icons">article</i>
|
||||
</div>
|
||||
|
||||
<h3>Nenhuma notícia cadastrada</h3>
|
||||
|
||||
<p>
|
||||
Cadastre a primeira notícia para exibir conteúdo na página inicial.
|
||||
</p>
|
||||
|
||||
<button type="button" class="btn-main empty-btn" (click)="NovaNoticia()">
|
||||
<i class="material-icons">post_add</i>
|
||||
Criar primeira notícia
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue