Kaynağa Gözat

thêm tab báo cáo cho cms

student 1 ay önce
ebeveyn
işleme
fa05ad53ac

+ 54 - 8
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Controllers/MonthlyRewardPayoutReportController.cs

@@ -22,11 +22,14 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
     [HttpGet("/MonthlyRewardPayoutReport")]
     [HttpGet("/MonthlyRewardPayoutReport/Index")]
     [HttpGet("/Admin/MonthlyRewardPayoutReport")]
-    public async Task<IActionResult> Index(string? selectedMonth = null, int page = 1)
+    public async Task<IActionResult> Index(string? selectedMonth = null, string? tab = null, int page = 1)
     {
         if (!CheckLogin()) return RedirectToLogin();
         if (!HasMenuPermission(CmsSecurityHelper.MonthlyRewardPayoutReportsMenuKey)) return RedirectNoPermission();
 
+        var activeTab = string.Equals(tab?.Trim(), "monthly", StringComparison.OrdinalIgnoreCase)
+            ? "monthly"
+            : "daily";
         var monthText = string.IsNullOrWhiteSpace(selectedMonth)
             ? DateTime.Today.ToString("yyyy-MM", CultureInfo.InvariantCulture)
             : selectedMonth.Trim();
@@ -40,6 +43,7 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
         var model = new MonthlyRewardPayoutReportViewModel
         {
             SelectedMonth = monthText,
+            ActiveTab = activeTab,
             IsInvalidMonth = !isValidMonth,
             Page = Math.Max(1, page),
             PageSize = PageSize
@@ -93,19 +97,61 @@ public class MonthlyRewardPayoutReportController : CmsAuthorizedController
             .ThenBy(x => x.RewardValue)
             .ToList();
 
-        model.TotalRows = items.Count;
         model.GrandTotalPayoutCount = items.Sum(x => x.PayoutCount);
         model.GrandTotalMmk = items.Sum(x => x.TotalMmk);
-        model.TotalPages = Math.Max(1, (int)Math.Ceiling(model.TotalRows / (double)PageSize));
-        model.Page = Math.Min(model.Page, model.TotalPages);
-        model.Items = items
-            .Skip((model.Page - 1) * PageSize)
-            .Take(PageSize)
-            .ToList();
+
+        if (model.IsMonthlySummary)
+        {
+            var monthlyItems = items
+                .GroupBy(x => x.RewardType, StringComparer.OrdinalIgnoreCase)
+                .Select(group =>
+                {
+                    var rewardUnits = group
+                        .Select(x => x.RewardUnit)
+                        .Where(x => !string.IsNullOrWhiteSpace(x))
+                        .Distinct(StringComparer.OrdinalIgnoreCase)
+                        .OrderBy(x => x)
+                        .ToList();
+
+                    return new MonthlyRewardPayoutSummaryItemViewModel
+                    {
+                        Month = monthStart,
+                        RewardType = group.Key,
+                        RewardUnit = rewardUnits.Count == 0 ? string.Empty : string.Join(" / ", rewardUnits),
+                        PayoutCount = group.Sum(x => x.PayoutCount),
+                        TotalRewardValue = group.Sum(x => x.TotalRewardValue),
+                        MmkRate = GetMmkRate(group.Key)
+                    };
+                })
+                .OrderBy(x => x.RewardType)
+                .ToList();
+
+            model.TotalRows = monthlyItems.Count;
+            SetPagination(model);
+            model.MonthlyItems = monthlyItems
+                .Skip((model.Page - 1) * PageSize)
+                .Take(PageSize)
+                .ToList();
+        }
+        else
+        {
+            model.TotalRows = items.Count;
+            SetPagination(model);
+            model.Items = items
+                .Skip((model.Page - 1) * PageSize)
+                .Take(PageSize)
+                .ToList();
+        }
 
         return View(model);
     }
 
+    private static void SetPagination(MonthlyRewardPayoutReportViewModel model)
+    {
+        model.TotalPages = Math.Max(1, (int)Math.Ceiling(model.TotalRows / (double)PageSize));
+        model.Page = Math.Min(model.Page, model.TotalPages);
+    }
+
     private static decimal GetMmkRate(string rewardType)
     {
         return string.Equals(rewardType, "DATA", StringComparison.OrdinalIgnoreCase)

+ 23 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Models/MonthlyRewardPayoutReportViewModel.cs

@@ -4,6 +4,10 @@ public class MonthlyRewardPayoutReportViewModel
 {
     public string SelectedMonth { get; set; } = string.Empty;
 
+    public string ActiveTab { get; set; } = "daily";
+
+    public bool IsMonthlySummary => ActiveTab == "monthly";
+
     public bool IsInvalidMonth { get; set; }
 
     public int Page { get; set; } = 1;
@@ -20,11 +24,30 @@ public class MonthlyRewardPayoutReportViewModel
 
     public List<MonthlyRewardPayoutItemViewModel> Items { get; set; } = new();
 
+    public List<MonthlyRewardPayoutSummaryItemViewModel> MonthlyItems { get; set; } = new();
+
     public decimal TotalPayoutCount => GrandTotalPayoutCount;
 
     public decimal TotalMmk => GrandTotalMmk;
 }
 
+public class MonthlyRewardPayoutSummaryItemViewModel
+{
+    public DateTime Month { get; set; }
+
+    public string RewardType { get; set; } = string.Empty;
+
+    public string RewardUnit { get; set; } = string.Empty;
+
+    public decimal PayoutCount { get; set; }
+
+    public decimal TotalRewardValue { get; set; }
+
+    public decimal MmkRate { get; set; }
+
+    public decimal TotalMmk => TotalRewardValue * MmkRate;
+}
+
 public class MonthlyRewardPayoutItemViewModel
 {
     public DateTime PayoutDate { get; set; }

+ 93 - 36
Kitty_Fall/Kitty_Fall/Kitty_Fall.Cms/Views/MonthlyRewardPayoutReport/Index.cshtml

@@ -3,9 +3,11 @@
     ViewData["Title"] = "Monthly Reward Payout";
     string Number(decimal value) => value.ToString("#,##0.##");
     string Money(decimal value) => value.ToString("#,##0.00");
-    string PageUrl(int page) => Url.Content("~/MonthlyRewardPayoutReport")
+    string ReportUrl(string tab, int page = 1) => Url.Content("~/MonthlyRewardPayoutReport")
         + "?selectedMonth=" + System.Uri.EscapeDataString(Model.SelectedMonth)
+        + "&tab=" + System.Uri.EscapeDataString(tab)
         + "&page=" + page;
+    string PageUrl(int page) => ReportUrl(Model.ActiveTab, page);
 }
 
 <div class="py-6 sm:py-8">
@@ -13,7 +15,23 @@
         <div class="border-b border-gray-100 px-5 py-5 sm:px-6">
             <h1 class="text-2xl font-bold text-gray-900">Monthly Reward Payout Report</h1>
 
+            <div class="mt-5 inline-flex rounded-2xl bg-gray-100 p-1" role="tablist" aria-label="Report view">
+                <a href="@ReportUrl("daily")"
+                   role="tab"
+                   aria-selected="@(!Model.IsMonthlySummary ? "true" : "false")"
+                   class="rounded-xl px-5 py-2.5 text-sm font-semibold transition @(!Model.IsMonthlySummary ? "bg-white text-admin-active shadow-sm" : "text-gray-500 hover:text-gray-800")">
+                    By day
+                </a>
+                <a href="@ReportUrl("monthly")"
+                   role="tab"
+                   aria-selected="@(Model.IsMonthlySummary ? "true" : "false")"
+                   class="rounded-xl px-5 py-2.5 text-sm font-semibold transition @(Model.IsMonthlySummary ? "bg-white text-admin-active shadow-sm" : "text-gray-500 hover:text-gray-800")">
+                    By month
+                </a>
+            </div>
+
             <form method="get" action="@Url.Content("~/MonthlyRewardPayoutReport")" class="mt-5 flex flex-col gap-3 sm:flex-row sm:items-end">
+                <input type="hidden" name="tab" value="@Model.ActiveTab" />
                 <label class="block sm:w-64">
                     <span class="mb-2 block text-sm font-semibold text-gray-700">Month</span>
                     <input type="month" name="selectedMonth" value="@Model.SelectedMonth" class="w-full rounded-2xl border border-gray-200 px-4 py-3 text-sm outline-none transition focus:border-admin-active focus:ring-2 focus:ring-purple-100" />
@@ -36,43 +54,82 @@
                 </div>
                 <div class="overflow-hidden rounded-3xl border border-gray-100">
                     <div class="overflow-x-auto">
-                        <table class="min-w-full divide-y divide-gray-100">
-                            <thead class="bg-gray-50">
-                                <tr class="text-left text-xs font-bold uppercase tracking-wider text-gray-500">
-                                    <th class="px-4 py-3">Date</th>
-                                    <th class="px-4 py-3">Reward type</th>
-                                    <th class="px-4 py-3">Prize value</th>
-                                    <th class="px-4 py-3">Paid count</th>
-                                    <th class="px-4 py-3">Total reward</th>
-                                    <th class="px-4 py-3">MMK / unit</th>
-                                    <th class="px-4 py-3">MMK / prize</th>
-                                    <th class="px-4 py-3">Total MMK</th>
-                                </tr>
-                            </thead>
-                            <tbody class="divide-y divide-gray-100 bg-white text-sm text-gray-700">
-                                @foreach (var item in Model.Items)
-                                {
+                        @if (Model.IsMonthlySummary)
+                        {
+                            <table class="min-w-full divide-y divide-gray-100">
+                                <thead class="bg-gray-50">
+                                    <tr class="text-left text-xs font-bold uppercase tracking-wider text-gray-500">
+                                        <th class="px-4 py-3">Month</th>
+                                        <th class="px-4 py-3">Reward type</th>
+                                        <th class="px-4 py-3">Paid count</th>
+                                        <th class="px-4 py-3">Total reward</th>
+                                        <th class="px-4 py-3">MMK / unit</th>
+                                        <th class="px-4 py-3">Total MMK</th>
+                                    </tr>
+                                </thead>
+                                <tbody class="divide-y divide-gray-100 bg-white text-sm text-gray-700">
+                                    @foreach (var item in Model.MonthlyItems)
+                                    {
+                                        <tr>
+                                            <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@item.Month.ToString("MM/yyyy")</td>
+                                            <td class="px-4 py-4"><span class="rounded-full px-3 py-1 text-xs font-bold @(item.RewardType == "DATA" ? "bg-blue-50 text-blue-700" : "bg-amber-50 text-amber-700")">@item.RewardType</span></td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Number(item.PayoutCount)</td>
+                                            <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@Number(item.TotalRewardValue) @item.RewardUnit</td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Number(item.MmkRate)</td>
+                                            <td class="whitespace-nowrap px-4 py-4 font-bold text-gray-900">@Money(item.TotalMmk) MMK</td>
+                                        </tr>
+                                    }
+                                </tbody>
+                                <tfoot class="border-t-2 border-purple-100 bg-purple-50 text-sm">
                                     <tr>
-                                        <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@item.PayoutDate.ToString("dd/MM/yyyy")</td>
-                                        <td class="px-4 py-4"><span class="rounded-full px-3 py-1 text-xs font-bold @(item.RewardType == "DATA" ? "bg-blue-50 text-blue-700" : "bg-amber-50 text-amber-700")">@item.RewardType</span></td>
-                                        <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@Number(item.RewardValue) @item.RewardUnit</td>
-                                        <td class="whitespace-nowrap px-4 py-4">@Number(item.PayoutCount)</td>
-                                        <td class="whitespace-nowrap px-4 py-4">@Number(item.TotalRewardValue) @item.RewardUnit</td>
-                                        <td class="whitespace-nowrap px-4 py-4">@Number(item.MmkRate)</td>
-                                        <td class="whitespace-nowrap px-4 py-4">@Money(item.MmkPerPrize) MMK</td>
-                                        <td class="whitespace-nowrap px-4 py-4 font-bold text-gray-900">@Money(item.TotalMmk) MMK</td>
+                                        <td colspan="2" class="px-4 py-4 text-right font-bold uppercase tracking-wider text-purple-900">Grand total</td>
+                                        <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Number(Model.GrandTotalPayoutCount)</td>
+                                        <td colspan="2" class="px-4 py-4 text-right text-xs font-semibold text-purple-600">All reward types in @Model.SelectedMonth</td>
+                                        <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Money(Model.GrandTotalMmk) MMK</td>
                                     </tr>
-                                }
-                            </tbody>
-                            <tfoot class="border-t-2 border-purple-100 bg-purple-50 text-sm">
-                                <tr>
-                                    <td colspan="3" class="px-4 py-4 text-right font-bold uppercase tracking-wider text-purple-900">Grand total</td>
-                                    <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Number(Model.GrandTotalPayoutCount)</td>
-                                    <td colspan="3" class="px-4 py-4 text-right text-xs font-semibold text-purple-600">All rows in @Model.SelectedMonth</td>
-                                    <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Money(Model.GrandTotalMmk) MMK</td>
-                                </tr>
-                            </tfoot>
-                        </table>
+                                </tfoot>
+                            </table>
+                        }
+                        else
+                        {
+                            <table class="min-w-full divide-y divide-gray-100">
+                                <thead class="bg-gray-50">
+                                    <tr class="text-left text-xs font-bold uppercase tracking-wider text-gray-500">
+                                        <th class="px-4 py-3">Date</th>
+                                        <th class="px-4 py-3">Reward type</th>
+                                        <th class="px-4 py-3">Prize value</th>
+                                        <th class="px-4 py-3">Paid count</th>
+                                        <th class="px-4 py-3">Total reward</th>
+                                        <th class="px-4 py-3">MMK / unit</th>
+                                        <th class="px-4 py-3">MMK / prize</th>
+                                        <th class="px-4 py-3">Total MMK</th>
+                                    </tr>
+                                </thead>
+                                <tbody class="divide-y divide-gray-100 bg-white text-sm text-gray-700">
+                                    @foreach (var item in Model.Items)
+                                    {
+                                        <tr>
+                                            <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@item.PayoutDate.ToString("dd/MM/yyyy")</td>
+                                            <td class="px-4 py-4"><span class="rounded-full px-3 py-1 text-xs font-bold @(item.RewardType == "DATA" ? "bg-blue-50 text-blue-700" : "bg-amber-50 text-amber-700")">@item.RewardType</span></td>
+                                            <td class="whitespace-nowrap px-4 py-4 font-semibold text-gray-900">@Number(item.RewardValue) @item.RewardUnit</td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Number(item.PayoutCount)</td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Number(item.TotalRewardValue) @item.RewardUnit</td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Number(item.MmkRate)</td>
+                                            <td class="whitespace-nowrap px-4 py-4">@Money(item.MmkPerPrize) MMK</td>
+                                            <td class="whitespace-nowrap px-4 py-4 font-bold text-gray-900">@Money(item.TotalMmk) MMK</td>
+                                        </tr>
+                                    }
+                                </tbody>
+                                <tfoot class="border-t-2 border-purple-100 bg-purple-50 text-sm">
+                                    <tr>
+                                        <td colspan="3" class="px-4 py-4 text-right font-bold uppercase tracking-wider text-purple-900">Grand total</td>
+                                        <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Number(Model.GrandTotalPayoutCount)</td>
+                                        <td colspan="3" class="px-4 py-4 text-right text-xs font-semibold text-purple-600">All rows in @Model.SelectedMonth</td>
+                                        <td class="whitespace-nowrap px-4 py-4 font-bold text-purple-900">@Money(Model.GrandTotalMmk) MMK</td>
+                                    </tr>
+                                </tfoot>
+                            </table>
+                        }
                     </div>
                 </div>