using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Text; using Domain.Entities.Store.ValueObject; using Application.Abstractions.Messaging; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; namespace Admin.Pages.Store.Settlement; /// /// 게임사 정산 목록 CSV 다운로드. 현재 필터 기준 최대 10,000 row 익스포트. /// public class ExportModel(IMediator mediator) : PageModel { [BindProperty(SupportsGet = true)] public QueryParams Query { get; set; } = new(); public sealed class QueryParams { [DisplayName("게임")] public int? GameID { get; set; } [DisplayName("연도")] [Range(2000, 9999)] public int? Year { get; set; } [DisplayName("월")] [Range(1, 12)] public int? Month { get; set; } [DisplayName("정산 상태")] public GameSettlementStatus? Status { get; set; } } public async Task OnGetAsync(CancellationToken ct) { // 한 번에 최대 10,000 row 익스포트 (운영상 충분) var result = await mediator.Send(new SearchGameSettlements.Query( Query.GameID, Query.Year, Query.Month, Query.Status, 1, 10000 ), ct); var sb = new StringBuilder(); sb.Append(''); // UTF-8 BOM (Excel 한글 호환) sb.AppendLine("게임ID,게임명,게임사,연도,월,매출(원),주문수,상태,등록일시,처리일시,처리관리자,관리자메모"); foreach (var c in result.List) { sb.Append(c.GameID).Append(','); sb.Append(Csv(c.GameName)).Append(','); sb.Append(Csv(c.GamePublisher)).Append(','); sb.Append(c.Year).Append(','); sb.Append(c.Month).Append(','); sb.Append(c.TotalRevenueAmount).Append(','); sb.Append(c.OrderCount).Append(','); sb.Append(Csv(StatusToText(c.Status))).Append(','); sb.Append(c.CreatedAt.ToString("yyyy-MM-dd HH:mm")).Append(','); sb.Append(c.SettledAt?.ToString("yyyy-MM-dd HH:mm") ?? "").Append(','); sb.Append(Csv(c.SettledByAdminEmail ?? "")).Append(','); sb.AppendLine(Csv(c.AdminMemo ?? "")); } var fileName = $"GameSettlements_{DateTime.UtcNow:yyyyMMdd_HHmmss}.csv"; return File(Encoding.UTF8.GetBytes(sb.ToString()), "text/csv", fileName); } private static string Csv(string s) { if (string.IsNullOrEmpty(s)) { return ""; } if (s.Contains(',') || s.Contains('"') || s.Contains('\n') || s.Contains('\r')) { return "\"" + s.Replace("\"", "\"\"") + "\""; } return s; } private static string StatusToText(GameSettlementStatus s) => s switch { GameSettlementStatus.Pending => "정산 대기", GameSettlementStatus.Settled => "정산 완료", _ => "?" }; }