feat: Improve display of queue and WhatsApp number-based interaction report
parent
8447628fbf
commit
9f040ce953
|
@ -331,9 +331,6 @@ 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,
|
||||
|
|
|
@ -79,10 +79,11 @@ const ReportByNumberQueueService = async ({
|
|||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
|
||||
// CHAT AVG WAINTING TIME
|
||||
// CHAT WAINTING TIME
|
||||
const avgChatWaitingTime: any = await sequelize.query(
|
||||
`SELECT SEC_TO_TIME(
|
||||
AVG(
|
||||
`
|
||||
SELECT TIME_FORMAT(
|
||||
SEC_TO_TIME(
|
||||
TIMESTAMPDIFF(
|
||||
SECOND,
|
||||
(
|
||||
|
@ -102,8 +103,7 @@ const ReportByNumberQueueService = async ({
|
|||
LIMIT 1
|
||||
)
|
||||
)
|
||||
)
|
||||
) AS AVG_AWAITING_TIME
|
||||
), '%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
|
||||
|
@ -113,7 +113,9 @@ const ReportByNumberQueueService = async ({
|
|||
AND m.fromMe = 0
|
||||
-- AND q.id = 2
|
||||
AND w.number = ${number}
|
||||
AND (t.status = 'open' OR t.status = 'closed');`,
|
||||
AND (t.status = 'open' OR t.status = 'closed')
|
||||
ORDER BY
|
||||
WAITING_TIME;`,
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
|
||||
|
@ -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,10 +205,10 @@ const ReportByNumberQueueService = async ({
|
|||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
|
||||
// CHAT AVG WAINTING TIME
|
||||
// CHAT WAINTING TIME
|
||||
const avgChatWaitingTime: any = await sequelize.query(
|
||||
`SELECT SEC_TO_TIME(
|
||||
AVG(
|
||||
`SELECT TIME_FORMAT(
|
||||
SEC_TO_TIME(
|
||||
TIMESTAMPDIFF(
|
||||
SECOND,
|
||||
(
|
||||
|
@ -228,8 +228,7 @@ const ReportByNumberQueueService = async ({
|
|||
LIMIT 1
|
||||
)
|
||||
)
|
||||
)
|
||||
) AS AVG_AWAITING_TIME
|
||||
), '%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 }
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = () => {
|
|||
|
||||
<MaterialTable
|
||||
|
||||
localization={{
|
||||
|
||||
// header: {
|
||||
// actions: 'Deslogar'
|
||||
// },
|
||||
|
||||
}}
|
||||
|
||||
title={i18n.t("reports.listTitles.title4_1")}
|
||||
columns={
|
||||
[
|
||||
|
||||
// { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
|
||||
{ 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 = () => {
|
|||
|
||||
<MaterialTable
|
||||
|
||||
localization={{
|
||||
|
||||
// header: {
|
||||
// actions: 'Deslogar'
|
||||
// },
|
||||
|
||||
}}
|
||||
|
||||
title={i18n.t("reports.listTitles.title5_1")}
|
||||
columns={
|
||||
[
|
||||
|
||||
// { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
|
||||
|
||||
{ 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
|
||||
// })
|
||||
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
Loading…
Reference in New Issue