refactor(csv-export): streamline CSV export logic and remove redundant methods
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m36s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m36s
- Replaced manual CSV string construction with CsvExportHelper for better readability and maintainability across DiscountOrdersMainPage, SalesReports, OrderSalesReports, and UserOrderMainPage. - Removed obsolete EscapeCsv methods to simplify the codebase. - Enhanced CSV export functionality to utilize a unified base64 conversion method for file saving.
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace BackOffice.Common.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// خروجی CSV سازگار با Excel (UTF-8 BOM + sep=, + اعداد بدون جداکننده هزارگان).
|
||||
/// </summary>
|
||||
public static class CsvExportHelper
|
||||
{
|
||||
public const char Separator = ',';
|
||||
|
||||
public static string Escape(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return string.Empty;
|
||||
|
||||
if (value.Contains(Separator) || value.Contains('"') || value.Contains('\n') || value.Contains('\r'))
|
||||
return $"\"{value.Replace("\"", "\"\"")}\"";
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static string Cell(object? value) => value switch
|
||||
{
|
||||
null => string.Empty,
|
||||
string s => Escape(s),
|
||||
bool b => b ? "1" : "0",
|
||||
IFormattable f => Escape(f.ToString(null, CultureInfo.InvariantCulture) ?? string.Empty),
|
||||
_ => Escape(Convert.ToString(value, CultureInfo.InvariantCulture))
|
||||
};
|
||||
|
||||
public static string Row(params object?[] cells) =>
|
||||
string.Join(Separator, cells.Select(Cell));
|
||||
|
||||
/// <summary>
|
||||
/// نام نمایشی مشتری؛ اگر خالی باشد موبایل یا شناسه کاربر.
|
||||
/// </summary>
|
||||
public static string CustomerName(string? fullName, string? mobile = null, long? userId = null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(fullName))
|
||||
return fullName.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(mobile))
|
||||
return mobile.Trim();
|
||||
if (userId is > 0)
|
||||
return $"کاربر {userId}";
|
||||
return "—";
|
||||
}
|
||||
|
||||
public static string ToBase64(StringBuilder bodyWithoutSepHint)
|
||||
{
|
||||
// Excel در لوکال فارسی با این خط، جداکننده کاما را درست تشخیص میدهد
|
||||
var content = "sep=," + Environment.NewLine + bodyWithoutSepHint;
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(content)).ToArray();
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text;
|
||||
using BackOffice.Common.BaseComponents;
|
||||
using BackOffice.Common.Utilities;
|
||||
using BackOffice.Services.DiscountOrder;
|
||||
using BackOffice.Pages.DiscountShop.Components;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -245,30 +246,29 @@ public partial class DiscountOrdersMainPage
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("شناسه,نام کاربر,موبایل,مبلغ کل,کیف پول اعتباری,پرداخت درگاه,تعداد آیتم,وضعیت پرداخت,وضعیت ارسال,تاریخ پرداخت,تاریخ ثبت,آدرس");
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
"شناسه", "نام مشتری", "موبایل", "مبلغ کل", "کیف پول اعتباری", "پرداخت درگاه",
|
||||
"تعداد آیتم", "وضعیت پرداخت", "وضعیت ارسال", "تاریخ پرداخت", "تاریخ ثبت", "آدرس"));
|
||||
|
||||
foreach (var o in _orders)
|
||||
{
|
||||
sb.AppendLine(string.Join(",",
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
o.Id,
|
||||
EscapeCsv(o.UserFullName),
|
||||
EscapeCsv(o.UserMobile),
|
||||
o.TotalPrice.ToString("N0"),
|
||||
o.DiscountBalanceUsed.ToString("N0"),
|
||||
o.GatewayAmount.ToString("N0"),
|
||||
CsvExportHelper.CustomerName(o.UserFullName, o.UserMobile, o.UserId),
|
||||
o.UserMobile,
|
||||
o.TotalPrice,
|
||||
o.DiscountBalanceUsed,
|
||||
o.GatewayAmount,
|
||||
o.ItemsCount,
|
||||
EscapeCsv(GetPaymentStatusText(o.PaymentStatusValue)),
|
||||
EscapeCsv(GetStatusText(o.Status)),
|
||||
GetPaymentStatusText(o.PaymentStatusValue),
|
||||
GetStatusText(o.Status),
|
||||
o.PaymentDate?.MiladiToJalaliWithTime() ?? "-",
|
||||
o.Created?.MiladiToJalaliWithTime() ?? "-",
|
||||
EscapeCsv(o.ShippingAddress ?? "-")));
|
||||
o.ShippingAddress ?? "-"));
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
var filename = $"discount-orders-{DateTime.Now:yyyyMMddHHmmss}.csv";
|
||||
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64);
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, CsvExportHelper.ToBase64(sb));
|
||||
Snackbar.Add("خروجی Excel (CSV) آماده شد.", Severity.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -276,12 +276,4 @@ public partial class DiscountOrdersMainPage
|
||||
Snackbar.Add($"خطا در خروجی Excel: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return "";
|
||||
if (value.Contains(',') || value.Contains('"') || value.Contains('\n'))
|
||||
return $"\"{value.Replace("\"", "\"\"")}\"";
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,14 +531,15 @@
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("شناسه,نام کاربر,موبایل,تاریخ ثبت,تعداد آیتم,مبلغ نهایی,تخفیف,وضعیت");
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
"شناسه", "نام مشتری", "موبایل", "تاریخ ثبت", "تعداد آیتم", "مبلغ نهایی", "تخفیف", "وضعیت"));
|
||||
|
||||
foreach (var o in _orders.Where(o => o.Created.HasValue).OrderBy(o => o.Created))
|
||||
{
|
||||
sb.AppendLine(string.Join(",",
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
o.Id,
|
||||
EscapeCsv(o.UserFullName),
|
||||
EscapeCsv(o.UserMobile),
|
||||
CsvExportHelper.CustomerName(o.UserFullName, o.UserMobile, o.UserId),
|
||||
o.UserMobile,
|
||||
o.Created?.MiladiToJalaliWithTime() ?? "-",
|
||||
o.ItemsCount,
|
||||
o.GatewayAmount,
|
||||
@@ -546,11 +547,8 @@
|
||||
GetStatusText(o.Status)));
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
var filename = $"discount-sales-{DateTime.Now:yyyyMMddHHmmss}.csv";
|
||||
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64);
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, CsvExportHelper.ToBase64(sb));
|
||||
Snackbar.Add("خروجی Excel (CSV) آماده شد.", Severity.Success);
|
||||
}
|
||||
|
||||
@@ -575,12 +573,12 @@
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine("جزئیات سفارشها:");
|
||||
sb.AppendLine("شناسه | نام کاربر | تاریخ | تعداد آیتم | مبلغ نهایی | تخفیف | وضعیت");
|
||||
sb.AppendLine("شناسه | نام مشتری | تاریخ | تعداد آیتم | مبلغ نهایی | تخفیف | وضعیت");
|
||||
|
||||
foreach (var o in _orders.Where(o => o.Created.HasValue).OrderBy(o => o.Created))
|
||||
{
|
||||
sb.AppendLine(
|
||||
$"{o.Id} | {o.UserFullName} | {o.Created?.MiladiToJalaliWithTime() ?? "-"} | {o.ItemsCount} | {o.GatewayAmount:N0} | {o.DiscountBalanceUsed:N0} | {GetStatusText(o.Status)}");
|
||||
$"{o.Id} | {CsvExportHelper.CustomerName(o.UserFullName, o.UserMobile, o.UserId)} | {o.Created?.MiladiToJalaliWithTime() ?? "-"} | {o.ItemsCount} | {o.GatewayAmount:N0} | {o.DiscountBalanceUsed:N0} | {GetStatusText(o.Status)}");
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
@@ -590,14 +588,4 @@
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64);
|
||||
Snackbar.Add("خروجی PDF (نسخه متنی) آماده شد.", Severity.Success);
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return "";
|
||||
|
||||
var needsQuotes = value.Contains(',') || value.Contains('"') || value.Contains('\n');
|
||||
var escaped = value.Replace("\"", "\"\"");
|
||||
return needsQuotes ? $"\"{escaped}\"" : escaped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Text;
|
||||
using BackOffice.Common.Utilities;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -244,25 +245,23 @@ public partial class OrderSalesReports
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("شناسه,کاربر,نام کاربر,مبلغ,وضعیت پرداخت,وضعیت ارسال,تاریخ پرداخت");
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
"شناسه", "کاربر", "نام مشتری", "مبلغ", "وضعیت پرداخت", "وضعیت ارسال", "تاریخ پرداخت"));
|
||||
|
||||
foreach (var o in _orders)
|
||||
{
|
||||
sb.AppendLine(string.Join(",",
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
o.Id,
|
||||
o.UserId,
|
||||
EscapeCsv(o.UserFullName),
|
||||
CsvExportHelper.CustomerName(o.UserFullName, userId: o.UserId),
|
||||
o.Amount,
|
||||
EscapeCsv(o.PaymentStatus == PaymentStatus.Success ? "پرداخت شده" : "پرداخت نشده"),
|
||||
EscapeCsv(GetDeliveryStatusText(o.DeliveryStatus.GetHashCode())),
|
||||
o.PaymentStatus == PaymentStatus.Success ? "پرداخت شده" : "پرداخت نشده",
|
||||
GetDeliveryStatusText(o.DeliveryStatus.GetHashCode()),
|
||||
o.PaymentDate != null ? o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() : "-"));
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
var filename = $"store-sales-{DateTime.Now:yyyyMMddHHmmss}.csv";
|
||||
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64);
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, CsvExportHelper.ToBase64(sb));
|
||||
Snackbar.Add("خروجی Excel (CSV) آماده شد.", Severity.Success);
|
||||
}
|
||||
|
||||
@@ -292,7 +291,7 @@ public partial class OrderSalesReports
|
||||
foreach (var o in _orders)
|
||||
{
|
||||
sb.AppendLine(
|
||||
$"{o.Id} | {o.UserFullName} | {o.Amount:N0} | {(o.PaymentStatus == PaymentStatus.Success ? "پرداخت شده" : "پرداخت نشده")} | {GetDeliveryStatusText(o.DeliveryStatus.GetHashCode())} | {(o.PaymentDate != null ? o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() : "-")}");
|
||||
$"{o.Id} | {CsvExportHelper.CustomerName(o.UserFullName, userId: o.UserId)} | {o.Amount:N0} | {(o.PaymentStatus == PaymentStatus.Success ? "پرداخت شده" : "پرداخت نشده")} | {GetDeliveryStatusText(o.DeliveryStatus.GetHashCode())} | {(o.PaymentDate != null ? o.PaymentDate.ToDateTime().MiladiToJalaliWithTime() : "-")}");
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
@@ -351,12 +350,4 @@ public partial class OrderSalesReports
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return "";
|
||||
if (value.Contains(',') || value.Contains('"') || value.Contains('\n'))
|
||||
return $"\"{value.Replace("\"", "\"\"")}\"";
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Text.Json;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using BackOffice.Common.BaseComponents;
|
||||
using BackOffice.Common.Utilities;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using BackOffice.Common.BaseComponents;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using MudBlazor;
|
||||
@@ -242,6 +243,15 @@ public partial class UserOrderMainPage
|
||||
};
|
||||
}
|
||||
|
||||
// Domain PaymentStatus: Success=0, Reject=1, Pending=2
|
||||
private static string GetPaymentStatusText(int status) => status switch
|
||||
{
|
||||
0 => "پرداخت شده",
|
||||
1 => "پرداخت ناموفق",
|
||||
2 => "در انتظار پرداخت",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
|
||||
private async Task OpenChangeStatus(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters
|
||||
@@ -320,26 +330,24 @@ public partial class UserOrderMainPage
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("شناسه,کاربر,نام کاربر,مبلغ,وضعیت پرداخت,وضعیت ارسال,روش پرداخت,تاریخ پرداخت");
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
"شناسه", "کاربر", "نام مشتری", "مبلغ", "وضعیت پرداخت", "وضعیت ارسال", "روش پرداخت", "تاریخ پرداخت"));
|
||||
|
||||
foreach (var o in result.Models)
|
||||
{
|
||||
sb.AppendLine(string.Join(",",
|
||||
sb.AppendLine(CsvExportHelper.Row(
|
||||
o.Id,
|
||||
o.UserId,
|
||||
EscapeCsv(o.UserFullName),
|
||||
CsvExportHelper.CustomerName(o.UserFullName, userId: o.UserId),
|
||||
o.Amount,
|
||||
EscapeCsv(o.PaymentStatus.ToString()),
|
||||
EscapeCsv(GetDeliveryStatusText(o.DeliveryStatus.GetHashCode())),
|
||||
EscapeCsv(GetPaymentMethodText(o.PaymentMethod.GetHashCode())),
|
||||
GetPaymentStatusText(o.PaymentStatus.GetHashCode()),
|
||||
GetDeliveryStatusText(o.DeliveryStatus.GetHashCode()),
|
||||
GetPaymentMethodText(o.PaymentMethod.GetHashCode()),
|
||||
o.PaymentDate?.ToDateTime().ToLocalTime().MiladiToJalaliWithTime() ?? "-"));
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(sb.ToString())).ToArray();
|
||||
var base64 = Convert.ToBase64String(bytes);
|
||||
var filename = $"user-orders-{DateTime.Now:yyyyMMddHHmmss}.csv";
|
||||
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, base64);
|
||||
await JsRuntime.InvokeVoidAsync("jsSaveAsFile", filename, CsvExportHelper.ToBase64(sb));
|
||||
Snackbar.Add("خروجی Excel (CSV) آماده شد.", Severity.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -347,12 +355,4 @@ public partial class UserOrderMainPage
|
||||
Snackbar.Add($"خطا در خروجی Excel: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private static string EscapeCsv(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return "";
|
||||
if (value.Contains(',') || value.Contains('"') || value.Contains('\n'))
|
||||
return $"\"{value.Replace("\"", "\"\"")}\"";
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user