602 lines
19 KiB
TypeScript
602 lines
19 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import { DashboardService } from '../services/dashboard.service';
|
|
import logger from '@utils/logger';
|
|
|
|
export class DashboardController {
|
|
private dashboardService: DashboardService;
|
|
|
|
constructor() {
|
|
this.dashboardService = new DashboardService();
|
|
}
|
|
|
|
/**
|
|
* Get all KPI metrics for dashboard
|
|
*/
|
|
async getKPIs(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
const viewAsUser = req.query.viewAsUser === 'true'; // For admin to view as normal user
|
|
|
|
const kpis = await this.dashboardService.getKPIs(userId, dateRange, startDate, endDate, viewAsUser);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: kpis
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching KPIs:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch dashboard KPIs'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get request volume and status statistics
|
|
*/
|
|
async getRequestStats(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
const status = req.query.status as string | undefined; // Status filter (not used in stats - stats show all statuses)
|
|
const priority = req.query.priority as string | undefined;
|
|
const department = req.query.department as string | undefined;
|
|
const initiator = req.query.initiator as string | undefined;
|
|
const approver = req.query.approver as string | undefined;
|
|
const approverType = req.query.approverType as 'current' | 'any' | undefined;
|
|
const search = req.query.search as string | undefined;
|
|
const slaCompliance = req.query.slaCompliance as string | undefined;
|
|
const viewAsUser = req.query.viewAsUser === 'true'; // When true, treat admin as normal user
|
|
|
|
const stats = await this.dashboardService.getRequestStats(
|
|
userId,
|
|
dateRange,
|
|
startDate,
|
|
endDate,
|
|
status,
|
|
priority,
|
|
department,
|
|
initiator,
|
|
approver,
|
|
approverType,
|
|
search,
|
|
slaCompliance,
|
|
viewAsUser
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: stats
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching request stats:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch request statistics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get TAT efficiency metrics
|
|
*/
|
|
async getTATEfficiency(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const efficiency = await this.dashboardService.getTATEfficiency(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: efficiency
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching TAT efficiency:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch TAT efficiency metrics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get approver load statistics
|
|
*/
|
|
async getApproverLoad(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const load = await this.dashboardService.getApproverLoad(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: load
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching approver load:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch approver load statistics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get engagement and quality metrics
|
|
*/
|
|
async getEngagementStats(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const engagement = await this.dashboardService.getEngagementStats(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: engagement
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching engagement stats:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch engagement statistics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get AI insights and closure metrics
|
|
*/
|
|
async getAIInsights(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const insights = await this.dashboardService.getAIInsights(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: insights
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching AI insights:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch AI insights'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get AI Remark Utilization metrics with monthly trends
|
|
*/
|
|
async getAIRemarkUtilization(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const utilization = await this.dashboardService.getAIRemarkUtilization(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: utilization
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching AI remark utilization:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch AI remark utilization'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Approver Performance metrics with pagination
|
|
*/
|
|
async getApproverPerformance(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 10);
|
|
|
|
const result = await this.dashboardService.getApproverPerformance(userId, dateRange, page, limit, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.performance,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching approver performance:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch approver performance metrics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get recent activity feed
|
|
*/
|
|
async getRecentActivity(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 10);
|
|
const viewAsUser = req.query.viewAsUser === 'true'; // For admin to view as normal user
|
|
|
|
const result = await this.dashboardService.getRecentActivity(userId, page, limit, viewAsUser);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.activities,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching recent activity:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch recent activity'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get critical/high priority requests with pagination
|
|
*/
|
|
async getCriticalRequests(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 10);
|
|
const viewAsUser = req.query.viewAsUser === 'true'; // For admin to view as normal user
|
|
|
|
const result = await this.dashboardService.getCriticalRequests(userId, page, limit, viewAsUser);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.criticalRequests,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching critical requests:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch critical requests'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get upcoming deadlines with pagination
|
|
*/
|
|
async getUpcomingDeadlines(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 10);
|
|
const viewAsUser = req.query.viewAsUser === 'true'; // For admin to view as normal user
|
|
|
|
const result = await this.dashboardService.getUpcomingDeadlines(userId, page, limit, viewAsUser);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.deadlines,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching upcoming deadlines:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch upcoming deadlines'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get department-wise statistics
|
|
*/
|
|
async getDepartmentStats(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const stats = await this.dashboardService.getDepartmentStats(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: stats
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching department stats:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch department statistics'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get priority distribution statistics
|
|
*/
|
|
async getPriorityDistribution(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const distribution = await this.dashboardService.getPriorityDistribution(userId, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: distribution
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching priority distribution:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch priority distribution'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Request Lifecycle Report
|
|
*/
|
|
async getLifecycleReport(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 50);
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const result = await this.dashboardService.getLifecycleReport(userId, page, limit, dateRange, startDate, endDate);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.lifecycleData,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching lifecycle report:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch lifecycle report'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get enhanced User Activity Log Report
|
|
*/
|
|
async getActivityLogReport(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 50);
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
const filterUserId = req.query.filterUserId as string | undefined;
|
|
const filterType = req.query.filterType as string | undefined;
|
|
const filterCategory = req.query.filterCategory as string | undefined;
|
|
const filterSeverity = req.query.filterSeverity as string | undefined;
|
|
|
|
const result = await this.dashboardService.getActivityLogReport(
|
|
userId,
|
|
page,
|
|
limit,
|
|
dateRange,
|
|
filterUserId,
|
|
filterType,
|
|
filterCategory,
|
|
filterSeverity,
|
|
startDate,
|
|
endDate
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.activities,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching activity log report:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch activity log report'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get list of departments (metadata for filtering)
|
|
* GET /api/v1/dashboard/metadata/departments
|
|
*/
|
|
async getDepartments(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
if (!userId) {
|
|
res.status(401).json({
|
|
success: false,
|
|
message: 'Unauthorized',
|
|
timestamp: new Date()
|
|
});
|
|
return;
|
|
}
|
|
|
|
const departments = await this.dashboardService.getDepartments(userId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: 'Departments retrieved successfully',
|
|
data: {
|
|
departments
|
|
},
|
|
timestamp: new Date()
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Get Departments failed:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Internal server error',
|
|
timestamp: new Date()
|
|
});
|
|
}
|
|
}
|
|
|
|
async getWorkflowAgingReport(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const threshold = Number(req.query.threshold || 7);
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 50);
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
|
|
const result = await this.dashboardService.getWorkflowAgingReport(
|
|
userId,
|
|
threshold,
|
|
page,
|
|
limit,
|
|
dateRange,
|
|
startDate,
|
|
endDate
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.agingData,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching workflow aging report:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch workflow aging report'
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get requests filtered by approver ID for detailed performance analysis
|
|
*/
|
|
async getRequestsByApprover(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.userId;
|
|
const approverId = req.query.approverId as string;
|
|
const page = Number(req.query.page || 1);
|
|
const limit = Number(req.query.limit || 50);
|
|
const dateRange = req.query.dateRange as string | undefined;
|
|
const startDate = req.query.startDate as string | undefined;
|
|
const endDate = req.query.endDate as string | undefined;
|
|
const status = req.query.status as string | undefined;
|
|
const priority = req.query.priority as string | undefined;
|
|
const slaCompliance = req.query.slaCompliance as string | undefined;
|
|
const search = req.query.search as string | undefined;
|
|
|
|
if (!approverId) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: 'Approver ID is required'
|
|
});
|
|
return;
|
|
}
|
|
|
|
const result = await this.dashboardService.getRequestsByApprover(
|
|
userId,
|
|
approverId,
|
|
page,
|
|
limit,
|
|
dateRange,
|
|
startDate,
|
|
endDate,
|
|
status,
|
|
priority,
|
|
slaCompliance,
|
|
search
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.requests,
|
|
pagination: {
|
|
currentPage: result.currentPage,
|
|
totalPages: result.totalPages,
|
|
totalRecords: result.totalRecords,
|
|
limit: result.limit
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[Dashboard] Error fetching requests by approver:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to fetch requests by approver'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|