diff --git a/backend/src/controllers/ReportController.ts b/backend/src/controllers/ReportController.ts index 6cd6a60..01664d4 100644 --- a/backend/src/controllers/ReportController.ts +++ b/backend/src/controllers/ReportController.ts @@ -331,10 +331,7 @@ export const reportServiceByQueue = async ( const { startDate, endDate, queueId } = req.query as IndexQuery; - console.log( - `startDate: ${startDate} | endDate: ${endDate} | queueId: ${queueId}` - ); - + const reportService = await ReportByNumberQueueService({ startDate, endDate, diff --git a/backend/src/models/User.ts b/backend/src/models/User.ts index af93cd5..a2fde6a 100644 --- a/backend/src/models/User.ts +++ b/backend/src/models/User.ts @@ -30,7 +30,7 @@ class User extends Model { name: string; @Column - email: string; + email: string; @Column(DataType.VIRTUAL) password: string; diff --git a/backend/src/services/ReportServices/ReportByNumberQueueService.ts b/backend/src/services/ReportServices/ReportByNumberQueueService.ts index 5baf96a..32cd1f4 100644 --- a/backend/src/services/ReportServices/ReportByNumberQueueService.ts +++ b/backend/src/services/ReportServices/ReportByNumberQueueService.ts @@ -79,41 +79,43 @@ const ReportByNumberQueueService = async ({ { type: QueryTypes.SELECT } ); - // CHAT AVG WAINTING TIME + // CHAT WAINTING TIME const avgChatWaitingTime: any = await sequelize.query( - `SELECT SEC_TO_TIME( - AVG( - TIMESTAMPDIFF( - SECOND, - ( - SELECT createdAt - FROM Messages - WHERE ticketId = m.ticketId - AND fromMe = 0 - ORDER BY createdAt ASC - LIMIT 1 - ), - ( - SELECT createdAt - FROM Messages - WHERE ticketId = m.ticketId - AND fromAgent = 1 - ORDER BY createdAt ASC - LIMIT 1 - ) - ) - ) - ) AS AVG_AWAITING_TIME + ` + SELECT TIME_FORMAT( + SEC_TO_TIME( + TIMESTAMPDIFF( + SECOND, + ( + SELECT createdAt + FROM Messages + WHERE ticketId = m.ticketId + AND fromMe = 0 + ORDER BY createdAt ASC + LIMIT 1 + ), + ( + SELECT createdAt + FROM Messages + WHERE ticketId = m.ticketId + AND fromAgent = 1 + ORDER BY createdAt ASC + LIMIT 1 + ) + ) + ), '%H:%i:%s') AS WAITING_TIME FROM Tickets t JOIN Messages m ON t.id = m.ticketId JOIN Whatsapps w ON t.whatsappId = w.id JOIN Queues q ON q.id = t.queueId WHERE DATE(m.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999' - AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id) - AND m.fromMe = 0 - -- AND q.id = 2 - AND w.number = ${number} - AND (t.status = 'open' OR t.status = 'closed');`, + AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id) + AND m.fromMe = 0 + -- AND q.id = 2 + AND w.number = ${number} + AND (t.status = 'open' OR t.status = 'closed') + ORDER BY + WAITING_TIME;`, { type: QueryTypes.SELECT } ); @@ -129,8 +131,8 @@ const ReportByNumberQueueService = async ({ AND w.number = ${number};`, { type: QueryTypes.SELECT } - ); - + ); + reportServiceData.push({ id, name, @@ -138,9 +140,7 @@ const ReportByNumberQueueService = async ({ startedByAgent: startedByAgent[0]?.ticket_count, startedByClient: startedByClient[0]?.ticket_count, closedChat: closedChat[0]?.ticket_count, - avgChatWaitingTime: avgChatWaitingTime[0]?.AVG_AWAITING_TIME - ? avgChatWaitingTime[0]?.AVG_AWAITING_TIME - : 0, + avgChatWaitingTime: avg(avgChatWaitingTime), pendingChat: pendingChat[0]?.ticket_count }); } @@ -205,31 +205,30 @@ const ReportByNumberQueueService = async ({ { type: QueryTypes.SELECT } ); - // CHAT AVG WAINTING TIME + // CHAT WAINTING TIME const avgChatWaitingTime: any = await sequelize.query( - `SELECT SEC_TO_TIME( - AVG( - TIMESTAMPDIFF( - SECOND, - ( - SELECT createdAt - FROM Messages - WHERE ticketId = m.ticketId - AND fromMe = 0 - ORDER BY createdAt ASC - LIMIT 1 - ), - ( - SELECT createdAt - FROM Messages - WHERE ticketId = m.ticketId - AND fromAgent = 1 - ORDER BY createdAt ASC - LIMIT 1 - ) - ) - ) - ) AS AVG_AWAITING_TIME + `SELECT TIME_FORMAT( + SEC_TO_TIME( + TIMESTAMPDIFF( + SECOND, + ( + SELECT createdAt + FROM Messages + WHERE ticketId = m.ticketId + AND fromMe = 0 + ORDER BY createdAt ASC + LIMIT 1 + ), + ( + SELECT createdAt + FROM Messages + WHERE ticketId = m.ticketId + AND fromAgent = 1 + ORDER BY createdAt ASC + LIMIT 1 + ) + ) + ), '%H:%i:%s') AS WAITING_TIME FROM Tickets t JOIN Messages m ON t.id = m.ticketId JOIN Whatsapps w ON t.whatsappId = w.id @@ -238,7 +237,9 @@ const ReportByNumberQueueService = async ({ AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id) AND m.fromMe = 0 AND q.id = ${q.id} - AND (t.status = 'open' OR t.status = 'closed');`, + AND (t.status = 'open' OR t.status = 'closed') + ORDER BY + WAITING_TIME;`, { type: QueryTypes.SELECT } ); @@ -254,7 +255,7 @@ const ReportByNumberQueueService = async ({ AND q.id = ${q.id};`, { type: QueryTypes.SELECT } - ); + ); reportServiceData.push({ id, @@ -265,9 +266,7 @@ const ReportByNumberQueueService = async ({ startedByAgent: startedByAgent[0]?.ticket_count, startedByClient: startedByClient[0]?.ticket_count, closedChat: closedChat[0]?.ticket_count, - avgChatWaitingTime: avgChatWaitingTime[0]?.AVG_AWAITING_TIME - ? avgChatWaitingTime[0]?.AVG_AWAITING_TIME - : 0, + avgChatWaitingTime: avg(avgChatWaitingTime), pendingChat: pendingChat[0]?.ticket_count }); } @@ -278,3 +277,55 @@ const ReportByNumberQueueService = async ({ }; export default ReportByNumberQueueService; + +function avg(avgChatWaitingTime: any) { + let waitingAVG: any = avgChatWaitingTime + .filter((t: any) => t?.WAITING_TIME) + .map((t: any) => t.WAITING_TIME) + + if (waitingAVG.length > 0) { + let midIndex = Math.floor((0 + waitingAVG.length) / 2) + + if (waitingAVG.length % 2 == 1) { + waitingAVG = waitingAVG[midIndex] + } else { + waitingAVG = calculateAverageTime( + waitingAVG[midIndex - 1], + waitingAVG[midIndex] + ) + } + } else { + waitingAVG = 0 + } + return waitingAVG +} + +function calculateAverageTime(time1: string, time2: string) { + // Function to parse time string to seconds + function timeStringToSeconds(timeString: string) { + const [hours, minutes, seconds] = timeString.split(":").map(Number); + return hours * 3600 + minutes * 60 + seconds; + } + + // Function to convert seconds to time string + function secondsToTimeString(seconds: number) { + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const remainingSeconds = seconds % 60; + return `${hours.toString().padStart(2, "0")}:${minutes + .toString() + .padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`; + } + + // Convert time strings to seconds + const time1Seconds = timeStringToSeconds(time1); + const time2Seconds = timeStringToSeconds(time2); + + // Calculate average seconds + const averageSeconds = Math.round((time1Seconds + time2Seconds) / 2); + + // Convert average seconds back to time string + const averageTime = secondsToTimeString(averageSeconds); + + return averageTime; +} diff --git a/frontend/src/pages/Report/index.js b/frontend/src/pages/Report/index.js index 9295a8b..055f95e 100644 --- a/frontend/src/pages/Report/index.js +++ b/frontend/src/pages/Report/index.js @@ -395,15 +395,13 @@ const Report = () => { else if (reportOption === '3') { const dataQuery = await api.get("/reports/services/numbers", { params: { startDate, endDate }, }) - console.log('DATA QUERY.data numbers: ', dataQuery.data) - dispatchQ({ type: "RESET" }) dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService }) } else if (reportOption === '4') { const dataQuery = await api.get("/reports/services/queues", { params: { startDate, endDate }, }) - console.log('DATA QUERY.data queues: ', dataQuery.data) + console.log(' dataQuery?.data?.reportService: ', dataQuery?.data?.reportService) dispatchQ({ type: "RESET" }) dispatchQ({ type: "LOAD_QUERY", payload: dataQuery?.data?.reportService }) @@ -958,48 +956,11 @@ const Report = () => { imagem de perfil do whatsapp }, { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, - - { - title: 'Conversas iniciadas', field: 'startedByAgent', - - // cellStyle: (e, rowData) => { - - // if (rowData['statusOnline'] && rowData['statusOnline'].status) { - - // if (rowData['statusOnline'].status === 'offline') { - - // return { color: "red" } - // } - // else if (rowData['statusOnline'].status === 'online') { - // return { color: "green" } - // } - // else if (rowData['statusOnline'].status === 'logout...') { - // return { color: "orange" } - // } - // else if (rowData['statusOnline'].status === 'waiting...') { - // return { color: "orange" } - // } - // } - - - // }, - - }, - + { title: 'Conversas iniciadas', field: 'startedByAgent', }, { title: 'Conversas recebidas', field: 'startedByClient' }, { title: `Conversas finalizadas`, field: 'closedChat' }, { title: `Tempo médio de espera`, field: 'avgChatWaitingTime' }, @@ -1009,29 +970,6 @@ const Report = () => { } data={dataRows} - // actions={[ - // (rowData) => { - - // if (rowData.statusOnline && - // rowData.statusOnline['status'] && - // rowData.statusOnline['status'] === 'online') { - - - // return { - // icon: LogoutIcon, - // tooltip: 'deslogar', - // disable: false, - // onClick: (event, rowData) => { - // handleLogouOnlineUser(rowData.id) - // } - // } - - - // } - // } - // ]} - - options={ { search: true, @@ -1062,49 +1000,23 @@ const Report = () => { imagem de perfil do whatsapp }, - { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, - { title: 'Fila', field: 'queueName', cellStyle: { whiteSpace: 'nowrap' }, }, { - title: 'Conversas iniciadas', field: 'startedByAgent', - - // cellStyle: (e, rowData) => { - - // if (rowData['statusOnline'] && rowData['statusOnline'].status) { - - // if (rowData['statusOnline'].status === 'offline') { - - // return { color: "red" } - // } - // else if (rowData['statusOnline'].status === 'online') { - // return { color: "green" } - // } - // else if (rowData['statusOnline'].status === 'logout...') { - // return { color: "orange" } - // } - // else if (rowData['statusOnline'].status === 'waiting...') { - // return { color: "orange" } - // } - // } - - - // }, + title: 'Fila', field: 'queueName', + cellStyle: (evt, rowData) => { + return { + whiteSpace: 'nowrap', + backgroundColor: rowData?.queueColor || 'inherit', + color: 'white' + } + } }, - + { title: 'Conversas iniciadas', field: 'startedByAgent', }, { title: 'Conversas recebidas', field: 'startedByClient' }, { title: `Conversas finalizadas`, field: 'closedChat' }, { title: `Tempo médio de espera`, field: 'avgChatWaitingTime' }, @@ -1114,29 +1026,6 @@ const Report = () => { } data={dataRows} - // actions={[ - // (rowData) => { - - // if (rowData.statusOnline && - // rowData.statusOnline['status'] && - // rowData.statusOnline['status'] === 'online') { - - - // return { - // icon: LogoutIcon, - // tooltip: 'deslogar', - // disable: false, - // onClick: (event, rowData) => { - // handleLogouOnlineUser(rowData.id) - // } - // } - - - // } - // } - // ]} - - options={ { search: true, @@ -1159,6 +1048,11 @@ const Report = () => { fontSize: 14, } + // rowStyle: rowData => ({ + // backgroundColor: rowData.queueColor || 'inherit', + // fontSize: 14 + // }) + }} />