Compare commits
3 Commits
9f040ce953
...
b05cd7d1d6
Author | SHA1 | Date |
---|---|---|
willian-pessoa | b05cd7d1d6 | |
willian-pessoa | 1a7077feaf | |
adriano | dc5a6945d2 |
|
@ -20,6 +20,7 @@ import ShowQueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
||||||
import { getIO } from "../libs/socket";
|
import { getIO } from "../libs/socket";
|
||||||
import { Json } from "sequelize/types/lib/utils";
|
import { Json } from "sequelize/types/lib/utils";
|
||||||
import ReportByNumberQueueService from "../services/ReportServices/ReportByNumberQueueService";
|
import ReportByNumberQueueService from "../services/ReportServices/ReportByNumberQueueService";
|
||||||
|
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService";
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
@ -312,7 +313,7 @@ export const reportService = async (
|
||||||
const reportService = await ReportByNumberQueueService({
|
const reportService = await ReportByNumberQueueService({
|
||||||
startDate,
|
startDate,
|
||||||
endDate
|
endDate
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ reportService });
|
return res.status(200).json({ reportService });
|
||||||
};
|
};
|
||||||
|
@ -331,12 +332,37 @@ export const reportServiceByQueue = async (
|
||||||
|
|
||||||
const { startDate, endDate, queueId } = req.query as IndexQuery;
|
const { startDate, endDate, queueId } = req.query as IndexQuery;
|
||||||
|
|
||||||
|
|
||||||
const reportService = await ReportByNumberQueueService({
|
const reportService = await ReportByNumberQueueService({
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
queue: true
|
queue: true
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ reportService });
|
return res.status(200).json({ reportService });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reportTicksCountByStatusChatEnds = async (
|
||||||
|
req: Request,
|
||||||
|
res: Response
|
||||||
|
): Promise<Response> => {
|
||||||
|
if (
|
||||||
|
req.user.profile !== "master" &&
|
||||||
|
req.user.profile !== "admin" &&
|
||||||
|
req.user.profile !== "supervisor"
|
||||||
|
) {
|
||||||
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { startDate, endDate } = req.query as IndexQuery;
|
||||||
|
|
||||||
|
const dateToday = splitDateTime(
|
||||||
|
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const reportStatusChatEnd = await CountStatusChatEndService(
|
||||||
|
startDate || dateToday.fullDate,
|
||||||
|
endDate || dateToday.fullDate
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(200).json({ reportStatusChatEnd });
|
||||||
|
};
|
||||||
|
|
|
@ -76,6 +76,7 @@ import CreateContactService from "../services/ContactServices/CreateContactServi
|
||||||
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
|
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
|
||||||
import WhatsappQueue from "../models/WhatsappQueue";
|
import WhatsappQueue from "../models/WhatsappQueue";
|
||||||
import { get } from "../helpers/RedisClient"
|
import { get } from "../helpers/RedisClient"
|
||||||
|
import CountStatusChatEndService from "../services/StatusChatEndService/CountStatusChatEndService"
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
|
@ -109,8 +110,8 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
withUnreadMessages,
|
withUnreadMessages,
|
||||||
unlimited,
|
unlimited,
|
||||||
searchParamContent
|
searchParamContent
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ tickets, count, hasMore });
|
return res.status(200).json({ tickets, count, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -348,7 +349,8 @@ export const update = async (
|
||||||
ticketData: {
|
ticketData: {
|
||||||
status: status,
|
status: status,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
statusChatEnd: statusChatEndName.name
|
statusChatEnd: statusChatEndName.name,
|
||||||
|
statusChatEndId: statusChatEndName.id
|
||||||
},
|
},
|
||||||
ticketId
|
ticketId
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { QueryInterface, DataTypes } from "sequelize";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
up: (queryInterface: QueryInterface) => {
|
||||||
|
return queryInterface.addColumn("Tickets", "statusChatEndId", {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
references: { model: "StatusChatEnds", key: "id" },
|
||||||
|
onUpdate: "CASCADE",
|
||||||
|
onDelete: "SET NULL",
|
||||||
|
allowNull: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
down: (queryInterface: QueryInterface) => {
|
||||||
|
return queryInterface.removeColumn("Tickets", "statusChatEndId");
|
||||||
|
}
|
||||||
|
};
|
|
@ -10,25 +10,29 @@ import {
|
||||||
} from "sequelize-typescript";
|
} from "sequelize-typescript";
|
||||||
|
|
||||||
import SchedulingNotify from "./SchedulingNotify";
|
import SchedulingNotify from "./SchedulingNotify";
|
||||||
|
import Ticket from "./Ticket"
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
class StatusChatEnd extends Model<StatusChatEnd> {
|
class StatusChatEnd extends Model<StatusChatEnd> {
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
@AutoIncrement
|
@AutoIncrement
|
||||||
@Column
|
@Column
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
@HasMany(() => SchedulingNotify)
|
@HasMany(() => SchedulingNotify)
|
||||||
SchedulingNotifies: SchedulingNotify[];
|
SchedulingNotifies: SchedulingNotify[];
|
||||||
|
|
||||||
|
@HasMany(() => Ticket)
|
||||||
|
tickets: Ticket[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StatusChatEnd;
|
export default StatusChatEnd;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import User from "./User";
|
||||||
import Whatsapp from "./Whatsapp";
|
import Whatsapp from "./Whatsapp";
|
||||||
|
|
||||||
import SchedulingNotify from "./SchedulingNotify";
|
import SchedulingNotify from "./SchedulingNotify";
|
||||||
|
import StatusChatEnd from "./StatusChatEnd"
|
||||||
|
|
||||||
@Table
|
@Table
|
||||||
class Ticket extends Model<Ticket> {
|
class Ticket extends Model<Ticket> {
|
||||||
|
@ -42,6 +43,10 @@ class Ticket extends Model<Ticket> {
|
||||||
@Column
|
@Column
|
||||||
isGroup: boolean;
|
isGroup: boolean;
|
||||||
|
|
||||||
|
@ForeignKey(() => StatusChatEnd)
|
||||||
|
@Column
|
||||||
|
statusChatEndId: number;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
statusChatEnd: string;
|
statusChatEnd: string;
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,48 @@
|
||||||
//relatorio
|
//relatorio
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
|
||||||
import isAuth from "../middleware/isAuth";
|
import isAuth from "../middleware/isAuth";
|
||||||
|
|
||||||
import * as ReportController from "../controllers/ReportController";
|
|
||||||
|
|
||||||
const reportRoutes = express.Router();
|
import * as ReportController from "../controllers/ReportController";
|
||||||
|
|
||||||
reportRoutes.get("/reports", isAuth, ReportController.reportUserByDateStartDateEnd);
|
const reportRoutes = express.Router();
|
||||||
|
|
||||||
reportRoutes.post("/reports/onqueue", ReportController.reportOnQueue);
|
reportRoutes.get(
|
||||||
|
"/reports",
|
||||||
|
isAuth,
|
||||||
|
ReportController.reportUserByDateStartDateEnd
|
||||||
|
);
|
||||||
|
|
||||||
reportRoutes.get("/reports/user/services", isAuth, ReportController.reportUserService);
|
reportRoutes.post("/reports/onqueue", ReportController.reportOnQueue);
|
||||||
|
|
||||||
|
reportRoutes.get(
|
||||||
|
"/reports/user/services",
|
||||||
|
isAuth,
|
||||||
|
ReportController.reportUserService
|
||||||
|
);
|
||||||
|
|
||||||
reportRoutes.get(
|
reportRoutes.get(
|
||||||
"/reports/services/numbers",
|
"/reports/services/numbers",
|
||||||
isAuth,
|
isAuth,
|
||||||
ReportController.reportService
|
ReportController.reportService
|
||||||
);
|
);
|
||||||
|
|
||||||
reportRoutes.get("/reports/services/queues", isAuth, ReportController.reportServiceByQueue);
|
reportRoutes.get(
|
||||||
|
"/reports/services/queues",
|
||||||
|
isAuth,
|
||||||
|
ReportController.reportServiceByQueue
|
||||||
|
);
|
||||||
|
|
||||||
reportRoutes.get("/reports/messages", isAuth, ReportController.reportMessagesUserByDateStartDateEnd);
|
reportRoutes.get(
|
||||||
|
"/reports/messages",
|
||||||
|
isAuth,
|
||||||
|
ReportController.reportMessagesUserByDateStartDateEnd
|
||||||
|
);
|
||||||
|
|
||||||
|
reportRoutes.get(
|
||||||
|
"/reports/count/statusChatEnd",
|
||||||
|
isAuth,
|
||||||
|
ReportController.reportTicksCountByStatusChatEnds
|
||||||
|
);
|
||||||
|
|
||||||
export default reportRoutes;
|
export default reportRoutes;
|
||||||
|
|
|
@ -113,7 +113,8 @@ const ReportByNumberQueueService = async ({
|
||||||
AND m.fromMe = 0
|
AND m.fromMe = 0
|
||||||
-- AND q.id = 2
|
-- AND q.id = 2
|
||||||
AND w.number = ${number}
|
AND w.number = ${number}
|
||||||
AND (t.status = 'open' OR t.status = 'closed')
|
AND t.status IN ('open', 'closed')
|
||||||
|
HAVING WAITING_TIME IS NOT NULL
|
||||||
ORDER BY
|
ORDER BY
|
||||||
WAITING_TIME;`,
|
WAITING_TIME;`,
|
||||||
{ type: QueryTypes.SELECT }
|
{ type: QueryTypes.SELECT }
|
||||||
|
@ -237,7 +238,8 @@ const ReportByNumberQueueService = async ({
|
||||||
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
||||||
AND m.fromMe = 0
|
AND m.fromMe = 0
|
||||||
AND q.id = ${q.id}
|
AND q.id = ${q.id}
|
||||||
AND (t.status = 'open' OR t.status = 'closed')
|
AND t.status IN ('open', 'closed')
|
||||||
|
HAVING WAITING_TIME IS NOT NULL
|
||||||
ORDER BY
|
ORDER BY
|
||||||
WAITING_TIME;`,
|
WAITING_TIME;`,
|
||||||
{ type: QueryTypes.SELECT }
|
{ type: QueryTypes.SELECT }
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import StatusChatEnd from "../../models/StatusChatEnd";
|
||||||
|
import AppError from "../../errors/AppError";
|
||||||
|
|
||||||
|
import { Sequelize } from "sequelize";
|
||||||
|
import { splitDateTime } from "../../helpers/SplitDateTime"
|
||||||
|
import ptBR from "date-fns/locale/pt-BR";
|
||||||
|
import { format } from "date-fns"
|
||||||
|
const dbConfig = require("../../config/database");
|
||||||
|
const sequelize = new Sequelize(dbConfig);
|
||||||
|
const { QueryTypes } = require("sequelize");
|
||||||
|
|
||||||
|
const CountStatusChatEndService = async (
|
||||||
|
startDate: string,
|
||||||
|
endDate: string
|
||||||
|
) => {
|
||||||
|
|
||||||
|
const countStatusChatEnd: any = await sequelize.query(
|
||||||
|
`select t.id, s.name, count(t.id) as count from Tickets t join StatusChatEnds s on
|
||||||
|
t.statusChatEndId = s.id and DATE(t.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999'
|
||||||
|
group by s.id;`,
|
||||||
|
{ type: QueryTypes.SELECT }
|
||||||
|
);
|
||||||
|
|
||||||
|
return countStatusChatEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CountStatusChatEndService;
|
|
@ -7,7 +7,7 @@ import Queue from "../../models/Queue";
|
||||||
import Message from "../../models/Message";
|
import Message from "../../models/Message";
|
||||||
import { userInfo } from "os";
|
import { userInfo } from "os";
|
||||||
|
|
||||||
import { Op, QueryTypes, where } from "sequelize";
|
import { Op, QueryTypes, json, where } from "sequelize";
|
||||||
|
|
||||||
import { Sequelize } from "sequelize";
|
import { Sequelize } from "sequelize";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
@ -17,7 +17,7 @@ const sequelize = new Sequelize(dbConfig);
|
||||||
import { startOfDay, endOfDay, parseISO, getDate } from "date-fns";
|
import { startOfDay, endOfDay, parseISO, getDate } from "date-fns";
|
||||||
import { string } from "yup/lib/locale";
|
import { string } from "yup/lib/locale";
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query"
|
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query";
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
userId: string | number;
|
userId: string | number;
|
||||||
|
@ -73,9 +73,7 @@ const ShowTicketReport = async ({
|
||||||
{ type: QueryTypes.SELECT }
|
{ type: QueryTypes.SELECT }
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('QUERY: ', query)
|
let { count, rows: tickets }: any = await Ticket.findAndCountAll({
|
||||||
|
|
||||||
const { count, rows: tickets } = await Ticket.findAndCountAll({
|
|
||||||
where: {
|
where: {
|
||||||
id: { [Op.in]: _ticketsId.map((t: any) => t.id) }
|
id: { [Op.in]: _ticketsId.map((t: any) => t.id) }
|
||||||
},
|
},
|
||||||
|
@ -153,6 +151,58 @@ const ShowTicketReport = async ({
|
||||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ticketIds = tickets.map((t: any) => t.id);
|
||||||
|
|
||||||
|
if (ticketIds.length > 0) {
|
||||||
|
const waiting_time: any = await sequelize.query(
|
||||||
|
`SELECT t.id as ticketId, t.status, 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 t.id IN (${ticketIds.join()})
|
||||||
|
AND m.createdAt = (SELECT MIN(createdAt) FROM Messages WHERE ticketId = t.id)
|
||||||
|
AND m.fromMe = 0
|
||||||
|
AND t.status IN ('open', 'closed')
|
||||||
|
HAVING WAITING_TIME IS NOT NULL
|
||||||
|
ORDER BY
|
||||||
|
WAITING_TIME;`,
|
||||||
|
{ type: QueryTypes.SELECT }
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let w of waiting_time) {
|
||||||
|
const { ticketId, status, WAITING_TIME } = w;
|
||||||
|
|
||||||
|
const index = tickets.findIndex((t: any) => +t?.id == +ticketId);
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
tickets[index].dataValues.waiting_time = WAITING_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { tickets, count, hasMore };
|
return { tickets, count, hasMore };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
||||||
import { deleteObject } from "../../helpers/RedisClient"
|
import { deleteObject } from "../../helpers/RedisClient";
|
||||||
var flatten = require("flat");
|
var flatten = require("flat");
|
||||||
|
|
||||||
interface TicketData {
|
interface TicketData {
|
||||||
|
@ -18,6 +18,7 @@ interface TicketData {
|
||||||
userId?: number;
|
userId?: number;
|
||||||
queueId?: number;
|
queueId?: number;
|
||||||
statusChatEnd?: string;
|
statusChatEnd?: string;
|
||||||
|
statusChatEndId?: number;
|
||||||
unreadMessages?: number;
|
unreadMessages?: number;
|
||||||
whatsappId?: string | number;
|
whatsappId?: string | number;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +47,7 @@ const UpdateTicketService = async ({
|
||||||
queueId,
|
queueId,
|
||||||
statusChatEnd,
|
statusChatEnd,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
|
statusChatEndId,
|
||||||
whatsappId
|
whatsappId
|
||||||
} = ticketData;
|
} = ticketData;
|
||||||
|
|
||||||
|
@ -66,13 +68,14 @@ const UpdateTicketService = async ({
|
||||||
if (oldStatus === "closed") {
|
if (oldStatus === "closed") {
|
||||||
await CheckContactOpenTickets(ticket.contact.id, ticket.whatsappId);
|
await CheckContactOpenTickets(ticket.contact.id, ticket.whatsappId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ticket.update({
|
await ticket.update({
|
||||||
status,
|
status,
|
||||||
queueId,
|
queueId,
|
||||||
userId,
|
userId,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
statusChatEnd,
|
statusChatEnd,
|
||||||
|
statusChatEndId,
|
||||||
whatsappId
|
whatsappId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
import { Box } from '@material-ui/core';
|
||||||
|
import React from 'react';
|
||||||
|
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
||||||
|
import { PieChart as RechartsPieChart, Pie, Sector, Cell, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
|
import Title from './Title';
|
||||||
|
|
||||||
|
const dataExample = [
|
||||||
|
{
|
||||||
|
"id": 3366,
|
||||||
|
"name": "FINALIZADO",
|
||||||
|
"count": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3369,
|
||||||
|
"name": "LEMBRETE",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3367,
|
||||||
|
"name": "EXEMPLO",
|
||||||
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3364,
|
||||||
|
"name": "EXEMPLO 2",
|
||||||
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3364,
|
||||||
|
"name": "EXEMPLO 3",
|
||||||
|
"count": 6
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const COLORS = [
|
||||||
|
'#0088FE', // Azul escuro
|
||||||
|
'#00C49F', // Verde menta
|
||||||
|
'#FFBB28', // Laranja escuro
|
||||||
|
'#FF8042', // Vermelho escuro
|
||||||
|
'#9D38BD', // Roxo escuro
|
||||||
|
'#FFD166', // Laranja claro
|
||||||
|
'#331F00', // Marrom escuro
|
||||||
|
'#C0FFC0', // Verde Claro
|
||||||
|
'#C4E538', // Verde-amarelo vibrante
|
||||||
|
'#A2A2A2', // Cinza claro
|
||||||
|
];;
|
||||||
|
|
||||||
|
const RADIAN = Math.PI / 180;
|
||||||
|
|
||||||
|
const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, count }) => {
|
||||||
|
const radius = innerRadius + (outerRadius - innerRadius) * 0.75;
|
||||||
|
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
||||||
|
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<text x={x} y={y} fill="white" textAnchor={x > cx ? 'start' : 'end'} dominantBaseline="central">
|
||||||
|
{count}
|
||||||
|
</text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param data array de objetos no formato
|
||||||
|
* {
|
||||||
|
"id": number | string,
|
||||||
|
"name": string,
|
||||||
|
"count": number
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const PieChart = ({ data = dataExample }) => {
|
||||||
|
return (
|
||||||
|
<Box width="100%" height="100%" position="relative" display="flex">
|
||||||
|
<Box sx={{ position: "absolute" }}>
|
||||||
|
<Title>Tickets Status</Title>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
component="ul"
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0, right: 0,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: "4px"
|
||||||
|
}}>
|
||||||
|
{data.map((entry, index) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
component="li"
|
||||||
|
key={entry.id}
|
||||||
|
sx={{
|
||||||
|
display: "flex", gap: "2px",
|
||||||
|
color: COLORS[index % COLORS.length],
|
||||||
|
alignItems: "center"
|
||||||
|
}}>
|
||||||
|
<FiberManualRecordIcon fill={COLORS[index % COLORS.length]} />
|
||||||
|
<text style={{ color: 'black' }}>{entry.name}</text>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
<Box width="100%" height="100%" alignSelf="flex-end">
|
||||||
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
|
<RechartsPieChart width={400} height={400}>
|
||||||
|
<Pie
|
||||||
|
data={data}
|
||||||
|
cx="40%"
|
||||||
|
cy="60%"
|
||||||
|
labelLine={false}
|
||||||
|
label={renderCustomizedLabel}
|
||||||
|
outerRadius={100}
|
||||||
|
fill="#8884d8"
|
||||||
|
dataKey="count"
|
||||||
|
>
|
||||||
|
{data.map((entry, index) => (
|
||||||
|
<Cell key={`cell-${entry.id}`} fill={COLORS[index % COLORS.length]} />
|
||||||
|
))}
|
||||||
|
</Pie>
|
||||||
|
</RechartsPieChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</Box>
|
||||||
|
</Box >
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PieChart
|
|
@ -15,6 +15,7 @@ import Info from "@material-ui/icons/Info"
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||||
// import { i18n } from "../../translate/i18n";
|
// import { i18n } from "../../translate/i18n";
|
||||||
import Chart from "./Chart"
|
import Chart from "./Chart"
|
||||||
|
import PieChart from "./PieChart"
|
||||||
import openSocket from "socket.io-client"
|
import openSocket from "socket.io-client"
|
||||||
import api from "../../services/api"
|
import api from "../../services/api"
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ const useStyles = makeStyles((theme) => ({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
height: 240,
|
height: 280,
|
||||||
},
|
},
|
||||||
customFixedHeightPaper: {
|
customFixedHeightPaper: {
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
|
@ -108,7 +109,7 @@ const useStyles = makeStyles((theme) => ({
|
||||||
|
|
||||||
var _fifo
|
var _fifo
|
||||||
|
|
||||||
const sumOnlineTimeNow = (oldOnlineTimeSum) => {
|
const sumOnlineTimeNow = (oldOnlineTimeSum) => {
|
||||||
|
|
||||||
let onlineTime = new Date()
|
let onlineTime = new Date()
|
||||||
|
|
||||||
|
@ -138,7 +139,7 @@ const sumOnlineTimeNow = (oldOnlineTimeSum) => {
|
||||||
|
|
||||||
const isoDate = new Date(onlineTime)
|
const isoDate = new Date(onlineTime)
|
||||||
|
|
||||||
const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ')
|
const newOnlinetime = isoDate.toJSON().slice(0, 19).replace('T', ' ')
|
||||||
|
|
||||||
return newOnlinetime
|
return newOnlinetime
|
||||||
}
|
}
|
||||||
|
@ -207,9 +208,9 @@ const reducer = (state, action) => {
|
||||||
|
|
||||||
if ("onlineTime" in onlineUser) {
|
if ("onlineTime" in onlineUser) {
|
||||||
|
|
||||||
if ("sumOnlineTime" in state[index]) {
|
if ("sumOnlineTime" in state[index]) {
|
||||||
|
|
||||||
state[index].sumOnlineTime.sum = onlineUser.onlineTime.split(" ")[1]
|
state[index].sumOnlineTime.sum = onlineUser.onlineTime.split(" ")[1]
|
||||||
|
|
||||||
} else if (!("sumOnlineTime" in state[index])) {
|
} else if (!("sumOnlineTime" in state[index])) {
|
||||||
|
|
||||||
|
@ -283,7 +284,7 @@ const Dashboard = () => {
|
||||||
try {
|
try {
|
||||||
let date = new Date().toLocaleDateString("pt-BR").split("/")
|
let date = new Date().toLocaleDateString("pt-BR").split("/")
|
||||||
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
|
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
|
||||||
|
|
||||||
const { data } = await api.get("/reports/user/services", {
|
const { data } = await api.get("/reports/user/services", {
|
||||||
params: { userId: null, startDate: dateToday, endDate: dateToday },
|
params: { userId: null, startDate: dateToday, endDate: dateToday },
|
||||||
})
|
})
|
||||||
|
@ -319,7 +320,7 @@ const Dashboard = () => {
|
||||||
if (usersOnlineInfo[i].statusOnline && usersOnlineInfo[i].statusOnline.status === 'online') {
|
if (usersOnlineInfo[i].statusOnline && usersOnlineInfo[i].statusOnline.status === 'online') {
|
||||||
|
|
||||||
let onlineTimeCurrent = sumOnlineTimeNow({ onlineTime: usersOnlineInfo[i].statusOnline.onlineTime, updatedAt: usersOnlineInfo[i].statusOnline.updatedAt })
|
let onlineTimeCurrent = sumOnlineTimeNow({ onlineTime: usersOnlineInfo[i].statusOnline.onlineTime, updatedAt: usersOnlineInfo[i].statusOnline.updatedAt })
|
||||||
|
|
||||||
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: usersOnlineInfo[i].id, status: usersOnlineInfo[i].statusOnline.status, onlineTime: onlineTimeCurrent } })
|
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: { userId: usersOnlineInfo[i].id, status: usersOnlineInfo[i].statusOnline.status, onlineTime: onlineTimeCurrent } })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -356,7 +357,7 @@ const Dashboard = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("onlineStatus", (data) => {
|
socket.on("onlineStatus", (data) => {
|
||||||
if (data.action === "logout" || data.action === "update") {
|
if (data.action === "logout" || data.action === "update") {
|
||||||
|
|
||||||
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
|
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
|
||||||
} else if (data.action === "delete") {
|
} else if (data.action === "delete") {
|
||||||
|
@ -497,10 +498,17 @@ const Dashboard = () => {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item container spacing={3}>
|
||||||
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
<Chart allTickets={usersOnlineInfo} />
|
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
||||||
</Paper>
|
<Chart allTickets={usersOnlineInfo} />
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} md={6} lg={6}>
|
||||||
|
<Paper className={classes.fixedHeightPaper} variant="outlined">
|
||||||
|
<PieChart data={[]} />
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
|
@ -235,6 +235,7 @@ let columnsData = [
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
||||||
|
{ title: `Espera`, field: 'waiting_time' },
|
||||||
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -249,6 +250,7 @@ let columnsDataSuper = [
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_7")}`, field: 'createdAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
{ title: `${i18n.t("reports.listColumns.column1_8")}`, field: 'updatedAt' },
|
||||||
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
{ title: `${i18n.t("reports.listColumns.column1_9")}`, field: 'statusChatEnd' },
|
||||||
|
{ title: `Espera`, field: 'waiting_time' },
|
||||||
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
{ title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue