Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6af9f2db7 | ||
|
|
364c1b455d | ||
|
|
d00e087b35 | ||
|
|
289992ce5e |
@@ -17,6 +17,24 @@ namespace WorkFlowCheck.API.Controllers
|
||||
_checkListService = checkListService;
|
||||
}
|
||||
|
||||
[HttpGet("GetDashboardInfo")]
|
||||
public async Task<ApiResponseDTO<DashboardDTO>> GetDashboardInfo()
|
||||
{
|
||||
var retVal = new ApiResponseDTO<DashboardDTO>();
|
||||
try
|
||||
{
|
||||
retVal.Data = await _checkListService.GetDashboardInfoAsync();
|
||||
retVal.IsSuccess = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
retVal.IsSuccess = false;
|
||||
retVal.Errors.Add("A műszerfal adatainak lekérése sikertelen.");
|
||||
Log.Error(ex, "GetDashboardInfo failed");
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
[HttpGet("GetCheckListHeader/{id}")]
|
||||
public async Task<ApiResponseDTO<CheckListHeaderDTO>> GetCheckListHeader(int id)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ using WorkFlowCheck.BL.Services.Interfaces;
|
||||
using WorkFlowCheck.Common.DataTables;
|
||||
using WorkFlowCheck.Common.DTO;
|
||||
using WorkFlowCheck.Common.Enums;
|
||||
using WorkFlowCheck.Common.Helper;
|
||||
using WorkFlowCheck.DL;
|
||||
using WorkFlowCheck.DL.Entities;
|
||||
|
||||
@@ -39,6 +40,171 @@ namespace WorkFlowCheck.BL.Services
|
||||
_messageService = messageService;
|
||||
}
|
||||
|
||||
public async Task<DashboardDTO> GetDashboardInfoAsync()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var currentMonthStart = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
var nextMonthStart = currentMonthStart.AddMonths(1);
|
||||
var previousMonthStart = currentMonthStart.AddMonths(-1);
|
||||
var sixMonthStart = currentMonthStart.AddMonths(-5);
|
||||
var fortyEightHoursAgo = now.AddHours(-48);
|
||||
|
||||
var headers = _dbContext.CheckListHeaders.AsNoTracking();
|
||||
|
||||
var statusCounts = await headers
|
||||
.GroupBy(x => x.CheckStatus)
|
||||
.Select(x => new { Status = x.Key, Count = x.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var monthlyRaw = await headers
|
||||
.Where(x => x.CreatedAt >= sixMonthStart && x.CreatedAt < nextMonthStart)
|
||||
.GroupBy(x => new { x.CreatedAt.Year, x.CreatedAt.Month })
|
||||
.Select(x => new
|
||||
{
|
||||
x.Key.Year,
|
||||
x.Key.Month,
|
||||
Total = x.Count(),
|
||||
Approved = x.Count(y => y.CheckStatus == CheckStatus.Signed || y.CheckStatus == CheckStatus.Closed)
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var topUsers = await headers
|
||||
.Where(x => x.CreatedAt >= currentMonthStart && x.CreatedAt < nextMonthStart)
|
||||
.GroupBy(x => new { x.UserId, x.User.LastName, x.User.FirstName })
|
||||
.Select(x => new DashboardUserItemDTO
|
||||
{
|
||||
Name = (x.Key.LastName + " " + x.Key.FirstName).Trim(),
|
||||
Count = x.Count()
|
||||
})
|
||||
.OrderByDescending(x => x.Count)
|
||||
.ThenBy(x => x.Name)
|
||||
.Take(5)
|
||||
.ToListAsync();
|
||||
|
||||
var recentItems = await headers
|
||||
.OrderByDescending(x => x.LastModAt)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.DocumentNumber,
|
||||
x.ShortName,
|
||||
x.User.LastName,
|
||||
x.User.FirstName,
|
||||
x.LastModAt,
|
||||
x.CheckStatus
|
||||
})
|
||||
.Take(8)
|
||||
.ToListAsync();
|
||||
|
||||
var delayedApprovalCount = await headers.CountAsync(x =>
|
||||
x.CheckStatus == CheckStatus.Sent && x.LastModAt < fortyEightHoursAgo);
|
||||
|
||||
var blockedCount = statusCounts.FirstOrDefault(x => x.Status == CheckStatus.Blocked)?.Count ?? 0;
|
||||
var currentMonthCount = monthlyRaw
|
||||
.FirstOrDefault(x => x.Year == currentMonthStart.Year && x.Month == currentMonthStart.Month)?.Total ?? 0;
|
||||
var previousMonthCount = monthlyRaw
|
||||
.FirstOrDefault(x => x.Year == previousMonthStart.Year && x.Month == previousMonthStart.Month)?.Total ?? 0;
|
||||
var approvedThisMonth = monthlyRaw
|
||||
.FirstOrDefault(x => x.Year == currentMonthStart.Year && x.Month == currentMonthStart.Month)?.Approved ?? 0;
|
||||
|
||||
var culture = System.Globalization.CultureInfo.GetCultureInfo("hu-HU");
|
||||
var result = new DashboardDTO
|
||||
{
|
||||
GeneratedAt = now,
|
||||
TotalCheckLists = statusCounts.Sum(x => x.Count),
|
||||
CheckListsThisMonth = currentMonthCount,
|
||||
MonthlyChangePercent = previousMonthCount == 0
|
||||
? (currentMonthCount > 0 ? 100 : 0)
|
||||
: Math.Round((currentMonthCount - previousMonthCount) * 100m / previousMonthCount, 1),
|
||||
OpenAndInProgressCount = statusCounts
|
||||
.Where(x => x.Status == CheckStatus.Open || x.Status == CheckStatus.InProgress)
|
||||
.Sum(x => x.Count),
|
||||
AwaitingApprovalCount = statusCounts.FirstOrDefault(x => x.Status == CheckStatus.Sent)?.Count ?? 0,
|
||||
BlockedCount = blockedCount,
|
||||
ApprovedThisMonthCount = approvedThisMonth,
|
||||
ApprovalRate = currentMonthCount == 0 ? 0 : Math.Round(approvedThisMonth * 100m / currentMonthCount, 1),
|
||||
ActiveUserCount = await _dbContext.Users.AsNoTracking().CountAsync(x => x.Active),
|
||||
TemplateCount = await _dbContext.CheckListTemplateHeaders.AsNoTracking().CountAsync(),
|
||||
TopUsers = topUsers,
|
||||
AttentionItems = new List<DashboardAttentionItemDTO>(),
|
||||
RecentCheckLists = recentItems.Select(x => new DashboardRecentCheckListDTO
|
||||
{
|
||||
Id = x.Id,
|
||||
DocumentNumber = x.DocumentNumber,
|
||||
ShortName = x.ShortName,
|
||||
Responsible = (x.LastName + " " + x.FirstName).Trim(),
|
||||
ModifiedAt = x.LastModAt,
|
||||
Status = x.CheckStatus,
|
||||
StatusName = DisplayNameHelper.GetEnumDisplayName(x.CheckStatus)
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
var month = sixMonthStart.AddMonths(i);
|
||||
var value = monthlyRaw.FirstOrDefault(x => x.Year == month.Year && x.Month == month.Month);
|
||||
result.MonthlyItems.Add(new DashboardMonthlyItemDTO
|
||||
{
|
||||
Month = month.ToString("MMM", culture).TrimEnd('.'),
|
||||
Total = value?.Total ?? 0,
|
||||
Approved = value?.Approved ?? 0
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var status in Enum.GetValues<CheckStatus>())
|
||||
{
|
||||
result.StatusItems.Add(new DashboardStatusItemDTO
|
||||
{
|
||||
Status = status,
|
||||
Name = DisplayNameHelper.GetEnumDisplayName(status),
|
||||
Count = statusCounts.FirstOrDefault(x => x.Status == status)?.Count ?? 0,
|
||||
Color = GetDashboardStatusColor(status)
|
||||
});
|
||||
}
|
||||
|
||||
if (delayedApprovalCount > 0)
|
||||
{
|
||||
result.AttentionItems.Add(new DashboardAttentionItemDTO
|
||||
{
|
||||
Title = $"{delayedApprovalCount} munkalap több mint 48 órája jóváhagyásra vár",
|
||||
Description = "Érdemes ellenőrizni a beküldött munkalapokat.",
|
||||
IsCritical = true
|
||||
});
|
||||
}
|
||||
if (blockedCount > 0)
|
||||
{
|
||||
result.AttentionItems.Add(new DashboardAttentionItemDTO
|
||||
{
|
||||
Title = $"{blockedCount} blokkolt munkalap",
|
||||
Description = "A folytatásuk felhasználói beavatkozást igényel.",
|
||||
IsCritical = true
|
||||
});
|
||||
}
|
||||
if (result.AwaitingApprovalCount > delayedApprovalCount)
|
||||
{
|
||||
result.AttentionItems.Add(new DashboardAttentionItemDTO
|
||||
{
|
||||
Title = $"{result.AwaitingApprovalCount - delayedApprovalCount} friss beküldött munkalap",
|
||||
Description = "Jóváhagyásra váró, 48 óránál frissebb tételek.",
|
||||
IsCritical = false
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetDashboardStatusColor(CheckStatus status) => status switch
|
||||
{
|
||||
CheckStatus.Open => "#64748b",
|
||||
CheckStatus.InProgress => "#e28a17",
|
||||
CheckStatus.Blocked => "#dc2626",
|
||||
CheckStatus.Storno => "#7c3aed",
|
||||
CheckStatus.Sent => "#38bdf8",
|
||||
CheckStatus.Signed => "#16875b",
|
||||
CheckStatus.Closed => "#123c69",
|
||||
_ => "#94a3b8"
|
||||
};
|
||||
|
||||
public async Task<CheckListHeaderDTO> GetCheckListHeaderAsync(int Id)
|
||||
{
|
||||
var retVal = new CheckListHeaderDTO()
|
||||
|
||||
@@ -4,9 +4,10 @@ using WorkFlowCheck.Common.DTO;
|
||||
|
||||
namespace WorkFlowCheck.BL.Services.Interfaces
|
||||
{
|
||||
public interface ICheckListService
|
||||
{
|
||||
Task<CheckListHeaderDTO> GetCheckListHeaderAsync(int Id);
|
||||
public interface ICheckListService
|
||||
{
|
||||
Task<DashboardDTO> GetDashboardInfoAsync();
|
||||
Task<CheckListHeaderDTO> GetCheckListHeaderAsync(int Id);
|
||||
Task<ApiResponseListDTO<List<CheckListHeaderDTO>>> GetFilteredCheckListHeaderAsync(DataTablesRequest dataTablesRequest);
|
||||
Task<List<CheckListHeaderDTO>> GetAllCheckListHeaderAsync(int mode = 0);
|
||||
Task<CheckListHeaderDTO> UpdateCheckListHeaderAsync(CheckListHeaderDTO checkListHeaderDTO);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using WorkFlowCheck.Common.Enums;
|
||||
|
||||
namespace WorkFlowCheck.Common.DTO
|
||||
{
|
||||
public class DashboardDTO
|
||||
{
|
||||
public DateTime GeneratedAt { get; set; }
|
||||
public int TotalCheckLists { get; set; }
|
||||
public int CheckListsThisMonth { get; set; }
|
||||
public decimal MonthlyChangePercent { get; set; }
|
||||
public int OpenAndInProgressCount { get; set; }
|
||||
public int AwaitingApprovalCount { get; set; }
|
||||
public int BlockedCount { get; set; }
|
||||
public int ApprovedThisMonthCount { get; set; }
|
||||
public decimal ApprovalRate { get; set; }
|
||||
public int ActiveUserCount { get; set; }
|
||||
public int TemplateCount { get; set; }
|
||||
public List<DashboardMonthlyItemDTO> MonthlyItems { get; set; } = new();
|
||||
public List<DashboardStatusItemDTO> StatusItems { get; set; } = new();
|
||||
public List<DashboardUserItemDTO> TopUsers { get; set; } = new();
|
||||
public List<DashboardAttentionItemDTO> AttentionItems { get; set; } = new();
|
||||
public List<DashboardRecentCheckListDTO> RecentCheckLists { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DashboardMonthlyItemDTO
|
||||
{
|
||||
public string Month { get; set; } = string.Empty;
|
||||
public int Total { get; set; }
|
||||
public int Approved { get; set; }
|
||||
}
|
||||
|
||||
public class DashboardStatusItemDTO
|
||||
{
|
||||
public CheckStatus Status { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int Count { get; set; }
|
||||
public string Color { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class DashboardUserItemDTO
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int Count { get; set; }
|
||||
}
|
||||
|
||||
public class DashboardAttentionItemDTO
|
||||
{
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public bool IsCritical { get; set; }
|
||||
}
|
||||
|
||||
public class DashboardRecentCheckListDTO
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string DocumentNumber { get; set; } = string.Empty;
|
||||
public string ShortName { get; set; } = string.Empty;
|
||||
public string Responsible { get; set; } = string.Empty;
|
||||
public DateTime ModifiedAt { get; set; }
|
||||
public CheckStatus Status { get; set; }
|
||||
public string StatusName { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,16 @@ namespace WorkFlowCheck.Web.Middleware
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var pathignore = context.Request.Path;
|
||||
if (pathignore.StartsWithSegments("/css") ||
|
||||
pathignore.StartsWithSegments("/js") ||
|
||||
pathignore.StartsWithSegments("/lib") ||
|
||||
pathignore.StartsWithSegments("/images") ||
|
||||
pathignore.StartsWithSegments("/favicon.ico"))
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
var token = context.Request.Cookies["AuthToken"];
|
||||
|
||||
if (!string.IsNullOrEmpty(token) && ValidateToken(token, out var claims))
|
||||
|
||||
@@ -27,16 +27,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckPointDTO.IsEnabled), typeof(CheckPointDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckPointDTO.ShortName), typeof(CheckPointDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckPointDTO.Code), typeof(CheckPointDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckPointDTO.RoleName), typeof(CheckPointDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -22,14 +22,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(EquipmentDTO.ShortName), typeof(EquipmentDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(EquipmentDTO.EquipmentNumber), typeof(EquipmentDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,13 +21,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(LocationDTO.FullName), typeof(LocationDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,15 +18,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.FileName), typeof(ImageFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.FileSize), typeof(ImageFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.CreateDate), typeof(ImageFileDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,15 +18,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.FileName), typeof(ImageFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.FileSize), typeof(ImageFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(ImageFileDTO.CreateDate), typeof(ImageFileDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,15 +18,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(PDFFileDTO.FileName), typeof(PDFFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(PDFFileDTO.FileSize), typeof(PDFFileDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(PDFFileDTO.CreateDate), typeof(PDFFileDTO))</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -37,20 +37,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.CheckStatus), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.IsEditable), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.DocumentNumber), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.DateExecution), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.ShortName), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.Description), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.UserId), typeof(CheckListHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListHeaderDTO.AcceptUserId), typeof(CheckListHeaderDTO))</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
-8
@@ -23,14 +23,6 @@
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListTemplateHeaderDTO.ShortName), typeof(CheckListTemplateHeaderDTO))</th>
|
||||
<th>@DisplayNameHelper.GetDisplayName(nameof(CheckListTemplateHeaderDTO.Description), typeof(CheckListTemplateHeaderDTO))</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
.status-badge { display:inline-flex; align-items:center; gap:.3rem; padding:.3rem .52rem; border-radius:999px; font-size:.7rem; font-weight:720; white-space:nowrap; }
|
||||
.status-approved { color:#0d6b47; background:#dcf5e9; } .status-submitted { color:#075985; background:#e0f2fe; }
|
||||
.status-progress { color:#945500; background:#fff1d2; } .status-closed { color:#475569; background:#e9eef4; }
|
||||
.status-blocked { color:#991b1b; background:#fee2e2; } .status-storno { color:#6d28d9; background:#ede9fe; }
|
||||
@@media(max-width:1199.98px){.kpi-grid{grid-template-columns:repeat(2,minmax(0,1fr));}}
|
||||
@@media(max-width:991.98px){.dashboard-grid,.dashboard-grid.equal{grid-template-columns:1fr;}}
|
||||
@@media(max-width:575.98px){.dashboard-heading{align-items:stretch;flex-direction:column}.demo-badge{align-self:flex-start}.kpi-grid{grid-template-columns:1fr}.chart-container{height:245px}.dashboard-card-header{align-items:flex-start;flex-direction:column}.dashboard-table{min-width:720px}}
|
||||
@@ -54,15 +55,15 @@
|
||||
|
||||
<div class="dashboard-page">
|
||||
<div class="dashboard-heading">
|
||||
<div><h1>Gyártási ellenőrzések áttekintése</h1><p>@Model.PeriodLabel · Frissítve: @Model.GeneratedAt.ToString("yyyy. MM. dd. HH:mm")</p></div>
|
||||
<span class="demo-badge"><i class="bi bi-stars"></i> Mintaadatokkal</span>
|
||||
<div><h1>Ellenőrzések áttekintése</h1><p>@Model.PeriodLabel · Frissítve: @Model.Dashboard.GeneratedAt.ToLocalTime().ToString("yyyy. MM. dd. HH:mm")</p></div>
|
||||
<span class="demo-badge"><i class="bi bi-database-check"></i> Élő adatok</span>
|
||||
</div>
|
||||
|
||||
<section class="kpi-grid" aria-label="Fő mutatók">
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-clipboard2-check"></i></span><span class="kpi-trend"><i class="bi bi-arrow-up-right"></i> @Model.MonthlyChangePercent.ToString("0.0")%</span></div><div class="kpi-value">@Model.InspectionsThisMonth</div><div class="kpi-label">Ellenőrzés ebben a hónapban</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-hourglass-split"></i></span><span class="kpi-trend warning">@Model.AwaitingApproval jóváhagyásra vár</span></div><div class="kpi-value">@Model.InProgress</div><div class="kpi-label">Folyamatban lévő ellenőrzés</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-patch-check"></i></span><span class="kpi-trend">@Model.ApprovalRate.ToString("0.0")% arány</span></div><div class="kpi-value">@Model.ApprovedThisMonth</div><div class="kpi-label">Jóváhagyás ebben a hónapban</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-stopwatch"></i></span><span class="kpi-trend neutral">átlagos idő</span></div><div class="kpi-value">@Model.AverageDurationMinutes.ToString("0.0") <small>perc</small></div><div class="kpi-label">Egy ellenőrzés végrehajtása</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-clipboard2-check"></i></span><span class="kpi-trend @((Model.Dashboard.MonthlyChangePercent < 0) ? "warning" : "")"><i class="bi @(Model.Dashboard.MonthlyChangePercent < 0 ? "bi-arrow-down-right" : "bi-arrow-up-right")"></i> @Model.Dashboard.MonthlyChangePercent.ToString("0.0")%</span></div><div class="kpi-value">@Model.Dashboard.CheckListsThisMonth.ToString("N0")</div><div class="kpi-label">Ellenőrzés ebben a hónapban</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-hourglass-split"></i></span><span class="kpi-trend warning">@Model.Dashboard.AwaitingApprovalCount jóváhagyásra vár</span></div><div class="kpi-value">@Model.Dashboard.OpenAndInProgressCount.ToString("N0")</div><div class="kpi-label">Nyitott vagy folyamatban</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-patch-check"></i></span><span class="kpi-trend">@Model.Dashboard.ApprovalRate.ToString("0.0")% arány</span></div><div class="kpi-value">@Model.Dashboard.ApprovedThisMonthCount.ToString("N0")</div><div class="kpi-label">Jóváhagyás ebben a hónapban</div></article>
|
||||
<article class="kpi-card"><div class="kpi-topline"><span class="kpi-icon"><i class="bi bi-slash-circle"></i></span><span class="kpi-trend neutral">összesen @Model.Dashboard.TotalCheckLists.ToString("N0")</span></div><div class="kpi-value">@Model.Dashboard.BlockedCount.ToString("N0")</div><div class="kpi-label">Blokkolt munkalap</div></article>
|
||||
</section>
|
||||
|
||||
<section class="dashboard-grid">
|
||||
@@ -71,26 +72,26 @@
|
||||
<div class="dashboard-card-body"><div class="chart-container"><canvas id="monthlyInspectionsChart"></canvas></div></div>
|
||||
</article>
|
||||
<article class="dashboard-card">
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Aktuális állapotok</h2><p class="dashboard-card-subtitle">Az e havi ellenőrzések megoszlása</p></div></header>
|
||||
<div class="dashboard-card-body"><div class="chart-container compact"><canvas id="statusChart"></canvas></div><div class="status-summary">@foreach(var status in Model.Statuses){<div class="status-item"><span class="status-dot" style="background:@status.Color"></span><span>@status.Name</span><strong>@status.Count</strong></div>}</div></div>
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Aktuális állapotok</h2><p class="dashboard-card-subtitle">Az összes ellenőrzés jelenlegi megoszlása</p></div></header>
|
||||
<div class="dashboard-card-body"><div class="chart-container compact"><canvas id="statusChart"></canvas></div><div class="status-summary">@foreach(var status in Model.Dashboard.StatusItems){<div class="status-item"><span class="status-dot" style="background:@status.Color"></span><span>@status.Name</span><strong>@status.Count</strong></div>}</div></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="dashboard-grid equal">
|
||||
<article class="dashboard-card">
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Jóváhagyások személyenként</h2><p class="dashboard-card-subtitle">Aktuális hónap · jóváhagyott ellenőrzések száma</p></div></header>
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Ellenőrzések személyenként</h2><p class="dashboard-card-subtitle">Aktuális hónap · elindított ellenőrzések száma</p></div></header>
|
||||
<div class="dashboard-card-body"><div class="chart-container compact"><canvas id="approversChart"></canvas></div></div>
|
||||
</article>
|
||||
<article class="dashboard-card">
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Figyelmet igényel</h2><p class="dashboard-card-subtitle">Elakadt vagy határidős tételek</p></div><span class="badge rounded-pill text-bg-danger">@Model.AttentionItems.Count</span></header>
|
||||
<div class="dashboard-card-body"><div class="attention-list">@foreach(var item in Model.AttentionItems){<div class="attention-item @(item.IsCritical ? "danger" : "")"><span class="attention-icon"><i class="bi @(item.IsCritical ? "bi-exclamation-triangle" : "bi-clock-history")"></i></span><div><div class="attention-title">@item.Title</div><div class="attention-meta">@item.Description</div></div></div>}</div></div>
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Figyelmet igényel</h2><p class="dashboard-card-subtitle">Elakadt vagy jóváhagyásra váró tételek</p></div><span class="badge rounded-pill text-bg-danger">@Model.Dashboard.AttentionItems.Count</span></header>
|
||||
<div class="dashboard-card-body"><div class="attention-list">@if(Model.Dashboard.AttentionItems.Count == 0){<div class="attention-item"><span class="attention-icon"><i class="bi bi-check2-circle"></i></span><div><div class="attention-title">Nincs figyelmet igénylő tétel</div><div class="attention-meta">Minden munkalap rendben halad.</div></div></div>}else{@foreach(var item in Model.Dashboard.AttentionItems){<div class="attention-item @(item.IsCritical ? "danger" : "")"><span class="attention-icon"><i class="bi @(item.IsCritical ? "bi-exclamation-triangle" : "bi-clock-history")"></i></span><div><div class="attention-title">@item.Title</div><div class="attention-meta">@item.Description</div></div></div>}}</div></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="dashboard-card">
|
||||
<header class="dashboard-card-header"><div><h2 class="dashboard-card-title">Legutóbbi ellenőrzések</h2><p class="dashboard-card-subtitle">A rendszerben legutóbb módosított tételek</p></div><a asp-page="/CheckList/CheckListHeader/CheckListHeaderPage" asp-route-mode="4" class="btn btn-sm btn-outline-primary">Összes megtekintése <i class="bi bi-arrow-right ms-1"></i></a></header>
|
||||
<div class="table-responsive"><table class="table dashboard-table"><thead><tr><th>Azonosító</th><th>Ellenőrzés</th><th>Lokáció</th><th>Felelős</th><th>Módosítva</th><th>Állapot</th></tr></thead><tbody>
|
||||
@foreach(var item in Model.RecentInspections){<tr><td><span class="inspection-code">@item.Code</span></td><td>@item.Name</td><td>@item.Location</td><td>@item.Responsible</td><td>@item.ModifiedAt.ToString("yyyy. MM. dd. HH:mm")</td><td><span class="status-badge @item.StatusCss"><i class="bi @item.StatusIcon"></i>@item.Status</span></td></tr>}
|
||||
<div class="table-responsive"><table class="table dashboard-table"><thead><tr><th>Azonosító</th><th>Ellenőrzés</th><th>Felelős</th><th>Módosítva</th><th>Állapot</th></tr></thead><tbody>
|
||||
@if(Model.Dashboard.RecentCheckLists.Count == 0){<tr><td colspan="5" class="text-center py-4 text-muted">Még nincs megjeleníthető ellenőrzés.</td></tr>}else{@foreach(var item in Model.Dashboard.RecentCheckLists){<tr><td><span class="inspection-code">@item.DocumentNumber</span></td><td>@item.ShortName</td><td>@item.Responsible</td><td>@item.ModifiedAt.ToLocalTime().ToString("yyyy. MM. dd. HH:mm")</td><td><span class="status-badge @IndexModel.GetStatusCss(item.Status)"><i class="bi @IndexModel.GetStatusIcon(item.Status)"></i>@item.StatusName</span></td></tr>}}
|
||||
</tbody></table></div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -99,14 +100,14 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
(() => {
|
||||
const monthly = @Html.Raw(JsonSerializer.Serialize(Model.MonthlyInspections, jsonOptions));
|
||||
const statuses = @Html.Raw(JsonSerializer.Serialize(Model.Statuses, jsonOptions));
|
||||
const approvers = @Html.Raw(JsonSerializer.Serialize(Model.Approvers, jsonOptions));
|
||||
const monthly = @Html.Raw(JsonSerializer.Serialize(Model.Dashboard.MonthlyItems, jsonOptions));
|
||||
const statuses = @Html.Raw(JsonSerializer.Serialize(Model.Dashboard.StatusItems, jsonOptions));
|
||||
const approvers = @Html.Raw(JsonSerializer.Serialize(Model.Dashboard.TopUsers, jsonOptions));
|
||||
const gridColor = 'rgba(100,116,139,.14)';
|
||||
Chart.defaults.font.family = 'Inter, "Segoe UI", Arial, sans-serif'; Chart.defaults.color = '#64748b';
|
||||
new Chart(document.getElementById('monthlyInspectionsChart'),{type:'line',data:{labels:monthly.map(x=>x.month),datasets:[{label:'Összes ellenőrzés',data:monthly.map(x=>x.total),borderColor:'#123c69',backgroundColor:'rgba(56,189,248,.13)',borderWidth:3,pointBackgroundColor:'#123c69',pointRadius:4,fill:true,tension:.36},{label:'Jóváhagyott',data:monthly.map(x=>x.approved),borderColor:'#38bdf8',backgroundColor:'#38bdf8',borderWidth:2,pointRadius:3,borderDash:[6,4],tension:.36}]},options:{responsive:true,maintainAspectRatio:false,interaction:{mode:'index',intersect:false},plugins:{legend:{position:'bottom',labels:{usePointStyle:true,boxWidth:8,padding:18}}},scales:{x:{grid:{display:false}},y:{beginAtZero:true,grid:{color:gridColor},ticks:{precision:0}}}}});
|
||||
new Chart(document.getElementById('statusChart'),{type:'doughnut',data:{labels:statuses.map(x=>x.name),datasets:[{data:statuses.map(x=>x.count),backgroundColor:statuses.map(x=>x.color),borderColor:'#fff',borderWidth:4,hoverOffset:5}]},options:{responsive:true,maintainAspectRatio:false,cutout:'68%',plugins:{legend:{display:false}}}});
|
||||
new Chart(document.getElementById('approversChart'),{type:'bar',data:{labels:approvers.map(x=>x.name),datasets:[{label:'Jóváhagyás',data:approvers.map(x=>x.count),backgroundColor:['#123c69','#1c5c91','#2687bd','#38bdf8','#7dd3fc'],borderRadius:7,borderSkipped:false,barThickness:24}]},options:{indexAxis:'y',responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},scales:{x:{beginAtZero:true,grid:{color:gridColor},ticks:{precision:0}},y:{grid:{display:false}}}}});
|
||||
new Chart(document.getElementById('approversChart'),{type:'bar',data:{labels:approvers.map(x=>x.name),datasets:[{label:'Ellenőrzés',data:approvers.map(x=>x.count),backgroundColor:['#123c69','#1c5c91','#2687bd','#38bdf8','#7dd3fc'],borderRadius:7,borderSkipped:false,barThickness:24}]},options:{indexAxis:'y',responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},scales:{x:{beginAtZero:true,grid:{color:gridColor},ticks:{precision:0}},y:{grid:{display:false}}}}});
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -1,76 +1,57 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.Globalization;
|
||||
using WorkFlowCheck.Common.DTO;
|
||||
using WorkFlowCheck.Common.Enums;
|
||||
using WorkFlowCheck.Web.Services.Interfaces;
|
||||
|
||||
namespace WorkFlowCheck.Web.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly ICheckListService _checkListService;
|
||||
private readonly ILogger<IndexModel> _logger;
|
||||
|
||||
public DateTime GeneratedAt { get; private set; }
|
||||
public string PeriodLabel { get; private set; } = string.Empty;
|
||||
public int InspectionsThisMonth { get; private set; }
|
||||
public decimal MonthlyChangePercent { get; private set; }
|
||||
public int InProgress { get; private set; }
|
||||
public int AwaitingApproval { get; private set; }
|
||||
public int ApprovedThisMonth { get; private set; }
|
||||
public decimal ApprovalRate { get; private set; }
|
||||
public decimal AverageDurationMinutes { get; private set; }
|
||||
public List<MonthlyInspectionPoint> MonthlyInspections { get; private set; } = [];
|
||||
public List<DashboardStatus> Statuses { get; private set; } = [];
|
||||
public List<ApproverStatistic> Approvers { get; private set; } = [];
|
||||
public List<AttentionItem> AttentionItems { get; private set; } = [];
|
||||
public List<RecentInspection> RecentInspections { get; private set; } = [];
|
||||
public DashboardDTO Dashboard { get; private set; } = new();
|
||||
public string PeriodLabel => Dashboard.GeneratedAt.ToLocalTime()
|
||||
.ToString("yyyy. MMMM", CultureInfo.GetCultureInfo("hu-HU"));
|
||||
|
||||
public IndexModel(ILogger<IndexModel> logger) => _logger = logger;
|
||||
|
||||
public void OnGet()
|
||||
public IndexModel(ICheckListService checkListService, ILogger<IndexModel> logger)
|
||||
{
|
||||
// TODO: A következő körben ezt az egy blokkot cseréljük IDashboardService hívásra.
|
||||
LoadDemoData();
|
||||
_checkListService = checkListService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private void LoadDemoData()
|
||||
public async Task OnGetAsync()
|
||||
{
|
||||
GeneratedAt = DateTime.Now;
|
||||
PeriodLabel = GeneratedAt.ToString("yyyy. MMMM", CultureInfo.GetCultureInfo("hu-HU"));
|
||||
InspectionsThisMonth = 128;
|
||||
MonthlyChangePercent = 18.5m;
|
||||
InProgress = 17;
|
||||
AwaitingApproval = 9;
|
||||
ApprovedThisMonth = 96;
|
||||
ApprovalRate = 75.0m;
|
||||
AverageDurationMinutes = 14.2m;
|
||||
|
||||
var totals = new[] { 76, 89, 84, 105, 112, 128 };
|
||||
var approved = new[] { 55, 63, 61, 79, 86, 96 };
|
||||
var firstMonth = new DateTime(GeneratedAt.Year, GeneratedAt.Month, 1).AddMonths(-5);
|
||||
var culture = CultureInfo.GetCultureInfo("hu-HU");
|
||||
MonthlyInspections = Enumerable.Range(0, 6).Select(i => new MonthlyInspectionPoint(firstMonth.AddMonths(i).ToString("MMM", culture).TrimEnd('.'), totals[i], approved[i])).ToList();
|
||||
|
||||
Statuses = [new("Jóváhagyott",96,"#16875b"),new("Beküldött",9,"#38bdf8"),new("Folyamatban",17,"#e28a17"),new("Lezárt",6,"#94a3b8")];
|
||||
Approvers = [new("Kovács Péter",28),new("Nagy Anna",24),new("Tóth Gábor",19),new("Szabó Éva",15),new("Varga Tamás",10)];
|
||||
AttentionItems =
|
||||
[
|
||||
new("3 ellenőrzés több mint 48 órája beküldve", "Jóváhagyásra várnak a C2 gyártócsarnokban.", true),
|
||||
new("Kalibrálás hamarosan lejár", "A CNC–04 berendezés következő határideje 3 nap.", false),
|
||||
new("Hiányzó fényképes dokumentáció", "2 folyamatban lévő ellenőrzésnél nincs csatolmány.", true),
|
||||
new("Heti ellenőrzési terv", "A tervezett 34 ellenőrzésből még 7 nem kezdődött el.", false)
|
||||
];
|
||||
RecentInspections =
|
||||
[
|
||||
new("WFC-260912-018","Műszakindító gépellenőrzés","C2 gyártócsarnok","Kiss Dániel",GeneratedAt.AddMinutes(-18),"Jóváhagyott","status-approved","bi-check-circle"),
|
||||
new("WFC-260912-017","Hegesztőcella biztonsági ellenőrzés","A1 csarnok","Farkas András",GeneratedAt.AddMinutes(-42),"Beküldött","status-submitted","bi-send-check"),
|
||||
new("WFC-260912-016","Csomagolósor minőségellenőrzés","B3 csomagoló","Molnár Rita",GeneratedAt.AddHours(-1.4),"Folyamatban","status-progress","bi-hourglass-split"),
|
||||
new("WFC-260912-015","Napi karbantartási ellenőrzés","CNC terület","Kiss Dániel",GeneratedAt.AddHours(-2.1),"Lezárt","status-closed","bi-lock"),
|
||||
new("WFC-260912-014","Beérkező alapanyag vizsgálata","Központi raktár","Nagy Júlia",GeneratedAt.AddHours(-3.3),"Jóváhagyott","status-approved","bi-check-circle")
|
||||
];
|
||||
try
|
||||
{
|
||||
Dashboard = await _checkListService.GetDashboardInfoAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "A műszerfal betöltése sikertelen.");
|
||||
Dashboard = new DashboardDTO { GeneratedAt = DateTime.UtcNow };
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record MonthlyInspectionPoint(string Month, int Total, int Approved);
|
||||
public sealed record DashboardStatus(string Name, int Count, string Color);
|
||||
public sealed record ApproverStatistic(string Name, int Count);
|
||||
public sealed record AttentionItem(string Title, string Description, bool IsCritical);
|
||||
public sealed record RecentInspection(string Code, string Name, string Location, string Responsible, DateTime ModifiedAt, string Status, string StatusCss, string StatusIcon);
|
||||
public static string GetStatusCss(CheckStatus status) => status switch
|
||||
{
|
||||
CheckStatus.Signed => "status-approved",
|
||||
CheckStatus.Sent => "status-submitted",
|
||||
CheckStatus.Open or CheckStatus.InProgress => "status-progress",
|
||||
CheckStatus.Blocked => "status-blocked",
|
||||
CheckStatus.Storno => "status-storno",
|
||||
_ => "status-closed"
|
||||
};
|
||||
|
||||
public static string GetStatusIcon(CheckStatus status) => status switch
|
||||
{
|
||||
CheckStatus.Signed => "bi-check-circle",
|
||||
CheckStatus.Sent => "bi-send-check",
|
||||
CheckStatus.Blocked => "bi-slash-circle",
|
||||
CheckStatus.Storno => "bi-x-circle",
|
||||
CheckStatus.Closed => "bi-lock",
|
||||
_ => "bi-hourglass-split"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,23 @@ namespace WorkFlowCheck.Web.Services
|
||||
public CheckListService(HttpClient httpClient, IConfiguration configuration, IHttpContextAccessor httpContextAccessor) : base(httpClient, configuration, httpContextAccessor)
|
||||
{
|
||||
}
|
||||
public async Task<DashboardDTO> GetDashboardInfoAsync()
|
||||
{
|
||||
var endpoint = $"{_httpClient.BaseAddress}api/CheckList/GetDashboardInfo";
|
||||
try
|
||||
{
|
||||
var response = await _httpClient.GetFromJsonAsync<ApiResponseDTO<DashboardDTO>>(endpoint);
|
||||
if (response?.IsSuccess == true && response.Data != null)
|
||||
{
|
||||
return response.Data;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetDashboardInfoAsync failed");
|
||||
}
|
||||
return new DashboardDTO { GeneratedAt = DateTime.Now };
|
||||
}
|
||||
public async Task<ApiResponseListDTO<List<CheckListHeaderDTO>>> GetFilteredCheckListHeaderAsync(DataTablesRequest dataTablesRequest)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -4,9 +4,10 @@ using WorkFlowCheck.Common.DTO;
|
||||
|
||||
namespace WorkFlowCheck.Web.Services.Interfaces
|
||||
{
|
||||
public interface ICheckListService
|
||||
{
|
||||
Task<CheckListHeaderDTO> GetCheckListHeader(int id);
|
||||
public interface ICheckListService
|
||||
{
|
||||
Task<DashboardDTO> GetDashboardInfoAsync();
|
||||
Task<CheckListHeaderDTO> GetCheckListHeader(int id);
|
||||
Task<ApiResponseListDTO<List<CheckListHeaderDTO>>> GetFilteredCheckListHeaderAsync(DataTablesRequest dataTablesRequest);
|
||||
Task<List<CheckListHeaderDTO>> GetAllCheckListHeaderAsync(int mode = 0);
|
||||
Task<ApiResponseDTO<CheckListHeaderDTO>> UpdateCheckListHeader(CheckListHeaderDTO checkListHeaderDTO);
|
||||
|
||||
@@ -1,2 +1,158 @@
|
||||
body {
|
||||
}
|
||||
/* Workflow Check – DataTables arculat */
|
||||
|
||||
/* Körbefutó keret és finoman lekerekített táblázatsarkok. */
|
||||
table.dataTable {
|
||||
border: 1px solid var(--wfc-border, #d7e2ee) !important;
|
||||
border-collapse: separate !important;
|
||||
border-spacing: 0 !important;
|
||||
border-radius: .6rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr:first-child > th:first-child,
|
||||
table.dataTable > thead > tr:first-child > td:first-child {
|
||||
border-top-left-radius: .52rem;
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr:first-child > th:last-child,
|
||||
table.dataTable > thead > tr:first-child > td:last-child {
|
||||
border-top-right-radius: .52rem;
|
||||
}
|
||||
|
||||
table.dataTable > tbody > tr:last-child > td:first-child,
|
||||
table.dataTable > tbody > tr:last-child > th:first-child,
|
||||
table.dataTable > tfoot > tr:last-child > td:first-child,
|
||||
table.dataTable > tfoot > tr:last-child > th:first-child {
|
||||
border-bottom-left-radius: .52rem;
|
||||
}
|
||||
|
||||
table.dataTable > tbody > tr:last-child > td:last-child,
|
||||
table.dataTable > tbody > tr:last-child > th:last-child,
|
||||
table.dataTable > tfoot > tr:last-child > td:last-child,
|
||||
table.dataTable > tfoot > tr:last-child > th:last-child {
|
||||
border-bottom-right-radius: .52rem;
|
||||
}
|
||||
|
||||
table.dataTable > tbody > tr:last-child > td,
|
||||
table.dataTable > tbody > tr:last-child > th,
|
||||
table.dataTable > tfoot > tr:last-child > td,
|
||||
table.dataTable > tfoot > tr:last-child > th {
|
||||
border-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Fejléc: minden DataTables táblán egységes sötétkék háttér. */
|
||||
table.dataTable > thead,
|
||||
table.dataTable > thead.table-primary {
|
||||
--bs-table-color: var(--wfc-white, #fff);
|
||||
--bs-table-bg: var(--wfc-navy-700, #123c69);
|
||||
--bs-table-border-color: rgb(255 255 255 / 20%);
|
||||
color: var(--wfc-white, #fff);
|
||||
background: var(--wfc-navy-700, #123c69);
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr > th,
|
||||
table.dataTable > thead > tr > td,
|
||||
table.dataTable > thead.table-primary > tr > th,
|
||||
table.dataTable > thead.table-primary > tr > td {
|
||||
border-color: rgb(255 255 255 / 20%) !important;
|
||||
color: var(--wfc-white, #fff) !important;
|
||||
background-color: var(--wfc-navy-700, #123c69) !important;
|
||||
background-image: none !important;
|
||||
font-weight: 700;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr > th:first-child,
|
||||
table.dataTable > thead > tr > td:first-child {
|
||||
border-left-color: var(--wfc-navy-700, #123c69) !important;
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr > th:last-child,
|
||||
table.dataTable > thead > tr > td:last-child {
|
||||
border-right-color: var(--wfc-navy-700, #123c69) !important;
|
||||
}
|
||||
|
||||
/* DataTables 2 rendezési nyilak: fehérek és jól láthatók. */
|
||||
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order::after,
|
||||
table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order::after,
|
||||
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order::after,
|
||||
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order::after {
|
||||
color: var(--wfc-white, #fff) !important;
|
||||
}
|
||||
|
||||
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order::after,
|
||||
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order::after {
|
||||
opacity: .45 !important;
|
||||
}
|
||||
|
||||
table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order::after,
|
||||
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order::before,
|
||||
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order::after {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* Finomabb hover-visszajelzés a rendezhető fejlécen. */
|
||||
table.dataTable > thead > tr > th.dt-orderable-asc:hover,
|
||||
table.dataTable > thead > tr > th.dt-orderable-desc:hover,
|
||||
table.dataTable > thead > tr > td.dt-orderable-asc:hover,
|
||||
table.dataTable > thead > tr > td.dt-orderable-desc:hover {
|
||||
background-color: var(--wfc-navy-800, #0e2c4f) !important;
|
||||
}
|
||||
|
||||
/* A táblázat lábléce marad világos, de illeszkedik az arculathoz. */
|
||||
table.dataTable > tfoot > tr > th,
|
||||
table.dataTable > tfoot > tr > td {
|
||||
border-color: var(--wfc-border, #d7e2ee);
|
||||
color: var(--wfc-navy-900, #0b1f3a);
|
||||
background: #eef6fc;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
/* DataTables lapozó – Workflow Check sötétkék arculat. */
|
||||
div.dt-container .dt-paging .pagination {
|
||||
gap: .18rem;
|
||||
}
|
||||
|
||||
div.dt-container .dt-paging .page-link,
|
||||
div.dt-container .dt-paging button.dt-paging-button {
|
||||
min-width: 38px;
|
||||
border: 1px solid var(--wfc-border, #d7e2ee) !important;
|
||||
border-radius: .45rem !important;
|
||||
color: var(--wfc-navy-700, #123c69) !important;
|
||||
background: var(--wfc-white, #fff) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
div.dt-container .dt-paging .page-link:hover,
|
||||
div.dt-container .dt-paging .page-link:focus,
|
||||
div.dt-container .dt-paging button.dt-paging-button:hover,
|
||||
div.dt-container .dt-paging button.dt-paging-button:focus {
|
||||
border-color: var(--wfc-blue-500, #38bdf8) !important;
|
||||
color: var(--wfc-navy-900, #0b1f3a) !important;
|
||||
background: var(--wfc-blue-200, #bae6fd) !important;
|
||||
}
|
||||
|
||||
div.dt-container .dt-paging .page-item.active .page-link,
|
||||
div.dt-container .dt-paging button.dt-paging-button.current,
|
||||
div.dt-container .dt-paging button.dt-paging-button.current:hover {
|
||||
border-color: var(--wfc-navy-700, #123c69) !important;
|
||||
color: var(--wfc-white, #fff) !important;
|
||||
background: var(--wfc-navy-700, #123c69) !important;
|
||||
box-shadow: 0 4px 10px rgb(18 60 105 / 18%) !important;
|
||||
}
|
||||
|
||||
div.dt-container .dt-paging .page-item.disabled .page-link,
|
||||
div.dt-container .dt-paging button.dt-paging-button.disabled,
|
||||
div.dt-container .dt-paging button.dt-paging-button:disabled {
|
||||
border-color: #e2e8f0 !important;
|
||||
color: #94a3b8 !important;
|
||||
background: #f8fafc !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import url("wfc-datatables.css");
|
||||
@import url("wfc-form.css");
|
||||
@import url("wfc-buttons.css");
|
||||
@import url("wfc-datatables.css");
|
||||
@import url("wfc-forms.css");
|
||||
@import url("wfc-buttons.css");
|
||||
|
||||
.sidebar-brand {
|
||||
display: flex;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import url("wfc.css");
|
||||
|
||||
:root {
|
||||
--wfc-navy-950: #071629;
|
||||
--wfc-navy-900: #0b1f3a;
|
||||
|
||||
Reference in New Issue
Block a user