parent
58529b477e
commit
e8135d40d2
@ -1,2 +1,2 @@ |
|||||||
REACT_APP_ENVIRONMENT=qa |
REACT_APP_ENVIRONMENT=qa |
||||||
REACT_APP_API=https://www.gemcousa.solutions/GEMCOBackend/api |
REACT_APP_API=https://www.adminusa.gemcousa.solutions/GEMCOBackend/api |
@ -1,119 +0,0 @@ |
|||||||
|
|
||||||
import * as React from 'react'; |
|
||||||
import { useState } from 'react'; |
|
||||||
import { Button, Card, Form } from 'react-bootstrap'; |
|
||||||
import ExelServices from '../../../Utils/ExelFiles/Exel.services'; |
|
||||||
import { FiSend } from "react-icons/fi"; |
|
||||||
import { MsgInformativo } from '../../../Utils/Toast/msgInformativo'; |
|
||||||
import * as XLSX from 'xlsx'; |
|
||||||
|
|
||||||
export default function FileUploadExel() { |
|
||||||
const [WorkingHoursFile, setWorkingHoursFile] = useState<File | null>(null); |
|
||||||
const [showToast, setShowToast] = useState<boolean>(false); |
|
||||||
const [toastMsg, setToastMsg] = useState<string>(''); |
|
||||||
const [toastHeader, setToastHeader] = useState<string>(''); |
|
||||||
const [toastColor, setToastColor] = useState<string>(''); |
|
||||||
|
|
||||||
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => { |
|
||||||
let file = event.target.files?.[0] || null; |
|
||||||
|
|
||||||
if (file && file.name.endsWith('.xls')) { |
|
||||||
// Convertir XLS a XLSX usando la biblioteca xlsx
|
|
||||||
const data = await file.arrayBuffer(); |
|
||||||
const workbook = XLSX.read(data, { type: 'array' }); |
|
||||||
const convertedData = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); |
|
||||||
file = new File([convertedData], file.name.replace('.xls', '.xlsx'), { |
|
||||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
setWorkingHoursFile(file); |
|
||||||
}; |
|
||||||
|
|
||||||
const handleSendFiles = async () => { |
|
||||||
if (!WorkingHoursFile) { |
|
||||||
setToastMsg('No hay archivos para enviar'); |
|
||||||
setToastHeader('Error'); |
|
||||||
setToastColor('danger'); |
|
||||||
setShowToast(true); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
const formDataBook = new FormData(); |
|
||||||
formDataBook.append('file', WorkingHoursFile); |
|
||||||
|
|
||||||
try { |
|
||||||
const responseBook = await ExelServices.uploadWorkingHours(formDataBook); |
|
||||||
|
|
||||||
if (!responseBook || responseBook.status !== 200) { |
|
||||||
throw new Error('Error al subir el archivo de horas de trabajo'); |
|
||||||
} |
|
||||||
|
|
||||||
setToastMsg('Archivo enviado exitosamente'); |
|
||||||
setToastHeader('Informativo'); |
|
||||||
setToastColor('success'); |
|
||||||
setShowToast(true); |
|
||||||
|
|
||||||
setWorkingHoursFile(null); |
|
||||||
|
|
||||||
} catch (error) { |
|
||||||
setToastMsg(`Error al enviar archivos: ${(error as Error).message || 'Error desconocido'}`); |
|
||||||
setToastHeader('Error'); |
|
||||||
setToastColor('danger'); |
|
||||||
setShowToast(true); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
return ( |
|
||||||
<div className="mt-2"> |
|
||||||
<Card> |
|
||||||
<Card.Body> |
|
||||||
<Form> |
|
||||||
<div className="d-flex justify-content-around"> |
|
||||||
<Card |
|
||||||
className="text-center p-4 m-2" |
|
||||||
style={{ backgroundColor: 'lightgreen', borderRadius: '8px', width: '45%' }} |
|
||||||
> |
|
||||||
<Form.Group> |
|
||||||
<Form.Label className="d-block mb-2" style={{ fontWeight: 'bold' }}> |
|
||||||
Arrastra o selecciona el archivo Excel |
|
||||||
</Form.Label> |
|
||||||
<Form.Control |
|
||||||
type="file" |
|
||||||
accept=".xlsx, .xls" |
|
||||||
onChange={handleFileChange} |
|
||||||
style={{ display: 'none' }} |
|
||||||
id="workingHoursFileInput" |
|
||||||
/> |
|
||||||
<label |
|
||||||
htmlFor="workingHoursFileInput" |
|
||||||
className="btn btn-light d-block" |
|
||||||
style={{ cursor: 'pointer', border: '2px solid green', borderRadius: '8px' }} |
|
||||||
> |
|
||||||
{WorkingHoursFile ? WorkingHoursFile.name : 'Seleccionar archivo'} |
|
||||||
</label> |
|
||||||
</Form.Group> |
|
||||||
</Card> |
|
||||||
|
|
||||||
<Button |
|
||||||
variant="success" |
|
||||||
onClick={handleSendFiles} |
|
||||||
style={{ marginTop: '10px', display: 'block', marginLeft: 'auto', marginRight: 'auto' }} |
|
||||||
> |
|
||||||
Enviar <FiSend /> |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</Form> |
|
||||||
</Card.Body> |
|
||||||
</Card> |
|
||||||
|
|
||||||
<MsgInformativo |
|
||||||
show={showToast} |
|
||||||
msg={toastMsg} |
|
||||||
header={toastHeader} |
|
||||||
msgColor={toastColor} |
|
||||||
closeToast={setShowToast} |
|
||||||
/> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
@ -0,0 +1,19 @@ |
|||||||
|
export default interface WorkingHours { |
||||||
|
empNo : string,
|
||||||
|
acNo : string,
|
||||||
|
name: string,
|
||||||
|
date : string,
|
||||||
|
clockIn1 : string,
|
||||||
|
clockOut1 : string,
|
||||||
|
clockIn2 : string, |
||||||
|
clockOut2 : string, |
||||||
|
clocIn3 : string,
|
||||||
|
clocOut3 : string,
|
||||||
|
clocIn4 : string,
|
||||||
|
clocOut4 : string,
|
||||||
|
clocIn5 : string,
|
||||||
|
clocOut5 : string,
|
||||||
|
totalInTime : string,
|
||||||
|
totalHoursWorked : string |
||||||
|
|
||||||
|
} |
@ -0,0 +1,474 @@ |
|||||||
|
|
||||||
|
import * as React from 'react'; |
||||||
|
import { useState } from 'react'; |
||||||
|
import { Button, Card, Form, Col, Row, ToastHeader, } from 'react-bootstrap'; |
||||||
|
import { BsSearch, BsFileEarmarkExcel } from 'react-icons/bs' |
||||||
|
import ExelServices from '../../../Utils/ExelFiles/Exel.services'; |
||||||
|
import { FiSend } from "react-icons/fi"; |
||||||
|
import { MsgInformativo } from '../../../Utils/Toast/msgInformativo'; |
||||||
|
import * as XLSX from 'xlsx'; |
||||||
|
import DataTable from 'react-data-table-component'; |
||||||
|
import { DTOWorkingHours } from '../../../DTO/DTOWorkingHours'; |
||||||
|
import reportesServices from '../../../Services/Reportes/reportes.services'; |
||||||
|
|
||||||
|
|
||||||
|
export default function FileUploadExel() { |
||||||
|
const [WorkingHoursFile, setWorkingHoursFile] = useState<File | null>(null); |
||||||
|
const [showToast, setShowToast] = useState<boolean>(false); |
||||||
|
const [toastMsg, setToastMsg] = useState<string>(''); |
||||||
|
const [toastHeader, setToastHeader] = useState<string>(''); |
||||||
|
const [toastColor, setToastColor] = useState<string>(''); |
||||||
|
const [Inicio, setInicio] = useState(currentDate()) |
||||||
|
const [Fin, setFin] = useState(currentDate()) |
||||||
|
const [Data, setData] = useState<Array<DTOWorkingHours>>([]) |
||||||
|
const [show, setShowMsg] = useState(false) |
||||||
|
const [filtro, setFiltro] = useState('') |
||||||
|
const [filteredData, setFilteredData] = useState<Array<DTOWorkingHours>>( |
||||||
|
[] |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => { |
||||||
|
let file = event.target.files?.[0] || null; |
||||||
|
|
||||||
|
if (file && file.name.endsWith('.xls')) { |
||||||
|
// Convertir XLS a XLSX usando la biblioteca xlsx
|
||||||
|
const data = await file.arrayBuffer(); |
||||||
|
const workbook = XLSX.read(data, { type: 'array' }); |
||||||
|
const convertedData = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); |
||||||
|
file = new File([convertedData], file.name.replace('.xls', '.xlsx'), { |
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
setWorkingHoursFile(file); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const columnsConcepts = [ |
||||||
|
{ |
||||||
|
name: 'EmpNo',
|
||||||
|
width: '100px',
|
||||||
|
selector: (row : DTOWorkingHours ) => row.empNo,
|
||||||
|
sortable: true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'AcNo',
|
||||||
|
width: '80px',
|
||||||
|
selector :(row:DTOWorkingHours) => row.acNo,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'No',
|
||||||
|
width: '5px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.no,
|
||||||
|
sortable: true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'Name',
|
||||||
|
width: '150px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.name,
|
||||||
|
sortable : true ,
|
||||||
|
filter : true |
||||||
|
|
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'Date',
|
||||||
|
width: '150px',
|
||||||
|
selector : (row : DTOWorkingHours ) => row.date,
|
||||||
|
sortable: true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockIn1',
|
||||||
|
width : '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.clockIn1,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockOut1',
|
||||||
|
width : '120px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.clockOut1,
|
||||||
|
sortable : true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockIn2',
|
||||||
|
width : '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.clockIn2,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockOut2',
|
||||||
|
width : '120px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.clockOut2,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockIn3',
|
||||||
|
width : '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.clockIn3,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockOut3',
|
||||||
|
width : '150px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.clockOut3,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockIn4',
|
||||||
|
width : '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.clockIn4,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockOut4',
|
||||||
|
width : '120px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.clockOut4,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
} ,
|
||||||
|
{ |
||||||
|
name: 'ClockIn5',
|
||||||
|
width : '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.clockIn5,
|
||||||
|
sortable: true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'ClockOut5',
|
||||||
|
width : '120px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.clockOut5,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'TotalInTime',
|
||||||
|
width: '120px',
|
||||||
|
selector: (row : DTOWorkingHours) => row.totalInTime,
|
||||||
|
sortable : true ,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
|
||||||
|
{ |
||||||
|
name: 'TotalHoursWorked',
|
||||||
|
width: '130px',
|
||||||
|
selector : (row : DTOWorkingHours) => row.totalHoursWorked,
|
||||||
|
sortable : true,
|
||||||
|
filter : true
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
function currentDate (): string { |
||||||
|
var today = new Date() |
||||||
|
var dd = String(today.getDate()).padEnd(2,'0') |
||||||
|
var mm = String(today.getMonth() + 1 ).padStart(2, '0') |
||||||
|
var yyyy = today.getFullYear() |
||||||
|
return yyyy+'-' + mm + '-' + dd |
||||||
|
} |
||||||
|
|
||||||
|
const generarReporte = () => { |
||||||
|
reportesServices.getRptWorkingHours(Inicio, Fin) |
||||||
|
.then((response) => { |
||||||
|
setData(response.data) |
||||||
|
setFilteredData(response.data) |
||||||
|
setToastMsg('Se econtro la siguiente informacion'); |
||||||
|
setToastHeader('Informativo'); |
||||||
|
setToastColor('success'); |
||||||
|
setShowToast(true); |
||||||
|
|
||||||
|
})
|
||||||
|
.catch((e:Error) => { |
||||||
|
// alert('Ocurrio un Error'+e.message.toString())
|
||||||
|
setToastMsg('No se ha introducido fechas validas') |
||||||
|
setToastHeader('Error') |
||||||
|
setToastColor('danger') |
||||||
|
setShowToast(true) |
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
} ) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const donwloadExel = () => { |
||||||
|
exportExcel(filteredData , 'Reportes de Horas Trabajadas') |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const filtraReporte = (e: any ) => { |
||||||
|
const searchText = e.target.value.toLowerCase();
|
||||||
|
setFiltro(searchText) |
||||||
|
|
||||||
|
const filtered = Data.filter((iteam) => { |
||||||
|
return ( |
||||||
|
(iteam.empNo && iteam.empNo.toString().toLocaleLowerCase().includes(searchText)) ||
|
||||||
|
(iteam.name && iteam.name.toString().toLocaleLowerCase().includes(searchText)) ||
|
||||||
|
(iteam.date && iteam.date.toString().toLocaleLowerCase().includes(searchText)) |
||||||
|
) |
||||||
|
} ) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log('filtered data ', filtered ) |
||||||
|
setFilteredData(filtered) |
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const exportExcel = (jsonData: any[], fileName: string) => { |
||||||
|
const Heading = [ |
||||||
|
[ |
||||||
|
'EmpNo',
|
||||||
|
'AcNo',
|
||||||
|
'No', |
||||||
|
'Name', |
||||||
|
'Date',
|
||||||
|
'ClockIn1',
|
||||||
|
'ClockOut1',
|
||||||
|
'ClockIn1',
|
||||||
|
'ClockOut1',
|
||||||
|
'ClockIn1',
|
||||||
|
'ClockOut1',
|
||||||
|
'ClockIn1',
|
||||||
|
'ClockOut1',
|
||||||
|
'ClockIn1',
|
||||||
|
'ClockOut1',
|
||||||
|
'TotalInTime',
|
||||||
|
'TotalHoursWorked' |
||||||
|
] |
||||||
|
|
||||||
|
] |
||||||
|
|
||||||
|
const wb = XLSX.utils.book_new() |
||||||
|
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet([]) |
||||||
|
XLSX.utils.sheet_add_aoa(ws, Heading) |
||||||
|
XLSX.utils.sheet_add_json(ws, jsonData, { origin: 'A2', skipHeader: true }) |
||||||
|
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1') |
||||||
|
XLSX.writeFile(wb, `${fileName}.xlsx`) |
||||||
|
const range = XLSX.utils.decode_range(ws['!ref']!) |
||||||
|
for (let C = range.s.c; C <= range.e.c; ++C) { |
||||||
|
const address = XLSX.utils.encode_col(C) + '1' |
||||||
|
if (!ws[address]) continue |
||||||
|
ws[address].v = ws[address].v.toUpperCase() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleSendFiles = async () => { |
||||||
|
if (!WorkingHoursFile) { |
||||||
|
setToastMsg('No hay archivos para enviar'); |
||||||
|
setToastHeader('Error'); |
||||||
|
setToastColor('danger'); |
||||||
|
setShowToast(true); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const formDataBook = new FormData(); |
||||||
|
formDataBook.append('file', WorkingHoursFile); |
||||||
|
|
||||||
|
try { |
||||||
|
const responseBook = await ExelServices.uploadWorkingHours(formDataBook); |
||||||
|
|
||||||
|
if (!responseBook || responseBook.status !== 200) { |
||||||
|
throw new Error('Error al subir el archivo de horas de trabajo'); |
||||||
|
} |
||||||
|
|
||||||
|
setToastMsg('Archivo enviado exitosamente'); |
||||||
|
setToastHeader('Informativo'); |
||||||
|
setToastColor('success'); |
||||||
|
setShowToast(true); |
||||||
|
|
||||||
|
setWorkingHoursFile(null); |
||||||
|
|
||||||
|
} catch (error) { |
||||||
|
setToastMsg(`Error al enviar archivos: ${(error as Error).message || 'Error desconocido'}`); |
||||||
|
setToastHeader('Error'); |
||||||
|
setToastColor('danger'); |
||||||
|
setShowToast(true); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="mt-2"> |
||||||
|
<Card> |
||||||
|
<Card.Body> |
||||||
|
<Form> |
||||||
|
<div className="d-flex justify-content-around"> |
||||||
|
<Card |
||||||
|
className="text-center p-4 m-2" |
||||||
|
style={{ backgroundColor: 'lightgreen', borderRadius: '8px', width: '25%' }} |
||||||
|
> |
||||||
|
<Form.Group> |
||||||
|
<Form.Label className="d-block mb-2" style={{ fontWeight: 'bold' }}> |
||||||
|
Arrastra o selecciona el archivo Excel |
||||||
|
</Form.Label> |
||||||
|
<Form.Control |
||||||
|
type="file" |
||||||
|
accept=".xlsx, .xls" |
||||||
|
onChange={handleFileChange} |
||||||
|
style={{ display: 'none' }} |
||||||
|
id="workingHoursFileInput" |
||||||
|
/> |
||||||
|
<label |
||||||
|
htmlFor="workingHoursFileInput" |
||||||
|
className="btn btn-light d-block" |
||||||
|
style={{ cursor: 'pointer', border: '2px solid green', borderRadius: '8px' }} |
||||||
|
> |
||||||
|
{WorkingHoursFile ? WorkingHoursFile.name : 'Seleccionar archivo'} |
||||||
|
</label> |
||||||
|
</Form.Group> |
||||||
|
</Card> |
||||||
|
|
||||||
|
<Button |
||||||
|
variant="success" |
||||||
|
onClick={handleSendFiles} |
||||||
|
style={{ marginTop: '10px', display: 'block', marginLeft: 'auto', marginRight: 'auto', height: '40px' }} |
||||||
|
> |
||||||
|
Enviar <FiSend /> |
||||||
|
</Button> |
||||||
|
</div> |
||||||
|
</Form> |
||||||
|
</Card.Body> |
||||||
|
</Card> |
||||||
|
|
||||||
|
<MsgInformativo |
||||||
|
show={showToast} |
||||||
|
msg={toastMsg} |
||||||
|
header={toastHeader} |
||||||
|
msgColor={toastColor} |
||||||
|
closeToast={setShowToast} |
||||||
|
/> |
||||||
|
|
||||||
|
<Card className="mt-3"> |
||||||
|
<Card.Body> |
||||||
|
<Form> |
||||||
|
<Row className="align-items-center"> |
||||||
|
<Col xs={1}> |
||||||
|
<Form.Label>Desde</Form.Label> |
||||||
|
<Form.Control |
||||||
|
defaultValue={Inicio} |
||||||
|
type="date" |
||||||
|
name="Inicio" |
||||||
|
placeholder="Inicio" |
||||||
|
title="Inicio" |
||||||
|
alt="Inicio" |
||||||
|
data-date-format="YYYY-mm-dd" |
||||||
|
onChange={(e) => setInicio(e.target.value)} |
||||||
|
size="sm" |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={1}> |
||||||
|
<Form.Label>Hasta</Form.Label> |
||||||
|
<Form.Control |
||||||
|
defaultValue={Fin} |
||||||
|
type="date" |
||||||
|
name="Fin" |
||||||
|
placeholder="Fin" |
||||||
|
title="Fin" |
||||||
|
alt="Fin" |
||||||
|
onChange={(e) => setFin(e.target.value)} |
||||||
|
size="sm" |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
<Form.Control |
||||||
|
type="text" |
||||||
|
size="sm" |
||||||
|
placeholder="Search..." |
||||||
|
onChange={ (e) => { |
||||||
|
filtraReporte(e) |
||||||
|
} } |
||||||
|
|
||||||
|
style={{ height: '20px', padding: '5px' }} |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={3}> |
||||||
|
<Button |
||||||
|
// size="sm"
|
||||||
|
variant="success" |
||||||
|
onClick={donwloadExel} |
||||||
|
style={{ width: '30%' }} |
||||||
|
> |
||||||
|
<BsFileEarmarkExcel /> |
||||||
|
Excel |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
<Button |
||||||
|
variant="primary" |
||||||
|
onClick={generarReporte} |
||||||
|
style={{ width: '30%' }} |
||||||
|
> |
||||||
|
<BsSearch /> |
||||||
|
Buscar |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
</Card.Body> |
||||||
|
</Card> |
||||||
|
|
||||||
|
<Card className="mt-3"> |
||||||
|
<Card.Body> |
||||||
|
<div className="ag-theme-alpine" style={{ height: 500, width: '100%' }}> |
||||||
|
<DataTable |
||||||
|
noHeader |
||||||
|
defaultSortFieldId={''} |
||||||
|
defaultSortAsc={true} |
||||||
|
striped={true} |
||||||
|
dense={true} |
||||||
|
paginationPerPage={10} |
||||||
|
pagination |
||||||
|
highlightOnHover |
||||||
|
columns={columnsConcepts} |
||||||
|
data={filteredData} |
||||||
|
pointerOnHover |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</Card.Body> |
||||||
|
</Card> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,448 @@ |
|||||||
|
import * as react from 'react' |
||||||
|
import { useState } from 'react' |
||||||
|
import reportesServices from '../../../Services/Reportes/reportes.services' |
||||||
|
import DataTable from 'react-data-table-component' |
||||||
|
import {DTOTotalHours} from '../../../DTO/Reportes/DTOTotalHours' |
||||||
|
import * as XLSX from 'xlsx' |
||||||
|
import { MsgInformativo } from '../../../Utils/Toast/msgInformativo' |
||||||
|
import { Button, Card, Form, Col, Row, ToastHeader, CardBody, } from 'react-bootstrap'; |
||||||
|
import { BsSearch, BsFileEarmarkExcel } from 'react-icons/bs' |
||||||
|
import { DTOWorkingHours } from '../../../DTO/DTOWorkingHours' |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function RptTotalHours () |
||||||
|
{ |
||||||
|
const [Inicio, setInicio] = useState(currentDate())
|
||||||
|
const [Fin , setFin] = useState(currentDate) |
||||||
|
const [filtro, setFiltro] = useState('') |
||||||
|
const [filteredData, setFilteredData] = useState<Array<DTOTotalHours>> ( |
||||||
|
[] |
||||||
|
) |
||||||
|
const [filteredDataDet, setFilteredDataDet] = useState <Array<DTOWorkingHours>>( |
||||||
|
[] |
||||||
|
) |
||||||
|
|
||||||
|
const [Data, setData] = useState<Array<DTOTotalHours>> ([]) |
||||||
|
const [DataDet , setDataDet ] = useState <Array <DTOWorkingHours>> ([]) |
||||||
|
const [showToast, setShowToast] = useState<boolean>(false); |
||||||
|
const [toastMsg, setToastMsg] = useState<string>(''); |
||||||
|
const [toastHeader, setToastHeader] = useState<string>(''); |
||||||
|
const [toastColor, setToastColor] = useState<string>(''); |
||||||
|
|
||||||
|
|
||||||
|
function currentDate (): string { |
||||||
|
var today = new Date() |
||||||
|
var dd = String(today.getDate()).padEnd(2,'0') |
||||||
|
var mm = String(today.getMonth() + 1 ).padStart(2, '0') |
||||||
|
var yyyy = today.getFullYear() |
||||||
|
return yyyy+'-' + mm + '-' + dd |
||||||
|
} |
||||||
|
|
||||||
|
const generarRptRes = () => { |
||||||
|
reportesServices.getRptTotalHours(Inicio, Fin) |
||||||
|
.then((response) => { |
||||||
|
setData(response.data) |
||||||
|
setFilteredData(response.data) |
||||||
|
setToastMsg('Se econtro la siguiente informacion'); |
||||||
|
setToastHeader('Informativo'); |
||||||
|
setToastColor('success'); |
||||||
|
setShowToast(true); |
||||||
|
|
||||||
|
})
|
||||||
|
.catch((e:Error) => { |
||||||
|
// alert('Ocurrio un Error'+e.message.toString())
|
||||||
|
setToastMsg('No se ha introducido fechas validas') |
||||||
|
setToastHeader('Error') |
||||||
|
setToastColor('danger') |
||||||
|
setShowToast(true) |
||||||
|
return;
|
||||||
|
} ) |
||||||
|
} |
||||||
|
|
||||||
|
const generarRptDet = () => { |
||||||
|
reportesServices.getRptWorkingHours(Inicio, Fin) |
||||||
|
.then((response) => { |
||||||
|
setDataDet(response.data); |
||||||
|
}) |
||||||
|
.catch((e: Error) => { |
||||||
|
setToastMsg('Fechas No Validas'); |
||||||
|
setToastHeader('Error'); |
||||||
|
setToastColor('danger'); |
||||||
|
setShowToast(true); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const columnsConcepts = [ |
||||||
|
{ |
||||||
|
name: 'EmpNo',
|
||||||
|
width : '100px', |
||||||
|
selector : (row : DTOTotalHours ) => row.empNo,
|
||||||
|
sortable: true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{ |
||||||
|
name: 'AcNo',
|
||||||
|
width : '100px',
|
||||||
|
selector : (row : DTOTotalHours) => row.acNo,
|
||||||
|
sortable : true,
|
||||||
|
filter : true
|
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'Name',
|
||||||
|
width : '200px',
|
||||||
|
selector: (row: DTOTotalHours) => row.name,
|
||||||
|
sortable: true,
|
||||||
|
filter: true
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{ |
||||||
|
name: 'TotalHoursAccumulated',
|
||||||
|
width: '200px',
|
||||||
|
selector : (row: DTOTotalHours ) => row.totalHoursAccumulated,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'TotalHoursWithMilitaryMinutes',
|
||||||
|
with: '200px',
|
||||||
|
selector : (row: DTOTotalHours) => row.totalHoursWithMilitaryMinutes,
|
||||||
|
filter : true |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
] |
||||||
|
|
||||||
|
const columnsConceptsDet = [ |
||||||
|
[ |
||||||
|
{ |
||||||
|
name: 'Name' ,
|
||||||
|
selector : (row: DTOWorkingHours ) => row.name,
|
||||||
|
sortable : true,
|
||||||
|
filter : true |
||||||
|
},
|
||||||
|
{ |
||||||
|
name: 'EmpNo',
|
||||||
|
|
||||||
|
selector : (row : DTOWorkingHours ) => row.empNo,
|
||||||
|
sortable: true,
|
||||||
|
filter : true |
||||||
|
} |
||||||
|
] |
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const donwloadExel = () => {
|
||||||
|
// exportExcel(filteredData, 'ReporteTotalHoras' )
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// const exportExcel = (jsonData: any[], fileName: string) => {
|
||||||
|
// const Heading = [
|
||||||
|
// [
|
||||||
|
// 'EmpNo',
|
||||||
|
// 'AcNo',
|
||||||
|
// 'No',
|
||||||
|
// 'TotalHoursAccumuled',
|
||||||
|
// 'TotalHoursWithMilitaryMinutes'
|
||||||
|
|
||||||
|
// ]
|
||||||
|
|
||||||
|
|
||||||
|
// ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const Heading1 = [[
|
||||||
|
// 'EmpNo', 'AcNo', 'Name', 'Date', 'ClockIn1', 'ClockOut1 ' ,'ClockIn1', 'ClockOut1 ' ,
|
||||||
|
// 'ClockIn2', 'ClockOut2 ', 'ClockIn3', 'ClockOut3 ', 'ClockIn4', 'ClockOut4 ',
|
||||||
|
// 'ClockIn5', 'ClockOut5 '
|
||||||
|
|
||||||
|
|
||||||
|
// ]]
|
||||||
|
|
||||||
|
|
||||||
|
// const wb = XLSX.utils.book_new()
|
||||||
|
// const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet([])
|
||||||
|
// XLSX.utils.sheet_add_aoa(ws, Heading)
|
||||||
|
// XLSX.utils.sheet_add_json(ws, jsonData, { origin: 'A2', skipHeader: true })
|
||||||
|
// XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
|
||||||
|
// XLSX.writeFile(wb, `${fileName}.xlsx`)
|
||||||
|
// const range = XLSX.utils.decode_range(ws['!ref']!)
|
||||||
|
// for (let C = range.s.c; C <= range.e.c; ++C) {
|
||||||
|
// const address = XLSX.utils.encode_col(C) + '1'
|
||||||
|
// if (!ws[address]) continue
|
||||||
|
// ws[address].v = ws[address].v.toUpperCase()
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const donwloadExel = () => { |
||||||
|
exportExcel(filteredData, DataDet, 'ReporteTotal');
|
||||||
|
|
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const exportExcel = (jsonData1: any[], jsonData2: any[], fileName: string) => { |
||||||
|
const Heading1 = [ |
||||||
|
[ |
||||||
|
'EmpNo',
|
||||||
|
'AcNo',
|
||||||
|
'No',
|
||||||
|
'TotalHoursAccumuled',
|
||||||
|
'TotalHoursWithMilitaryMinutes' |
||||||
|
] |
||||||
|
]; |
||||||
|
|
||||||
|
const Heading2 = [ |
||||||
|
[ |
||||||
|
'EmpNo', 'AcNo', 'Name', 'Date', 'ClockIn1', 'ClockOut1', 'ClockIn1', 'ClockOut1',
|
||||||
|
'ClockIn2', 'ClockOut2', 'ClockIn3', 'ClockOut3', 'ClockIn4', 'ClockOut4',
|
||||||
|
'ClockIn5', 'ClockOut5' , 'TotalInTime' |
||||||
|
] |
||||||
|
]; |
||||||
|
|
||||||
|
// Crear libro de trabajo
|
||||||
|
const wb = XLSX.utils.book_new(); |
||||||
|
|
||||||
|
// Hoja 1
|
||||||
|
const ws1: XLSX.WorkSheet = XLSX.utils.json_to_sheet([]); |
||||||
|
XLSX.utils.sheet_add_aoa(ws1, Heading1); |
||||||
|
XLSX.utils.sheet_add_json(ws1, jsonData1, { origin: 'A2', skipHeader: true }); |
||||||
|
XLSX.utils.book_append_sheet(wb, ws1, 'Resumen'); |
||||||
|
|
||||||
|
// Hoja 2
|
||||||
|
const ws2: XLSX.WorkSheet = XLSX.utils.json_to_sheet([]); |
||||||
|
XLSX.utils.sheet_add_aoa(ws2, Heading2); |
||||||
|
XLSX.utils.sheet_add_json(ws2, jsonData2, { origin: 'A2', skipHeader: true }); |
||||||
|
XLSX.utils.book_append_sheet(wb, ws2, 'Detalle'); |
||||||
|
|
||||||
|
// Convertir títulos a mayúsculas en ambas hojas
|
||||||
|
const capitalizeHeaders = (ws: XLSX.WorkSheet) => { |
||||||
|
const range = XLSX.utils.decode_range(ws['!ref']!); |
||||||
|
for (let C = range.s.c; C <= range.e.c; ++C) { |
||||||
|
const address = XLSX.utils.encode_col(C) + '1'; |
||||||
|
if (!ws[address]) continue; |
||||||
|
ws[address].v = ws[address].v.toUpperCase(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
capitalizeHeaders(ws1); |
||||||
|
capitalizeHeaders(ws2); |
||||||
|
|
||||||
|
// Escribir y descargar el archivo Excel
|
||||||
|
XLSX.writeFile(wb, `${fileName}.xlsx`); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const filtraReporte1 = (e: any) => { |
||||||
|
const searchText = e.target.value.toLowerCase();
|
||||||
|
setFiltro(searchText) |
||||||
|
|
||||||
|
const filtered = DataDet.filter((iteam) => { |
||||||
|
return ( |
||||||
|
(iteam.empNo && iteam.empNo.toString().toLocaleUpperCase().includes(searchText)) ||
|
||||||
|
(iteam.name && iteam.name.toString().toLocaleLowerCase().includes(searchText) )
|
||||||
|
|
||||||
|
|
||||||
|
) |
||||||
|
} ) |
||||||
|
|
||||||
|
setFilteredDataDet(filtered) |
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const filtraReporte = (e: any) => { |
||||||
|
const searchText = e.target.value.toLowerCase();
|
||||||
|
setFiltro(searchText) |
||||||
|
|
||||||
|
const filtered = Data.filter((iteam) => { |
||||||
|
return ( |
||||||
|
(iteam.empNo && iteam.empNo.toString().toLocaleUpperCase().includes(searchText)) ||
|
||||||
|
(iteam.name && iteam.name.toString().toLocaleLowerCase().includes(searchText) )
|
||||||
|
|
||||||
|
|
||||||
|
) |
||||||
|
} ) |
||||||
|
|
||||||
|
setFilteredData(filtered) |
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const generReportes = () => { |
||||||
|
generarRptRes() |
||||||
|
generarRptDet() |
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const filtros = (e: any) => {
|
||||||
|
// filtraReporte(e);
|
||||||
|
// filtraReporte1(e);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return( |
||||||
|
<div className='mt-2'>
|
||||||
|
{/* <Card className="mt-3"> */} |
||||||
|
<Card.Body> |
||||||
|
<Form> |
||||||
|
<Row className="align-items-center"> |
||||||
|
<Col xs={1}> |
||||||
|
{/* <Form.Label>Desde</Form.Label> */} |
||||||
|
|
||||||
|
<Col style={{textAlign: 'center'}} >Desde</Col> |
||||||
|
<Form.Control |
||||||
|
defaultValue={Inicio} |
||||||
|
type="date" |
||||||
|
name="Inicio" |
||||||
|
placeholder="Inicio" |
||||||
|
title="Inicio" |
||||||
|
alt="Inicio" |
||||||
|
data-date-format="YYYY-mm-dd" |
||||||
|
onChange={(e) => setInicio(e.target.value)} |
||||||
|
size="sm" |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
{/* <Form.Label>Hasta</Form.Label> */} |
||||||
|
<Col style={{textAlign: 'center'}} >Hasta</Col> |
||||||
|
<Form.Control |
||||||
|
defaultValue={Fin} |
||||||
|
type="date" |
||||||
|
name="Fin" |
||||||
|
placeholder="Fin" |
||||||
|
title="Fin" |
||||||
|
alt="Fin" |
||||||
|
onChange={(e) => setFin(e.target.value)} |
||||||
|
size="sm" |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
<Form.Control |
||||||
|
type="text" |
||||||
|
size="sm" |
||||||
|
placeholder="Search..." |
||||||
|
onChange={ (e) => { |
||||||
|
filtraReporte(e) |
||||||
|
} } |
||||||
|
// onChange={filtros}
|
||||||
|
style={{ height: '10px', padding: '5px' }} |
||||||
|
/> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
<Button |
||||||
|
// size="sm"
|
||||||
|
variant="success" |
||||||
|
onClick={donwloadExel} |
||||||
|
style={{ width: '35%' }} |
||||||
|
> |
||||||
|
<BsFileEarmarkExcel /> |
||||||
|
Excel |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
|
||||||
|
<Col xs={2}> |
||||||
|
<Button |
||||||
|
variant="primary" |
||||||
|
onClick={generReportes}
|
||||||
|
style={{ width: '40%' }} |
||||||
|
> |
||||||
|
<BsSearch /> |
||||||
|
Buscar |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</Form> |
||||||
|
</Card.Body> |
||||||
|
{/* </Card> */} |
||||||
|
|
||||||
|
<MsgInformativo |
||||||
|
show={showToast} |
||||||
|
msg={toastMsg} |
||||||
|
header={toastHeader} |
||||||
|
msgColor={toastColor} |
||||||
|
closeToast={setShowToast} |
||||||
|
/> |
||||||
|
|
||||||
|
|
||||||
|
<Card className='mt-3'>
|
||||||
|
|
||||||
|
<Card.Body>
|
||||||
|
<div className='ag-theme-alpine' style={{ height: 500, width: '100%'}}> |
||||||
|
|
||||||
|
<DataTable
|
||||||
|
noHeader
|
||||||
|
defaultSortFieldId={''} |
||||||
|
defaultSortAsc = {true} |
||||||
|
striped= {true} |
||||||
|
dense = {true} |
||||||
|
paginationPerPage={10} |
||||||
|
pagination
|
||||||
|
highlightOnHover
|
||||||
|
columns={columnsConcepts} |
||||||
|
data={filteredData} |
||||||
|
pointerOnHover |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/> |
||||||
|
</div> |
||||||
|
</Card.Body> |
||||||
|
</Card> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
export interface DTOTotalHours { |
||||||
|
|
||||||
|
empNo : string ,
|
||||||
|
acNo : string,
|
||||||
|
name : string, |
||||||
|
totalHoursAccumulated : string
|
||||||
|
totalHoursWithMilitaryMinutes : string |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue