@page "/admin/tax-filing-schedules" @using TaxBaik.Web.Services.AdminClients @inject ITaxFilingScheduleBrowserClient TaxFilingClient @inject IClientBrowserClient ClientClient @inject IJSRuntime JS @attribute [Authorize] 신고 일정
CRM & 세무관리

신고 일정

고객별 마감일과 처리 상태를 한 화면에서 관리합니다.

@if (schedules is null) { } else if (schedules.Count == 0) {
신고 일정이 없습니다.
} else {
@foreach (var item in schedules) { var daysLeft = (item.DueDate.Date - DateTime.Today).Days; }
ID 고객 신고 유형 마감일 신고연도 상태 작업
@item.Id @clientMap.GetValueOrDefault(item.ClientId, $"Client #{item.ClientId}") @item.FilingType @item.DueDate.ToString("yyyy-MM-dd") @(daysLeft >= 0 ? $"(D-{daysLeft})" : $"(마감 {Math.Abs(daysLeft)}일 경과)") @item.FilingYear @(item.Status == "completed" ? "완료" : "대기")
@if (item.Status != "completed") { }
}

새 신고 일정 추가

@code { [CascadingParameter] private Task? AuthStateTask { get; set; } private List? schedules; private List clients = []; private Dictionary clientMap = new(); private bool isDialogOpen; private TaxFilingScheduleForm scheduleForm = new(); private string ClientIdText { get => scheduleForm.ClientId > 0 ? scheduleForm.ClientId.ToString() : ""; set => scheduleForm.ClientId = int.TryParse(value, out var id) ? id : 0; } private string DueDateText { get => scheduleForm.DueDate?.ToString("yyyy-MM-dd") ?? ""; set => scheduleForm.DueDate = DateTime.TryParse(value, out var dt) ? dt : null; } private string FilingYearText { get => scheduleForm.FilingYear.ToString(); set => scheduleForm.FilingYear = int.TryParse(value, out var year) ? year : DateTime.Now.Year; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && AuthStateTask != null) { var authState = await AuthStateTask; if (authState.User.Identity?.IsAuthenticated == true) { await LoadData(); StateHasChanged(); } } } private async Task LoadData() { try { schedules = await TaxFilingClient.GetAllAsync(); var (clientItems, _) = await ClientClient.GetPagedAsync(pageSize: 1000); clients = clientItems.ToList(); clientMap = clients.ToDictionary(c => c.Id, GetClientDisplayName); } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"데이터 로드 실패: {ex.Message}"); } } private void OpenCreateDialog() { scheduleForm = new TaxFilingScheduleForm { FilingYear = DateTime.Now.Year, DueDate = DateTime.Today, ClientId = clients.FirstOrDefault()?.Id ?? 0 }; isDialogOpen = true; } private async Task SaveSchedule() { if (scheduleForm.ClientId <= 0 || string.IsNullOrWhiteSpace(scheduleForm.FilingType)) { await JS.InvokeVoidAsync("alert", "필수 항목을 입력해주세요."); return; } try { var newId = await TaxFilingClient.CreateAsync(scheduleForm.ClientId, scheduleForm.FilingType, scheduleForm.DueDate ?? DateTime.Today, scheduleForm.FilingYear); if (newId > 0) { await JS.InvokeVoidAsync("alert", "신고 일정이 추가되었습니다."); CloseDialog(); await LoadData(); } } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"저장 실패: {ex.Message}"); } } private async Task CompleteSchedule(int id) { try { await TaxFilingClient.MarkCompletedAsync(id); await JS.InvokeVoidAsync("alert", "신고 일정이 완료 처리되었습니다."); await LoadData(); } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"처리 실패: {ex.Message}"); } } private async Task DeleteSchedule(int id) { if (!await JS.InvokeAsync("confirm", "이 신고 일정을 삭제하시겠습니까?")) return; try { await TaxFilingClient.DeleteAsync(id); await JS.InvokeVoidAsync("alert", "신고 일정이 삭제되었습니다."); await LoadData(); } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"삭제 실패: {ex.Message}"); } } private void CloseDialog() { isDialogOpen = false; scheduleForm = new(); } private static string GetClientDisplayName(Client client) => !string.IsNullOrWhiteSpace(client.CompanyName) ? client.CompanyName : !string.IsNullOrWhiteSpace(client.Name) ? client.Name : $"Client #{client.Id}"; private sealed class TaxFilingScheduleForm { public int ClientId { get; set; } public string FilingType { get; set; } = ""; public DateTime? DueDate { get; set; } public int FilingYear { get; set; } = DateTime.Now.Year; } }