cambio de inf en los reportes
This commit is contained in:
Binary file not shown.
Binary file not shown.
+18
-17
@@ -1,27 +1,28 @@
|
||||
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
||||
import { Body, Controller, Get, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { UpdateUsuarioDto } from 'src/usuarios/dto/update-usuario.dto';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor( private readonly authService:AuthService){}
|
||||
|
||||
@Post("registro")
|
||||
registro(@Body() registroDto:CreateUsuarioDto ){
|
||||
return this.authService.registro(registroDto);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Post("login")
|
||||
login(@Body() loginDto:LoginDto){
|
||||
return this.authService.login(loginDto);
|
||||
}
|
||||
|
||||
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
@Post('registro')
|
||||
registro(@Body() registroDto: CreateUsuarioDto) {
|
||||
return this.authService.registro(registroDto);
|
||||
}
|
||||
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
@Patch('update')
|
||||
update(@Body() registroDto: UpdateUsuarioDto) {
|
||||
return this.authService.update(registroDto);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
login(@Body() loginDto: LoginDto) {
|
||||
return this.authService.login(loginDto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as bcrypt from 'bcryptjs';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { CreateUsuarioDto } from 'src/usuarios/dto/create-usuario.dto';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { UpdateUsuarioDto } from 'src/usuarios/dto/update-usuario.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@@ -17,6 +18,18 @@ export class AuthService {
|
||||
private readonly jwtService: JwtService,
|
||||
) {}
|
||||
|
||||
async update(registroDto: UpdateUsuarioDto) {
|
||||
const update_data = await this.usuarioService.actualizarUsuario(
|
||||
registroDto.id_User,
|
||||
{
|
||||
nombre: registroDto.nombre,
|
||||
contraseña: registroDto.contraseña,
|
||||
id_tipo_usuario: registroDto.tipoUsuario,
|
||||
},
|
||||
);
|
||||
return update_data;
|
||||
}
|
||||
|
||||
async registro({ nombre, contraseña, tipoUsuario }: CreateUsuarioDto) {
|
||||
const usuario = await this.usuarioService.findOneByName(nombre);
|
||||
if (usuario) {
|
||||
|
||||
@@ -351,15 +351,20 @@ let tabletas = ['TABLETA ANDROID', 'TABLETA iPAD OS'];
|
||||
let impresoras = [
|
||||
'INYECCIÓN TINTA',
|
||||
'LÁSER DE ALTO VOLUMEN B/N',
|
||||
'LÁSER DE ALTO VOLUMEN COLOR',
|
||||
'LÁSER PEQUEÑA B/N',
|
||||
'LÁSER PEQUEÑA COLOR',
|
||||
'MATRIZ DE PUNTOS',
|
||||
'MULTIFUNCIONALES',
|
||||
'3D',
|
||||
'IMPRESORA TÉRMICA',
|
||||
'IMPRESORA CREDENCIALES',
|
||||
'PLOTTER',
|
||||
];
|
||||
|
||||
let dijitales = [
|
||||
'3D',
|
||||
'DIGITALIZADOR DE CAMA PLANA PARA OFICINA',
|
||||
'DIGITALIZADOR DE GRAN VOLUMEN',
|
||||
'DIGITALIZADOR CON ALIMENTADOR DE HOJAS PARA OFICINA',
|
||||
];
|
||||
|
||||
|
||||
@@ -359,11 +359,52 @@ export class EquipoService {
|
||||
}
|
||||
|
||||
async createEcxel(res: Response) {
|
||||
let obj = await this.generar_reporte();
|
||||
const objectParse = Array.isArray(obj)
|
||||
? obj.map((item) => this.flattenObject(item))
|
||||
: [this.flattenObject(obj)];
|
||||
return this.exportToClient(objectParse, res);
|
||||
const data = await this.generar_reporte();
|
||||
return this.exportarReporteAExcel(data, res);
|
||||
}
|
||||
|
||||
async exportarReporteAExcel(data: any, res: Response) {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
|
||||
for (const key of Object.keys(data)) {
|
||||
const sheetName = key.substring(0, 30); // Excel limita a 30 caracteres
|
||||
const sheet = workbook.addWorksheet(sheetName);
|
||||
|
||||
const rows = data[key];
|
||||
|
||||
if (!Array.isArray(rows) || rows.length === 0) {
|
||||
sheet.addRow([`(sin datos)`]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Obtener columnas automáticamente
|
||||
const headers = Object.keys(rows[0]);
|
||||
|
||||
// Crear encabezado
|
||||
sheet.addRow(headers);
|
||||
|
||||
// Agregar filas
|
||||
for (const row of rows) {
|
||||
sheet.addRow(headers.map((h) => row[h]));
|
||||
}
|
||||
|
||||
// Estilo básico
|
||||
sheet.getRow(1).font = { bold: true };
|
||||
sheet.getRow(1).alignment = { horizontal: 'center' };
|
||||
sheet.columns.forEach((col) => {
|
||||
col.width = 35;
|
||||
});
|
||||
}
|
||||
|
||||
// Enviar el archivo al cliente
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
);
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=reporte.xlsx');
|
||||
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
}
|
||||
|
||||
async createReport() {
|
||||
@@ -441,10 +482,8 @@ export class EquipoService {
|
||||
.createQueryBuilder('e')
|
||||
.innerJoin('e.tipoEquipo', 't')
|
||||
.where('t.tipo_equipo IN (:...tipo_equipo)', { tipo_equipo })
|
||||
.select(['t.tipo_equipo AS tipo_equipo'])
|
||||
.addSelect('COUNT(*) AS total')
|
||||
.groupBy('t.tipo_equipo')
|
||||
.getRawMany();
|
||||
.select('COUNT(*) AS total')
|
||||
.getRawOne();
|
||||
|
||||
return count;
|
||||
} catch (error) {
|
||||
@@ -489,27 +528,21 @@ export class EquipoService {
|
||||
.groupBy('e.antiguedad')
|
||||
.getRawMany();
|
||||
|
||||
interface Porcentaje {
|
||||
antiguedad: any;
|
||||
total: any;
|
||||
porcentaje: string;
|
||||
}
|
||||
|
||||
return {
|
||||
escritorios: countEscritorios.map((i) => ({
|
||||
antiguedad: i.antiguedad,
|
||||
total: i.total,
|
||||
porcentaje: ((i.total / totalEscrtitorio) * 100).toFixed(2),
|
||||
porcentaje: ((i.total / totalEscrtitorio.total) * 100).toFixed(2),
|
||||
})),
|
||||
portatiles: countPortatiles.map((i) => ({
|
||||
antiguedad: i.antiguedad,
|
||||
total: i.total,
|
||||
porcentaje: ((i.total / totalPortatiles) * 100).toFixed(2),
|
||||
porcentaje: ((i.total / totalPortatiles.total) * 100).toFixed(2),
|
||||
})),
|
||||
altoRendimiento: countAltoRendimiento.map((i) => ({
|
||||
antiguedad: i.antiguedad,
|
||||
total: i.total,
|
||||
porcentaje: ((i.total / totalAltoRendimiento) * 100).toFixed(2),
|
||||
porcentaje: ((i.total / totalAltoRendimiento.total) * 100).toFixed(2),
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -596,20 +629,25 @@ export class EquipoService {
|
||||
}> {
|
||||
try {
|
||||
// Helper para obtener total por tipos de equipo (count simple, sin group by)
|
||||
const getTotalPorTipos = async (tipos: string[]): Promise<number> => {
|
||||
const getTotalPorTipos = async (tipos: string[]): Promise<any> => {
|
||||
if (!tipos || tipos.length === 0) return 0;
|
||||
return this.equipoRepository
|
||||
.createQueryBuilder('e')
|
||||
.innerJoin('e.tipoEquipo', 't')
|
||||
.where('t.tipo_equipo IN (:...tipos)', { tipos })
|
||||
.getCount();
|
||||
.innerJoin('e.periferico', 'p')
|
||||
.where('p.periferico IN (:...tipos)', { tipos })
|
||||
.select('COUNT(*) AS total')
|
||||
.getRawOne();
|
||||
};
|
||||
|
||||
// Ejecutar ambos totales en paralelo
|
||||
const [totalImpresion, totalDigitalizacion] = await Promise.all([
|
||||
|
||||
const [totalI, totalD] = await Promise.all([
|
||||
getTotalPorTipos(impresion),
|
||||
getTotalPorTipos(digitalizacion),
|
||||
]);
|
||||
const totalImpresion = totalI.total;
|
||||
|
||||
const totalDigitalizacion = totalD.total;
|
||||
|
||||
// Obtener conteos por antiguedad para impresion
|
||||
const countImpresionPromise = this.equipoRepository
|
||||
@@ -641,6 +679,11 @@ export class EquipoService {
|
||||
countDigitalizacionPromise,
|
||||
]);
|
||||
|
||||
console.log('I', totalImpresion);
|
||||
console.log('D', totalDigitalizacion);
|
||||
console.log('I', countImpresion);
|
||||
console.log('D', countDigitalizacion);
|
||||
|
||||
// Tipo para salida
|
||||
interface Porcentaje {
|
||||
antiguedad: any;
|
||||
|
||||
@@ -1,4 +1,29 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateUsuarioDto } from './create-usuario.dto';
|
||||
import { DefaultValuePipe } from '@nestjs/common';
|
||||
import { Transform } from 'class-transformer';
|
||||
import {
|
||||
IsInt,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MinLength,
|
||||
} from 'class-validator';
|
||||
|
||||
export class UpdateUsuarioDto extends PartialType(CreateUsuarioDto) {}
|
||||
export class UpdateUsuarioDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
id_User: number;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
nombre?: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(5)
|
||||
@Transform(({ value }) => value.trim())
|
||||
@IsOptional()
|
||||
contraseña?: string;
|
||||
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
tipoUsuario?: number;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { CreateUsuarioDto } from './dto/create-usuario.dto';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Tipo_Usuario, Usuario } from './entities/usuario.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
|
||||
@Injectable()
|
||||
export class UsuariosService {
|
||||
@@ -13,6 +18,49 @@ export class UsuariosService {
|
||||
@InjectRepository(Tipo_Usuario)
|
||||
private readonly tipoUsuarioRepository: Repository<Tipo_Usuario>,
|
||||
) {}
|
||||
|
||||
async actualizarUsuario(
|
||||
id: number,
|
||||
datos: { nombre?: string; contraseña?: string; id_tipo_usuario?: number },
|
||||
) {
|
||||
// Buscar al usuario
|
||||
const usuario = await this.usuarioRepository.findOne({
|
||||
where: { id_usuario: id },
|
||||
relations: ['tipoUsuario'],
|
||||
});
|
||||
|
||||
if (!usuario) {
|
||||
throw new NotFoundException('Usuario no encontrado');
|
||||
}
|
||||
|
||||
// Actualizar nombre
|
||||
if (datos.nombre) {
|
||||
usuario.nombre = datos.nombre;
|
||||
}
|
||||
|
||||
// Actualizar contraseña con hash
|
||||
if (datos.contraseña) {
|
||||
const hashed = await bcrypt.hash(datos.contraseña, 10);
|
||||
usuario.contraseña = hashed;
|
||||
}
|
||||
|
||||
// Actualizar tipo de usuario
|
||||
if (datos.id_tipo_usuario) {
|
||||
const tipo = await this.tipoUsuarioRepository.findOne({
|
||||
where: { id_tipo_usuario: datos.id_tipo_usuario },
|
||||
});
|
||||
|
||||
if (!tipo) {
|
||||
throw new BadRequestException('El tipo de usuario no existe');
|
||||
}
|
||||
|
||||
usuario.tipoUsuario = tipo;
|
||||
}
|
||||
|
||||
// Guardar cambios
|
||||
return await this.usuarioRepository.save(usuario);
|
||||
}
|
||||
|
||||
async create(createUsuarioDto: CreateUsuarioDto) {
|
||||
let user = await this.usuarioRepository.create({
|
||||
nombre: createUsuarioDto.nombre,
|
||||
|
||||
Reference in New Issue
Block a user