From c3ee46ff6297f7743e62d19f5163fe744552ff36 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sat, 8 Aug 2026 21:59:30 +0330 Subject: [PATCH] feat(club): update club reports and navigation with new customer package insights - Updated ReportLabels.cs to refine purchase method labels for clarity. - Enhanced ClubHub.razor by adding a new tab for customer package reports and adjusting tab indices. - Modified ClubPackagePurchasesReport.razor to reflect updated purchase method options. - Updated NavMenu.razor to include a link to the new customer packages report. - Bumped Foursat.CMSMicroservice.Protobuf version to 0.0.208 for compatibility with recent changes. --- src/BackOffice/BackOffice.csproj | 2 +- .../Common/Utilities/ReportLabels.cs | 5 +- src/BackOffice/Pages/Club/ClubHub.razor | 11 +- .../Reports/ClubPackagePurchasesReport.razor | 5 +- ...CustomerPackagePurchaseDetailsDialog.razor | 105 +++++++ .../CustomerPackagePurchasesReport.razor | 294 ++++++++++++++++++ src/BackOffice/Shared/NavMenu.razor | 5 + 7 files changed, 419 insertions(+), 8 deletions(-) create mode 100644 src/BackOffice/Pages/Club/Reports/Components/CustomerPackagePurchaseDetailsDialog.razor create mode 100644 src/BackOffice/Pages/Club/Reports/CustomerPackagePurchasesReport.razor diff --git a/src/BackOffice/BackOffice.csproj b/src/BackOffice/BackOffice.csproj index cc3aef2..605345f 100644 --- a/src/BackOffice/BackOffice.csproj +++ b/src/BackOffice/BackOffice.csproj @@ -143,7 +143,7 @@ - + diff --git a/src/BackOffice/Common/Utilities/ReportLabels.cs b/src/BackOffice/Common/Utilities/ReportLabels.cs index 912915d..cc967fa 100644 --- a/src/BackOffice/Common/Utilities/ReportLabels.cs +++ b/src/BackOffice/Common/Utilities/ReportLabels.cs @@ -42,8 +42,9 @@ public static class ReportLabels public static string GetPurchaseMethodLabel(int method) => method switch { - 1 => "وام دایا", - 2 => "خرید مستقیم", + 1 => "دایا", + 2 => "درگاه", + 3 => "دستی", _ => "نامشخص" }; diff --git a/src/BackOffice/Pages/Club/ClubHub.razor b/src/BackOffice/Pages/Club/ClubHub.razor index ef21fcd..6d0a626 100644 --- a/src/BackOffice/Pages/Club/ClubHub.razor +++ b/src/BackOffice/Pages/Club/ClubHub.razor @@ -1,6 +1,7 @@ @page "/club" @page "/club/members" @page "/club/purchases" +@page "/club/customer-packages" @page "/club/cycles" @page "/club/history" @page "/club/statistics" @@ -18,6 +19,9 @@ + + + @@ -39,9 +43,10 @@ _activeTab = uri switch { "club/purchases" => 1, - "club/cycles" => 2, - "club/history" => 3, - "club/statistics" => 4, + "club/customer-packages" => 2, + "club/cycles" => 3, + "club/history" => 4, + "club/statistics" => 5, _ => 0 }; } diff --git a/src/BackOffice/Pages/Club/Reports/ClubPackagePurchasesReport.razor b/src/BackOffice/Pages/Club/Reports/ClubPackagePurchasesReport.razor index a4e7a7e..3c49538 100644 --- a/src/BackOffice/Pages/Club/Reports/ClubPackagePurchasesReport.razor +++ b/src/BackOffice/Pages/Club/Reports/ClubPackagePurchasesReport.razor @@ -17,8 +17,9 @@ - وام دایا - خرید مستقیم + دایا + دستی + درگاه diff --git a/src/BackOffice/Pages/Club/Reports/Components/CustomerPackagePurchaseDetailsDialog.razor b/src/BackOffice/Pages/Club/Reports/Components/CustomerPackagePurchaseDetailsDialog.razor new file mode 100644 index 0000000..5da3165 --- /dev/null +++ b/src/BackOffice/Pages/Club/Reports/Components/CustomerPackagePurchaseDetailsDialog.razor @@ -0,0 +1,105 @@ +@using CMSMicroservice.Protobuf.Protos.UserPackagePurchase +@using Google.Protobuf.WellKnownTypes +@using DateTimeConverterCL + +@inject UserPackagePurchaseContract.UserPackagePurchaseContractClient PurchaseClient + + + + + جزئیات خرید پکیج — @UserName + + + + @if (_loading) + { + + } + else if (_items.Count == 0) + { + خریدی برای این کاربر یافت نشد. + } + else + { + + + شناسه + پکیج + روش + مبلغ (ریال) + تاریخ خرید + + + @context.Id + @context.PackageName + + + @ReportLabels.GetPurchaseMethodLabel(context.PurchaseMethod) + + + @context.Amount.ToString("N0") + + @(context.PurchasedAt != null + ? context.PurchasedAt.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() + : "-") + + + + } + + + بستن + + + +@code { + [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; + [Parameter] public long UserId { get; set; } + [Parameter] public string UserName { get; set; } = string.Empty; + + private bool _loading = true; + private List _items = new(); + + protected override async Task OnInitializedAsync() + { + try + { + var result = await PurchaseClient.GetAllUserPackagePurchaseByFilterAsync( + new GetAllUserPackagePurchaseByFilterRequest + { + PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState + { + PageNumber = 1, + PageSize = 500 + }, + Filter = new GetAllUserPackagePurchaseByFilterFilter + { + UserId = UserId + } + }); + + _items = result?.Models? + .OrderBy(x => x.PurchasedAt?.ToDateTime() ?? DateTime.MinValue) + .ToList() ?? new(); + } + catch (Exception ex) + { + Snackbar.Add($"خطا در بارگذاری جزئیات: {ex.Message}", Severity.Error); + } + finally + { + _loading = false; + } + } + + private static Color GetMethodColor(int method) => method switch + { + 1 => Color.Info, // دایا + 2 => Color.Primary, // درگاه + 3 => Color.Secondary, // دستی + _ => Color.Default + }; + + private void Close() => MudDialog.Close(); +} diff --git a/src/BackOffice/Pages/Club/Reports/CustomerPackagePurchasesReport.razor b/src/BackOffice/Pages/Club/Reports/CustomerPackagePurchasesReport.razor new file mode 100644 index 0000000..66ed35e --- /dev/null +++ b/src/BackOffice/Pages/Club/Reports/CustomerPackagePurchasesReport.razor @@ -0,0 +1,294 @@ +@using System.Text +@using BackOffice.Common.BaseComponents +@using BackOffice.Common.Utilities +@using BackOffice.Pages.AutoComplete +@using BackOffice.Pages.Club.Reports.Components +@using CMSMicroservice.Protobuf.Protos.UserPackagePurchase +@using Google.Protobuf.WellKnownTypes +@using DateTimeConverterCL +@using Microsoft.JSInterop + +@inject UserPackagePurchaseContract.UserPackagePurchaseContractClient PurchaseClient +@inject IDialogService DialogService +@inject IJSRuntime JsRuntime + + + گزارش تجمیعی مشتریان — اولین/آخرین پکیج، تفکیک دایا / دستی / درگاه. خروجی Excel مطابق فیلتر فعال است. + + + + + + + + + + دایا + دستی + درگاه + + + + + + + + + + خروجی Excel + + + + + + + + + @context.Item.UserName + @context.Item.UserMobile + + + + + + + @context.Item.FirstPackageName + @context.Item.FirstAmount.ToString("N0") ریال + + @(context.Item.FirstPurchasedAt?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-") + + + + + + + + @context.Item.LastPackageName + @context.Item.LastAmount.ToString("N0") ریال + + @(context.Item.LastPurchasedAt?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-") + + + @ReportLabels.GetPurchaseMethodLabel(context.Item.LastPurchaseMethod) + + + + + + + + @context.Item.PurchaseCount خرید + @context.Item.TotalAmount.ToString("N0") ریال + + + + + + @context.Item.DayaCount عدد + @context.Item.DayaAmount.ToString("N0") + + + + + @context.Item.ManualCount عدد + @context.Item.ManualAmount.ToString("N0") + + + + + @context.Item.GatewayCount عدد + @context.Item.GatewayAmount.ToString("N0") + + + + + + جزئیات + + + + + + موردی یافت نشد. + + + + + + + + +@code { + private BasePageComponent? _basePage; + private MudDataGrid? _grid; + private long? _userId; + private int? _purchaseMethod; + private DateTime? _fromDate, _toDate; + private bool _exporting; + + private GetCustomerPackagePurchaseRollupFilter BuildFilter() + { + var filter = new GetCustomerPackagePurchaseRollupFilter(); + if (_userId is > 0) + filter.UserId = _userId; + if (_purchaseMethod.HasValue) + filter.PurchaseMethod = _purchaseMethod.Value; + if (_fromDate.HasValue) + filter.PurchasedFrom = Timestamp.FromDateTime(DateTime.SpecifyKind(_fromDate.Value.Date, DateTimeKind.Utc)); + if (_toDate.HasValue) + filter.PurchasedTo = Timestamp.FromDateTime(DateTime.SpecifyKind(_toDate.Value.Date.AddDays(1).AddTicks(-1), DateTimeKind.Utc)); + return filter; + } + + private async Task> LoadData(GridState state) + { + try + { + var result = await PurchaseClient.GetCustomerPackagePurchaseRollupAsync( + new GetCustomerPackagePurchaseRollupRequest + { + PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState + { + PageNumber = state.Page + 1, + PageSize = state.PageSize + }, + Filter = BuildFilter() + }); + + return new GridData + { + Items = result?.Models?.ToList() ?? new(), + TotalItems = (int)(result?.MetaData?.TotalCount ?? 0) + }; + } + catch (Exception ex) + { + Snackbar.Add($"خطا: {ex.Message}", Severity.Error); + return new GridData(); + } + } + + private async Task OnFilterSubmit() + { + if (_grid != null) await _grid.ReloadServerData(); + } + + private async Task OnFilterCleared() + { + _userId = null; + _purchaseMethod = null; + _fromDate = _toDate = null; + if (_grid != null) await _grid.ReloadServerData(); + } + + private async Task OpenDetails(CustomerPackagePurchaseRollupModel row) + { + var parameters = new DialogParameters + { + { nameof(CustomerPackagePurchaseDetailsDialog.UserId), row.UserId }, + { nameof(CustomerPackagePurchaseDetailsDialog.UserName), row.UserName } + }; + var options = new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true, CloseButton = true }; + await DialogService.ShowAsync("جزئیات خرید پکیج", parameters, options); + } + + private async Task ExportToExcel() + { + _exporting = true; + try + { + var filter = BuildFilter(); + var all = new List(); + const int pageSize = 500; + var page = 1; + long totalCount; + + do + { + var result = await PurchaseClient.GetCustomerPackagePurchaseRollupAsync( + new GetCustomerPackagePurchaseRollupRequest + { + PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState + { + PageNumber = page, + PageSize = pageSize + }, + Filter = filter + }); + + var batch = result?.Models?.ToList() ?? new(); + all.AddRange(batch); + totalCount = result?.MetaData?.TotalCount ?? 0; + page++; + } while (all.Count < totalCount && page <= 50); + + if (all.Count == 0) + { + Snackbar.Add("داده‌ای برای خروجی با فیلتر فعلی وجود ندارد.", Severity.Info); + return; + } + + var headers = new[] + { + "شناسه کاربر", "نام مشتری", "موبایل", + "اولین پکیج", "مبلغ اولین", "تاریخ اولین", + "آخرین پکیج", "مبلغ آخرین", "تاریخ آخرین", "روش آخرین", + "تعداد خرید", "جمع مبلغ", + "تعداد دایا", "مبلغ دایا", + "تعداد دستی", "مبلغ دستی", + "تعداد درگاه", "مبلغ درگاه" + }; + + var rows = all.Select(o => new object?[] + { + o.UserId, + o.UserName, + o.UserMobile, + o.FirstPackageName, + o.FirstAmount, + o.FirstPurchasedAt?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-", + o.LastPackageName, + o.LastAmount, + o.LastPurchasedAt?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-", + ReportLabels.GetPurchaseMethodLabel(o.LastPurchaseMethod), + o.PurchaseCount, + o.TotalAmount, + o.DayaCount, + o.DayaAmount, + o.ManualCount, + o.ManualAmount, + o.GatewayCount, + o.GatewayAmount + }); + + var filename = $"customer-packages-{DateTime.Now:yyyyMMddHHmmss}.xls"; + await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, + CsvExportHelper.ToExcelXmlBase64("مشتریان پکیج", headers, rows)); + Snackbar.Add($"خروجی Excel آماده شد ({all.Count} مشتری).", Severity.Success); + } + catch (Exception ex) + { + Snackbar.Add($"خطا در خروجی Excel: {ex.Message}", Severity.Error); + } + finally + { + _exporting = false; + } + } + + private static Color GetMethodColor(int method) => method switch + { + 1 => Color.Info, + 2 => Color.Primary, + 3 => Color.Secondary, + _ => Color.Default + }; +} diff --git a/src/BackOffice/Shared/NavMenu.razor b/src/BackOffice/Shared/NavMenu.razor index e228e37..c2c9776 100644 --- a/src/BackOffice/Shared/NavMenu.razor +++ b/src/BackOffice/Shared/NavMenu.razor @@ -77,6 +77,11 @@ Icon="@Icons.Material.Filled.Groups"> اعضا و گزارش‌ها + + گزارش مشتریان پکیج +