284 lines
9.9 KiB
Plaintext
284 lines
9.9 KiB
Plaintext
@model LittleShop.DTOs.BotMetricsSummaryDto
|
|
@{
|
|
ViewData["Title"] = $"Bot Metrics - {Model.BotName}";
|
|
var bot = ViewData["Bot"] as LittleShop.DTOs.BotDto;
|
|
var sessionSummary = ViewData["SessionSummary"] as LittleShop.DTOs.BotSessionSummaryDto;
|
|
var startDate = (DateTime)ViewData["StartDate"]!;
|
|
var endDate = (DateTime)ViewData["EndDate"]!;
|
|
}
|
|
|
|
<h1>Bot Metrics</h1>
|
|
<h3>@Model.BotName</h3>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-12">
|
|
<form method="get" class="row g-3">
|
|
<div class="col-auto">
|
|
<label for="startDate" class="col-form-label">Start Date:</label>
|
|
</div>
|
|
<div class="col-auto">
|
|
<input type="date" id="startDate" name="startDate" class="form-control" value="@startDate.ToString("yyyy-MM-dd")" />
|
|
</div>
|
|
<div class="col-auto">
|
|
<label for="endDate" class="col-form-label">End Date:</label>
|
|
</div>
|
|
<div class="col-auto">
|
|
<input type="date" id="endDate" name="endDate" class="form-control" value="@endDate.ToString("yyyy-MM-dd")" />
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="submit" class="btn btn-primary">Update</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="card text-center mb-3">
|
|
<div class="card-body">
|
|
<h2 class="text-primary">@Model.TotalSessions</h2>
|
|
<p class="text-muted">Total Sessions</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center mb-3">
|
|
<div class="card-body">
|
|
<h2 class="text-success">@Model.TotalOrders</h2>
|
|
<p class="text-muted">Total Orders</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center mb-3">
|
|
<div class="card-body">
|
|
<h2 class="text-info">$@Model.TotalRevenue.ToString("F2")</h2>
|
|
<p class="text-muted">Total Revenue</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center mb-3">
|
|
<div class="card-body">
|
|
<h2 class="text-warning">@Model.TotalMessages</h2>
|
|
<p class="text-muted">Total Messages</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Performance Metrics</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<dl class="row">
|
|
<dt class="col-sm-6">Average Response Time:</dt>
|
|
<dd class="col-sm-6">@Model.AverageResponseTime.ToString("F2") ms</dd>
|
|
|
|
<dt class="col-sm-6">Uptime Percentage:</dt>
|
|
<dd class="col-sm-6">
|
|
@if (Model.UptimePercentage > 0)
|
|
{
|
|
<span class="badge bg-success">@Model.UptimePercentage.ToString("F1")%</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="text-muted">N/A</span>
|
|
}
|
|
</dd>
|
|
|
|
<dt class="col-sm-6">Total Errors:</dt>
|
|
<dd class="col-sm-6">
|
|
@if (Model.TotalErrors > 0)
|
|
{
|
|
<span class="text-danger">@Model.TotalErrors</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="text-success">0</span>
|
|
}
|
|
</dd>
|
|
|
|
<dt class="col-sm-6">Unique Sessions:</dt>
|
|
<dd class="col-sm-6">@Model.UniqueSessions</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Session Statistics</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
@if (sessionSummary != null)
|
|
{
|
|
<dl class="row">
|
|
<dt class="col-sm-6">Active Sessions:</dt>
|
|
<dd class="col-sm-6">@sessionSummary.ActiveSessions</dd>
|
|
|
|
<dt class="col-sm-6">Completed Sessions:</dt>
|
|
<dd class="col-sm-6">@sessionSummary.CompletedSessions</dd>
|
|
|
|
<dt class="col-sm-6">Avg Session Duration:</dt>
|
|
<dd class="col-sm-6">@sessionSummary.AverageSessionDuration.ToString("F1") min</dd>
|
|
|
|
<dt class="col-sm-6">Avg Orders/Session:</dt>
|
|
<dd class="col-sm-6">@sessionSummary.AverageOrdersPerSession.ToString("F2")</dd>
|
|
|
|
<dt class="col-sm-6">Avg Spend/Session:</dt>
|
|
<dd class="col-sm-6">$@sessionSummary.AverageSpendPerSession.ToString("F2")</dd>
|
|
</dl>
|
|
}
|
|
else
|
|
{
|
|
<p class="text-muted">No session data available</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (Model.MetricsByType.Any())
|
|
{
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Metrics by Type</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Metric Type</th>
|
|
<th>Total Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var metric in Model.MetricsByType.OrderByDescending(m => m.Value))
|
|
{
|
|
<tr>
|
|
<td>@metric.Key</td>
|
|
<td>@metric.Value.ToString("F0")</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (sessionSummary != null)
|
|
{
|
|
<div class="row">
|
|
@if (sessionSummary.SessionsByPlatform.Any())
|
|
{
|
|
<div class="col-md-4">
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Sessions by Platform</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-unstyled">
|
|
@foreach (var platform in sessionSummary.SessionsByPlatform)
|
|
{
|
|
<li>@platform.Key: <strong>@platform.Value</strong></li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (sessionSummary.SessionsByCountry.Any())
|
|
{
|
|
<div class="col-md-4">
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Sessions by Country</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-unstyled">
|
|
@foreach (var country in sessionSummary.SessionsByCountry.Take(5))
|
|
{
|
|
<li>@country.Key: <strong>@country.Value</strong></li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (sessionSummary.SessionsByLanguage.Any())
|
|
{
|
|
<div class="col-md-4">
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Sessions by Language</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-unstyled">
|
|
@foreach (var language in sessionSummary.SessionsByLanguage)
|
|
{
|
|
<li>@language.Key: <strong>@language.Value</strong></li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
@if (Model.TimeSeries.Any())
|
|
{
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Activity Timeline</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="metricsChart"></canvas>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<div class="mt-3">
|
|
<a asp-action="Details" asp-route-id="@Model.BotId" class="btn btn-secondary">Back to Details</a>
|
|
<a asp-action="Index" class="btn btn-secondary">Back to List</a>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
@if (Model.TimeSeries.Any())
|
|
{
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
const ctx = document.getElementById('metricsChart').getContext('2d');
|
|
const chart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: [@Html.Raw(string.Join(",", Model.TimeSeries.Select(t => $"'{t.Label}'")))],
|
|
datasets: [{
|
|
label: 'Activity',
|
|
data: [@string.Join(",", Model.TimeSeries.Select(t => t.Value))],
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
}
|
|
} |