Index.cshtml 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. @page
  2. @model Admin.Pages.Store.Settlement.IndexModel
  3. @using Domain.Entities.Store.ValueObject
  4. @{
  5. ViewData["Title"] = "게임사 정산";
  6. }
  7. <div class="container-fluid">
  8. <h3>@ViewData["Title"]</h3>
  9. <hr />
  10. <partial name="_StatusMessage" />
  11. <div class="row g-2 mb-2 align-items-center">
  12. <div class="col-auto search-form__label">
  13. <label class="col-form-label">게임</label>
  14. </div>
  15. <div class="col-12 col-lg-auto">
  16. <select id="gameID" class="form-select">
  17. <option value="">전체 게임</option>
  18. @foreach (var g in Model.Games)
  19. {
  20. <option value="@g.Value" selected="@(Model.Query.GameID?.ToString() == g.Value)">@g.Text</option>
  21. }
  22. </select>
  23. </div>
  24. </div>
  25. <div class="row g-2 mb-2 align-items-center">
  26. <div class="col-auto search-form__label">
  27. <label class="col-form-label">정산 기준 연월</label>
  28. </div>
  29. <div class="col-auto">
  30. <select id="year" class="form-select">
  31. <option value="">연도</option>
  32. @{
  33. var nowY = DateTime.UtcNow.Year;
  34. for (var y = nowY; y >= nowY - 5; y--)
  35. {
  36. <option value="@y" selected="@(Model.Query.Year == y)">@(y)년</option>
  37. }
  38. }
  39. </select>
  40. </div>
  41. <div class="col-auto">
  42. <select id="month" class="form-select">
  43. <option value="">월</option>
  44. @for (var m = 1; m <= 12; m++)
  45. {
  46. <option value="@m" selected="@(Model.Query.Month == m)">@(m)월</option>
  47. }
  48. </select>
  49. </div>
  50. <div class="col-auto">
  51. <div class="btn-group" role="group" aria-label="빠른 선택">
  52. <button type="button" class="btn btn-sm btn-outline-secondary btn-period" data-period="thisMonth">이번달</button>
  53. <button type="button" class="btn btn-sm btn-outline-secondary btn-period" data-period="lastMonth">전월</button>
  54. <button type="button" class="btn btn-sm btn-outline-secondary btn-period" data-period="thisYear">올해</button>
  55. </div>
  56. </div>
  57. </div>
  58. <div class="row justify-content-center mt-3">
  59. <div class="col col-sm-auto">
  60. <button type="button" id="btnSearch" class="btn btn-primary w-100">검색</button>
  61. </div>
  62. </div>
  63. <hr />
  64. <div class="row g-2 mb-2">
  65. <div class="col">
  66. Total : @Model.Total.ToString("N0") &nbsp;|&nbsp;
  67. 합계 매출 : <strong>@((Model.Totals?.TotalRevenue ?? 0).ToString("N0"))원</strong> &nbsp;|&nbsp;
  68. 합계 주문 : <strong>@((Model.Totals?.TotalOrders ?? 0).ToString("N0"))건</strong>
  69. </div>
  70. <div class="col-auto">
  71. <select name="perPage" id="perPage" class="form-select w-auto d-inline-block">
  72. <option value="10" selected="@(Model.Query.PerPage == 10)">10</option>
  73. <option value="20" selected="@(Model.Query.PerPage == 20)">20</option>
  74. <option value="50" selected="@(Model.Query.PerPage == 50)">50</option>
  75. <option value="100" selected="@(Model.Query.PerPage == 100)">100</option>
  76. </select>
  77. </div>
  78. <div class="col-auto">
  79. <a class="btn btn-success" asp-page="Export" asp-all-route-data="@(new Dictionary<string,string?>{
  80. { "Query.GameID", Model.Query.GameID?.ToString() },
  81. { "Query.Year", Model.Query.Year?.ToString() },
  82. { "Query.Month", Model.Query.Month?.ToString() },
  83. { "Query.Status", ((int?)Model.Query.Status)?.ToString() }
  84. })">CSV 다운로드</a>
  85. </div>
  86. </div>
  87. <ul class="nav nav-tabs">
  88. <li class="nav-item">
  89. <a class="nav-link @(!Model.Query.Status.HasValue ? "active" : null)" href="?">
  90. 전체 (@((Model.Counts?.All ?? 0).ToString("N0")))
  91. </a>
  92. </li>
  93. <li class="nav-item">
  94. <a class="nav-link @(Model.Query.Status == GameSettlementStatus.Pending ? "active" : null)" href="?Query.Status=@((int)GameSettlementStatus.Pending)">
  95. 정산 대기 (@((Model.Counts?.Pending ?? 0).ToString("N0")))
  96. </a>
  97. </li>
  98. <li class="nav-item">
  99. <a class="nav-link @(Model.Query.Status == GameSettlementStatus.Settled ? "active" : null)" href="?Query.Status=@((int)GameSettlementStatus.Settled)">
  100. 정산 완료 (@((Model.Counts?.Settled ?? 0).ToString("N0")))
  101. </a>
  102. </li>
  103. </ul>
  104. <div class="table-responsive">
  105. <table class="table table-bordered table-hover mt-3">
  106. <colgroup>
  107. <col style="width: 5%;" />
  108. <col />
  109. <col style="width: 8%;" />
  110. <col style="width: 12%;" />
  111. <col style="width: 8%;" />
  112. <col style="width: 10%;" />
  113. <col style="width: 15%;" />
  114. <col style="width: 12%;" />
  115. <col style="width: 8%;" />
  116. </colgroup>
  117. <thead>
  118. <tr>
  119. <th>#</th>
  120. <th>게임 / 게임사</th>
  121. <th>정산월</th>
  122. <th class="text-end">매출(게임사 몫)</th>
  123. <th class="text-end">주문수</th>
  124. <th>상태</th>
  125. <th>처리 일시 / 관리자</th>
  126. <th>등록 일시</th>
  127. <th>비고</th>
  128. </tr>
  129. </thead>
  130. @if (Model.List == null || Model.List.Count <= 0)
  131. {
  132. <tbody><tr><td colspan="9">No Data.</td></tr></tbody>
  133. }
  134. else
  135. {
  136. <tbody>
  137. @foreach (var row in Model.List)
  138. {
  139. <tr>
  140. <td>@row.Num</td>
  141. <td>
  142. <strong>@row.GameName</strong>
  143. <br /><small class="text-muted">@row.GamePublisher</small>
  144. </td>
  145. <td>@row.Year.@(row.Month.ToString("00"))</td>
  146. <td class="text-end">@row.TotalRevenueAmount.ToString("N0") P</td>
  147. <td class="text-end">@row.OrderCount.ToString("N0")</td>
  148. <td>
  149. @if (row.Status == GameSettlementStatus.Pending)
  150. {
  151. <span class="badge bg-warning text-dark">@row.StatusText</span>
  152. }
  153. else
  154. {
  155. <span class="badge bg-success">@row.StatusText</span>
  156. }
  157. </td>
  158. <td>
  159. @if (row.SettledAt is not null)
  160. {
  161. <small>@row.SettledAt<br />@row.SettledByAdminEmail</small>
  162. }
  163. else
  164. {
  165. <span class="text-muted">-</span>
  166. }
  167. </td>
  168. <td>@row.CreatedAt</td>
  169. <td>
  170. <div class="d-xl-flex gap-2 justify-content-center d-grid">
  171. <a class="btn btn-sm btn-outline-info" href="@row.DetailURL">상세</a>
  172. </div>
  173. </td>
  174. </tr>
  175. }
  176. </tbody>
  177. }
  178. </table>
  179. <partial name="_Pagination" model="Model.Pagination" />
  180. </div>
  181. </div>
  182. @section Scripts {
  183. <script>
  184. function applyPeriod(p) {
  185. const now = new Date();
  186. if (p === "thisMonth") {
  187. document.getElementById("year").value = now.getFullYear();
  188. document.getElementById("month").value = now.getMonth() + 1;
  189. } else if (p === "lastMonth") {
  190. const last = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  191. document.getElementById("year").value = last.getFullYear();
  192. document.getElementById("month").value = last.getMonth() + 1;
  193. } else if (p === "thisYear") {
  194. document.getElementById("year").value = now.getFullYear();
  195. document.getElementById("month").value = "";
  196. }
  197. }
  198. function updateQueryString() {
  199. let queryParams = new URLSearchParams();
  200. const gameID = document.getElementById("gameID").value;
  201. const year = document.getElementById("year").value;
  202. const month = document.getElementById("month").value;
  203. const perPage = document.getElementById("perPage").value;
  204. if (gameID) { queryParams.set("Query.GameID", gameID); }
  205. if (year) { queryParams.set("Query.Year", year); }
  206. if (month) { queryParams.set("Query.Month", month); }
  207. queryParams.set("Query.PerPage", perPage);
  208. @if (Model.Query.Status.HasValue)
  209. {
  210. <text>queryParams.set("Query.Status", "@((int)Model.Query.Status.Value)");</text>
  211. }
  212. window.location.href = window.location.pathname + "?" + queryParams.toString();
  213. }
  214. $(document).on("click", ".btn-period", function() {
  215. applyPeriod($(this).data("period"));
  216. updateQueryString();
  217. });
  218. $(document).on("change", "#perPage", updateQueryString);
  219. $(document).on("click", "#btnSearch", function(e) {
  220. e.preventDefault();
  221. updateQueryString();
  222. });
  223. </script>
  224. }