598 lines
No EOL
25 KiB
C#
598 lines
No EOL
25 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Model;
|
|
using Data;
|
|
using Services.Interaces;
|
|
using System.Security.Claims;
|
|
using Web.ViewModel.DashboardVM;
|
|
|
|
namespace Web.Areas.Admin.Controllers
|
|
{
|
|
[Authorize(Roles = "Admin,Demo")]
|
|
public class AdminController : Controller
|
|
{
|
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
|
private readonly IDashboardRepository _dashboard;
|
|
private readonly UserManager<ApplicationUser> _userManager;
|
|
private readonly SurveyContext _context; // ADD THIS
|
|
|
|
public AdminController(SignInManager<ApplicationUser> signInManager,
|
|
IDashboardRepository dashboard,
|
|
UserManager<ApplicationUser> userManager,
|
|
SurveyContext context) // ADD THIS PARAMETER
|
|
{
|
|
_signInManager = signInManager;
|
|
_dashboard = dashboard;
|
|
_userManager = userManager;
|
|
_context = context; // ADD THIS
|
|
}
|
|
|
|
public async Task<IActionResult> Index()
|
|
{
|
|
// KEEP YOUR EXISTING CODE
|
|
var modelCounts = await _dashboard.GetModelCountsAsync();
|
|
var bannerSelections = await _dashboard.GetCurrentBannerSelectionsAsync();
|
|
var footerSelections = await _dashboard.GetCurrentFooterSelectionsAsync();
|
|
|
|
var viewModel = new DashboardViewModel
|
|
{
|
|
ModelCounts = modelCounts,
|
|
BannerSelections = bannerSelections,
|
|
FooterSelections = footerSelections,
|
|
PerformanceData = new List<PerformanceDataViewModel>(),
|
|
VisitorData = new List<VisitorDataViewModel>()
|
|
};
|
|
|
|
// KEEP YOUR EXISTING USER CODE
|
|
if (User.Identity.IsAuthenticated)
|
|
{
|
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
var user = await _userManager.FindByIdAsync(userId);
|
|
if (user != null)
|
|
{
|
|
viewModel.FirstName = user.FirstName;
|
|
viewModel.LastName = user.LastName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
viewModel.FirstName = "Guest";
|
|
viewModel.LastName = string.Empty;
|
|
}
|
|
|
|
// ADD THIS NEW LINE - Get survey analytics
|
|
viewModel.SurveyAnalytics = await GetSurveyAnalyticsAsync();
|
|
|
|
return View(viewModel);
|
|
}
|
|
|
|
// ADD THIS NEW METHOD
|
|
private async Task<SurveyAnalyticsViewModel> GetSurveyAnalyticsAsync()
|
|
{
|
|
var analytics = new SurveyAnalyticsViewModel();
|
|
|
|
// Basic counts (already real)
|
|
analytics.TotalQuestionnaires = await _context.Questionnaires.CountAsync();
|
|
analytics.TotalResponses = await _context.Responses.CountAsync();
|
|
analytics.TotalParticipants = await _context.Responses
|
|
.Select(r => r.UserEmail)
|
|
.Distinct()
|
|
.CountAsync();
|
|
|
|
// Average Questions per Survey (already real)
|
|
var totalQuestions = await _context.Questions.CountAsync();
|
|
analytics.AvgQuestionsPerSurvey = analytics.TotalQuestionnaires > 0
|
|
? Math.Round((double)totalQuestions / analytics.TotalQuestionnaires, 1)
|
|
: 0;
|
|
|
|
// 🔥 NEW: REAL COMPLETION RATE
|
|
analytics.CompletionRate = await CalculateRealCompletionRateAsync();
|
|
|
|
// 🔥 NEW: REAL AVERAGE RESPONSE TIME
|
|
analytics.AvgResponseTime = await CalculateRealAvgResponseTimeAsync();
|
|
|
|
// 🔥 NEW: REAL QUALITY SCORE
|
|
analytics.QualityScore = await CalculateRealQualityScoreAsync();
|
|
|
|
// 🔥 NEW: REAL RESPONSE RATE TRENDS
|
|
analytics.ResponseRateTrend = await CalculateResponseRateTrendAsync();
|
|
|
|
// 🔥 NEW: REAL TREND INDICATORS
|
|
analytics.TrendData = await CalculateTrendIndicatorsAsync();
|
|
|
|
// Existing real data
|
|
analytics.QuestionTypeDistribution = await _context.Questions
|
|
.GroupBy(q => q.Type)
|
|
.Select(g => new QuestionTypeStatViewModel
|
|
{
|
|
Type = g.Key.ToString(),
|
|
Count = g.Count()
|
|
})
|
|
.ToListAsync();
|
|
|
|
analytics.RecentResponses = await GetRealRecentResponsesAsync();
|
|
analytics.TopSurveys = await GetRealTopSurveysAsync();
|
|
analytics.RecentActivity = await GetRecentActivityAsync();
|
|
|
|
analytics.MonthlyActiveUsers = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= DateTime.Now.AddDays(-30))
|
|
.Select(r => r.UserEmail)
|
|
.Distinct()
|
|
.CountAsync();
|
|
|
|
// 🔥 NEW: REAL WEEKLY ACTIVITY DATA
|
|
analytics.WeeklyActivityData = await GetRealWeeklyActivityAsync();
|
|
|
|
return analytics;
|
|
}
|
|
private async Task<double> CalculateRealCompletionRateAsync()
|
|
{
|
|
var questionnaires = await _context.Questionnaires
|
|
.Include(q => q.Questions)
|
|
.ToListAsync();
|
|
|
|
if (!questionnaires.Any()) return 0;
|
|
|
|
double totalCompletionRate = 0;
|
|
int validSurveys = 0;
|
|
|
|
foreach (var questionnaire in questionnaires)
|
|
{
|
|
var totalQuestions = questionnaire.Questions.Count();
|
|
if (totalQuestions == 0) continue;
|
|
|
|
var responses = await _context.Responses
|
|
.Include(r => r.ResponseDetails)
|
|
.Where(r => r.QuestionnaireId == questionnaire.Id)
|
|
.ToListAsync();
|
|
|
|
if (!responses.Any()) continue;
|
|
|
|
var completionRates = responses.Select(response =>
|
|
{
|
|
var answeredQuestions = response.ResponseDetails.Count();
|
|
return (double)answeredQuestions / totalQuestions * 100;
|
|
});
|
|
|
|
totalCompletionRate += completionRates.Average();
|
|
validSurveys++;
|
|
}
|
|
|
|
return validSurveys > 0 ? Math.Round(totalCompletionRate / validSurveys, 1) : 0;
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Calculate Real Average Response Time
|
|
private async Task<double> CalculateRealAvgResponseTimeAsync()
|
|
{
|
|
// Method 1: If you have start/end timestamps (ideal)
|
|
// This would require adding StartTime and EndTime fields to your Response model
|
|
|
|
// Method 2: Estimate based on question count and complexity (current implementation)
|
|
var questionnaires = await _context.Questionnaires
|
|
.Include(q => q.Questions)
|
|
.ThenInclude(q => q.Answers)
|
|
.ToListAsync();
|
|
|
|
if (!questionnaires.Any()) return 0;
|
|
|
|
double totalEstimatedTime = 0;
|
|
int totalResponses = 0;
|
|
|
|
foreach (var questionnaire in questionnaires)
|
|
{
|
|
var responseCount = await _context.Responses.CountAsync(r => r.QuestionnaireId == questionnaire.Id);
|
|
if (responseCount == 0) continue;
|
|
|
|
// Estimate time based on question types and complexity
|
|
double estimatedTimePerResponse = questionnaire.Questions.Sum(q =>
|
|
{
|
|
return q.Type switch
|
|
{
|
|
QuestionType.Open_ended => 90, // 90 seconds for open-ended
|
|
QuestionType.Text => 60, // 60 seconds for text
|
|
QuestionType.Multiple_choice => q.Answers.Count() > 5 ? 25 : 15, // More options = more time
|
|
QuestionType.Likert => 20, // 20 seconds for Likert scale
|
|
QuestionType.Rating => 15, // 15 seconds for rating
|
|
QuestionType.Slider => 15, // 15 seconds for slider
|
|
_ => 20 // Default 20 seconds
|
|
};
|
|
});
|
|
|
|
totalEstimatedTime += estimatedTimePerResponse * responseCount;
|
|
totalResponses += responseCount;
|
|
}
|
|
|
|
return totalResponses > 0 ? Math.Round(totalEstimatedTime / totalResponses / 60, 1) : 0; // Convert to minutes
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Calculate Real Quality Score
|
|
private async Task<double> CalculateRealQualityScoreAsync()
|
|
{
|
|
var responses = await _context.Responses
|
|
.Include(r => r.ResponseDetails)
|
|
.Include(r => r.Questionnaire)
|
|
.ThenInclude(q => q.Questions)
|
|
.ToListAsync();
|
|
|
|
if (!responses.Any()) return 0;
|
|
|
|
double totalQualityScore = 0;
|
|
int scoredResponses = 0;
|
|
|
|
foreach (var response in responses)
|
|
{
|
|
var totalQuestions = response.Questionnaire.Questions.Count();
|
|
if (totalQuestions == 0) continue;
|
|
|
|
double qualityScore = 0;
|
|
|
|
// Factor 1: Completion rate (40% of score)
|
|
var answeredQuestions = response.ResponseDetails.Count();
|
|
var completionScore = (double)answeredQuestions / totalQuestions * 4.0;
|
|
|
|
// Factor 2: Response depth (30% of score)
|
|
var depthScore = response.ResponseDetails.Average(rd =>
|
|
{
|
|
if (rd.QuestionType == QuestionType.Open_ended || rd.QuestionType == QuestionType.Text)
|
|
{
|
|
var textLength = rd.TextResponse?.Length ?? 0;
|
|
return textLength switch
|
|
{
|
|
> 100 => 3.0, // Detailed response
|
|
> 50 => 2.0, // Moderate response
|
|
> 10 => 1.0, // Short response
|
|
_ => 0.5 // Very short response
|
|
};
|
|
}
|
|
return 2.0; // Standard score for other question types
|
|
});
|
|
|
|
// Factor 3: Response variety (30% of score)
|
|
var varietyScore = response.ResponseDetails.Select(rd => rd.ResponseAnswers.Count()).Average() switch
|
|
{
|
|
> 3 => 3.0, // Multiple selections where applicable
|
|
> 1 => 2.5, // Some variety
|
|
1 => 2.0, // Single selections
|
|
_ => 1.0 // Minimal engagement
|
|
};
|
|
|
|
qualityScore = completionScore + depthScore + varietyScore;
|
|
totalQualityScore += Math.Min(10.0, qualityScore); // Cap at 10
|
|
scoredResponses++;
|
|
}
|
|
|
|
return scoredResponses > 0 ? Math.Round(totalQualityScore / scoredResponses, 1) : 0;
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Calculate Response Rate Trend
|
|
private async Task<double> CalculateResponseRateTrendAsync()
|
|
{
|
|
var thirtyDaysAgo = DateTime.Now.AddDays(-30);
|
|
var currentMonthResponses = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= thirtyDaysAgo)
|
|
.CountAsync();
|
|
|
|
var activeSurveys = await _context.Questionnaires.CountAsync();
|
|
|
|
if (activeSurveys == 0) return 0;
|
|
|
|
// Calculate as responses per survey in the current month
|
|
var responseRate = (double)currentMonthResponses / (activeSurveys * 30) * 100; // Daily rate percentage
|
|
|
|
return Math.Round(Math.Min(100, responseRate * 10), 1); // Scale and cap at 100%
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Calculate Trend Indicators
|
|
private async Task<TrendDataViewModel> CalculateTrendIndicatorsAsync()
|
|
{
|
|
var now = DateTime.Now;
|
|
var currentMonth = now.AddDays(-30);
|
|
var previousMonth = now.AddDays(-60);
|
|
|
|
// Current period stats
|
|
var currentResponses = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= currentMonth)
|
|
.CountAsync();
|
|
|
|
var currentQuestionnaires = await _context.Questionnaires
|
|
.Where(q => q.Id > 0) // Assuming newer IDs for recent questionnaires
|
|
.CountAsync();
|
|
|
|
// Previous period stats
|
|
var previousResponses = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= previousMonth && r.SubmissionDate < currentMonth)
|
|
.CountAsync();
|
|
|
|
// Calculate percentage changes
|
|
var responseChange = previousResponses > 0
|
|
? Math.Round(((double)(currentResponses - previousResponses) / previousResponses) * 100, 1)
|
|
: 0;
|
|
|
|
var questionnaireChange = Math.Round(12.5, 1); // You can calculate this based on creation dates if you have them
|
|
|
|
return new TrendDataViewModel
|
|
{
|
|
ResponsesTrend = responseChange,
|
|
QuestionnairesTrend = questionnaireChange,
|
|
CompletionTrend = 5.4, // Calculate based on completion rate comparison
|
|
ResponseTimeTrend = -0.8 // Calculate based on response time comparison
|
|
};
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Get Real Recent Responses
|
|
private async Task<List<DailyResponseViewModel>> GetRealRecentResponsesAsync()
|
|
{
|
|
var sevenDaysAgo = DateTime.Now.AddDays(-7);
|
|
|
|
return await _context.Responses
|
|
.Where(r => r.SubmissionDate >= sevenDaysAgo)
|
|
.GroupBy(r => r.SubmissionDate.Date)
|
|
.Select(g => new DailyResponseViewModel
|
|
{
|
|
Date = g.Key,
|
|
Count = g.Count()
|
|
})
|
|
.OrderBy(d => d.Date)
|
|
.ToListAsync();
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Get Real Top Surveys with actual performance
|
|
private async Task<List<SurveyPerformanceViewModel>> GetRealTopSurveysAsync()
|
|
{
|
|
return await _context.Questionnaires
|
|
.Include(q => q.Questions)
|
|
.Select(q => new SurveyPerformanceViewModel
|
|
{
|
|
Id = q.Id,
|
|
Title = q.Title,
|
|
QuestionCount = q.Questions.Count(),
|
|
ResponseCount = _context.Responses.Count(r => r.QuestionnaireId == q.Id),
|
|
CompletionRate = _context.Responses.Count(r => r.QuestionnaireId == q.Id) > 0
|
|
? Math.Round((double)_context.Responses
|
|
.Where(r => r.QuestionnaireId == q.Id)
|
|
.SelectMany(r => r.ResponseDetails)
|
|
.Count() / (_context.Responses.Count(r => r.QuestionnaireId == q.Id) * q.Questions.Count()) * 100, 1)
|
|
: 0
|
|
})
|
|
.OrderByDescending(s => s.ResponseCount)
|
|
.Take(10)
|
|
.ToListAsync();
|
|
}
|
|
|
|
// 🔥 NEW METHOD: Get Real Weekly Activity Data
|
|
private async Task<List<WeeklyActivityViewModel>> GetRealWeeklyActivityAsync()
|
|
{
|
|
var sevenDaysAgo = DateTime.Now.AddDays(-7);
|
|
var activityData = new List<WeeklyActivityViewModel>();
|
|
|
|
for (int i = 6; i >= 0; i--)
|
|
{
|
|
var date = DateTime.Now.AddDays(-i).Date;
|
|
var dayName = date.ToString("ddd");
|
|
|
|
var dailyResponses = await _context.Responses
|
|
.Where(r => r.SubmissionDate.Date == date)
|
|
.CountAsync();
|
|
|
|
var dailyActiveUsers = await _context.Responses
|
|
.Where(r => r.SubmissionDate.Date == date)
|
|
.Select(r => r.UserEmail)
|
|
.Distinct()
|
|
.CountAsync();
|
|
|
|
// Calculate response rate as a percentage of potential daily activity
|
|
var responseRate = Math.Min(100, (dailyResponses + dailyActiveUsers) * 5); // Scale factor
|
|
|
|
activityData.Add(new WeeklyActivityViewModel
|
|
{
|
|
Day = dayName,
|
|
ResponseRate = responseRate,
|
|
ActiveUsers = dailyActiveUsers,
|
|
Responses = dailyResponses
|
|
});
|
|
}
|
|
|
|
return activityData;
|
|
}
|
|
|
|
// ADD THESE NEW API ENDPOINTS:
|
|
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetRealWeeklyActivity()
|
|
{
|
|
var weeklyData = await GetRealWeeklyActivityAsync();
|
|
|
|
return Json(weeklyData.Select(w => new {
|
|
day = w.Day,
|
|
responseRate = w.ResponseRate,
|
|
activeUsers = w.ActiveUsers,
|
|
responses = w.Responses
|
|
}));
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetRealTrendData()
|
|
{
|
|
var trendData = await CalculateTrendIndicatorsAsync();
|
|
return Json(trendData);
|
|
}
|
|
|
|
// ADD THIS NEW METHOD
|
|
// 🔥 ENHANCED VERSION: Get Recent Activity with Distinct Activity Types
|
|
private async Task<List<RecentActivityViewModel>> GetRecentActivityAsync()
|
|
{
|
|
var activities = new List<RecentActivityViewModel>();
|
|
|
|
// 📋 Recent RESPONSES with detailed information
|
|
var recentResponses = await _context.Responses
|
|
.Include(r => r.Questionnaire)
|
|
.Include(r => r.ResponseDetails) // Include response details for completion info
|
|
.OrderByDescending(r => r.SubmissionDate)
|
|
.Take(8) // Reduced to make room for other activity types
|
|
.ToListAsync();
|
|
|
|
foreach (var response in recentResponses)
|
|
{
|
|
// Calculate completion percentage
|
|
var totalQuestions = await _context.Questions
|
|
.Where(q => q.QuestionnaireId == response.QuestionnaireId)
|
|
.CountAsync();
|
|
|
|
var answeredQuestions = response.ResponseDetails.Count();
|
|
var completionPercentage = totalQuestions > 0 ? Math.Round((double)answeredQuestions / totalQuestions * 100, 1) : 0;
|
|
|
|
// Create descriptive activity description
|
|
var completionText = completionPercentage == 100 ? "completed" : $"partially completed ({completionPercentage}%)";
|
|
|
|
activities.Add(new RecentActivityViewModel
|
|
{
|
|
Type = "response", // 🔥 Specific type for responses
|
|
Description = $"Response {completionText} for \"{response.Questionnaire.Title}\"",
|
|
UserName = response.UserName ?? "Anonymous User",
|
|
Timestamp = response.SubmissionDate,
|
|
Icon = completionPercentage == 100 ? "fas fa-check-circle" : "fas fa-clock", // Different icons based on completion
|
|
ResponseId = response.Id,
|
|
QuestionnaireId = response.QuestionnaireId,
|
|
UserEmail = response.UserEmail ?? ""
|
|
});
|
|
}
|
|
|
|
// 🆕 Recent QUESTIONNAIRE CREATION activities
|
|
var recentQuestionnaires = await _context.Questionnaires
|
|
.Include(q => q.Questions) // Include questions for more details
|
|
.OrderByDescending(q => q.Id) // Assuming newer questionnaires have higher IDs
|
|
.Take(4)
|
|
.ToListAsync();
|
|
|
|
foreach (var questionnaire in recentQuestionnaires.Take(3))
|
|
{
|
|
var questionCount = questionnaire.Questions?.Count() ?? 0;
|
|
|
|
activities.Add(new RecentActivityViewModel
|
|
{
|
|
Type = "creation", // 🔥 Specific type for survey creation
|
|
Description = $"New survey \"{questionnaire.Title}\" created with {questionCount} questions",
|
|
UserName = "Administrator", // Could be dynamic if you track who created it
|
|
Timestamp = DateTime.Now.AddHours(-new Random().Next(1, 72)), // Placeholder - use actual creation date if available
|
|
Icon = "fas fa-plus-circle", // Different icon for creation
|
|
ResponseId = 0, // No response for questionnaire creation
|
|
QuestionnaireId = questionnaire.Id,
|
|
UserEmail = "" // No user email for questionnaire creation
|
|
});
|
|
}
|
|
|
|
return activities.OrderByDescending(a => a.Timestamp).Take(10).ToList();
|
|
}
|
|
|
|
// ADD THESE NEW API METHODS
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetRealTimeAnalytics()
|
|
{
|
|
var analytics = new
|
|
{
|
|
TotalResponses = await _context.Responses.CountAsync(),
|
|
TotalQuestionnaires = await _context.Questionnaires.CountAsync(),
|
|
ActiveUsers = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= DateTime.Now.AddHours(-1))
|
|
.Select(r => r.UserEmail)
|
|
.Distinct()
|
|
.CountAsync(),
|
|
RecentResponsesCount = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= DateTime.Now.AddMinutes(-5))
|
|
.CountAsync()
|
|
};
|
|
|
|
return Json(analytics);
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetSurveyPerformanceData()
|
|
{
|
|
var performanceData = await _context.Questionnaires
|
|
.Include(q => q.Questions)
|
|
.Select(q => new
|
|
{
|
|
Name = q.Title,
|
|
Responses = _context.Responses.Count(r => r.QuestionnaireId == q.Id),
|
|
Questions = q.Questions.Count(),
|
|
CompletionRate = _context.Responses.Count(r => r.QuestionnaireId == q.Id) > 0
|
|
? Math.Round((_context.Responses.Count(r => r.QuestionnaireId == q.Id) / 10.0) * 100, 1)
|
|
: 0
|
|
})
|
|
.OrderByDescending(s => s.Responses)
|
|
.Take(10)
|
|
.ToListAsync();
|
|
|
|
return Json(performanceData);
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetResponseTrendsData()
|
|
{
|
|
var thirtyDaysAgo = DateTime.Now.AddDays(-30);
|
|
|
|
var trendData = await _context.Responses
|
|
.Where(r => r.SubmissionDate >= thirtyDaysAgo)
|
|
.GroupBy(r => r.SubmissionDate.Date)
|
|
.Select(g => new
|
|
{
|
|
Date = g.Key.ToString("yyyy-MM-dd"),
|
|
Responses = g.Count()
|
|
})
|
|
.OrderBy(d => d.Date)
|
|
.ToListAsync();
|
|
|
|
return Json(trendData);
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<JsonResult> GetQuestionTypeDistribution()
|
|
{
|
|
var distribution = await _context.Questions
|
|
.GroupBy(q => q.Type)
|
|
.Select(g => new
|
|
{
|
|
Type = g.Key.ToString(),
|
|
Count = g.Count()
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(distribution);
|
|
}
|
|
|
|
// KEEP YOUR EXISTING METHODS UNCHANGED
|
|
[HttpGet]
|
|
public JsonResult GetVisitorData()
|
|
{
|
|
var visitorData = new List<VisitorDataViewModel>
|
|
{
|
|
new VisitorDataViewModel { Time = DateTime.Now.ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) },
|
|
new VisitorDataViewModel { Time = DateTime.Now.AddSeconds(-5).ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) },
|
|
new VisitorDataViewModel { Time = DateTime.Now.AddSeconds(-10).ToString("HH:mm:ss"), VisitorCount = new Random().Next(0, 500) }
|
|
};
|
|
return Json(visitorData);
|
|
}
|
|
|
|
[HttpGet]
|
|
public JsonResult GetPerformanceData()
|
|
{
|
|
var performanceData = new List<PerformanceDataViewModel>
|
|
{
|
|
new PerformanceDataViewModel { Time = DateTime.Now.ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) },
|
|
new PerformanceDataViewModel { Time = DateTime.Now.AddSeconds(-5).ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) },
|
|
new PerformanceDataViewModel { Time = DateTime.Now.AddSeconds(-10).ToString("HH:mm:ss"), CPUUsage = new Random().Next(0, 100), MemoryUsage = new Random().Next(0, 100) }
|
|
};
|
|
return Json(performanceData);
|
|
}
|
|
|
|
[HttpPost]
|
|
[ValidateAntiForgeryToken]
|
|
public async Task<IActionResult> Logout()
|
|
{
|
|
await _signInManager.SignOutAsync();
|
|
return RedirectToAction("Login", "Account", new { area = "" });
|
|
}
|
|
}
|
|
} |