using SharedKernel.Extensions; using SharedKernel.Helpers; using MediatR; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Admin.Pages.Crypto.List { public class IndexModel(IMediator mediator) : PageModel { [BindProperty(SupportsGet = true)] public QueryParams Query { get; set; } = new(); public List Categories { get; set; } = []; public sealed class QueryParams { [Range(1, int.MaxValue)] [DisplayName("페이지 번호")] public int PageNum { get; set; } = 1; [Range(1, 100)] [DisplayName("페이지 당 수")] public ushort PerPage { get; set; } = 20; [DisplayName("카테고리")] public int? CategoryID { get; set; } [DisplayName("검색어")] public string? Keyword { get; set; } [DisplayName("거래쌍 구분")] public ushort Tab { get; set; } = 0; public bool? IsActive { get; set; } public bool? IsWarning { get; set; } public bool? IsNew { get; set; } public bool? IsDelisted { get; set; } } public int Total { get; set; } public List<( int Num, int ID, string Market, string Symbol, string KorName, string EngName, string? LogoImage, IReadOnlyList CategoryNames, char IsActive, char IsWarning, char IsNew, char IsDelisted, string? UpdatedAt, string CreatedAt, string EditURL )> List { get; set; } = []; public int AllCount { get; set; } public int KrwCount { get; set; } public int BtcCount { get; set; } public int UsdtCount { get; set; } public Pagination? Pagination { get; set; } public async Task OnGetAsync(CancellationToken ct) { if (!ModelState.IsValid) { return; } var categories = await mediator.Send(new GetCryptoCategories.Query(), ct); Categories = [..categories.List.Select(c => new SelectListItem(c.Name, c.ID.ToString()))]; var result = await mediator.Send(new SearchCoins.Query( Query.CategoryID, Query.Keyword, Query.IsActive, Query.IsWarning, Query.IsNew, Query.IsDelisted, Query.PageNum, Query.PerPage, Query.Tab ), ct); Total = result.Total; AllCount = result.AllCount; KrwCount = result.KrwCount; BtcCount = result.BtcCount; UsdtCount = result.UsdtCount; List = [..result.List.Select(c => ( c.Num, c.ID, string.Join(", ", c.CoinMarkets.Select(x => x.Market)), c.Symbol, c.KorName, c.EngName, c.LogoImage, c.CategoryNames, c.IsActive ? 'Y' : 'N', c.IsWarning ? 'Y' : 'N', c.IsNew ? 'Y' : 'N', c.IsDelisted ? 'Y' : 'N', c.UpdatedAt.GetDateAt() ?? "-", c.CreatedAt.GetDateAt(), EditURL: $"/Crypto/List/Edit/{c.ID}{Request.QueryString}" ))]; Pagination = new Pagination(result.Total, Query.PageNum, Query.PerPage); } public async Task OnPostDeleteAsync(int[] ids, CancellationToken ct) { try { await mediator.Send(new DeleteCoin.Command(ids), ct); TempData["SuccessMessage"] = $"{ids.Length}개 코인이 삭제되었습니다."; } catch (Exception e) { TempData["ErrorMessages"] = e.Message; } return RedirectToPage("/Crypto/List/Index", Query); } public async Task OnPostSyncAsync(CancellationToken ct) { try { var result = await mediator.Send(new SyncCoins.Command(), ct); TempData["SuccessMessage"] = $"동기화 완료: 신규 {result.Created}개, 갱신 {result.Updated}개, 상폐 {result.Delisted}개"; } catch (Exception e) { TempData["ErrorMessages"] = e.Message; } return RedirectToPage("/Crypto/List/Index", Query); } } }