@page "/admin/tax-filing-schedules" @using TaxBaik.Web.Services.AdminClients @inject ITaxFilingScheduleBrowserClient TaxFilingClient @inject IClientBrowserClient ClientClient @inject ISnackbar Snackbar @inject IDialogService DialogService @attribute [Authorize] 신고 일정 CRM & 세무관리 신고 일정 고객별 마감일과 처리 상태를 한 화면에서 관리합니다. 새 일정 추가 @if (schedules is null) { } else if (schedules.Count == 0) { 신고 일정이 없습니다. } else { @if (clientMap.TryGetValue(context.Item.ClientId, out var clientName)) { @clientName } @{ var daysLeft = (context.Item.DueDate.Date - DateTime.Today).Days; var statusColor = daysLeft < 0 ? Color.Error : daysLeft <= 7 ? Color.Warning : Color.Success; } @context.Item.DueDate.ToString("yyyy-MM-dd") @if (daysLeft >= 0) { (D-@daysLeft) } else { (마감 @Math.Abs(daysLeft)일 경과) } @if (context.Item.Status == "completed") { 완료 } else { 대기 } @if (context.Item.Status != "completed") { } } 새 신고 일정 추가 @foreach (var client in clients) { @GetClientDisplayName(client) } 종합소득세 부가가치세 법인세 원천세 종합부동산세 양도소득세 상속·증여세 세무조정 취소 저장 @code { [CascadingParameter] private Task? AuthStateTask { get; set; } private List? schedules; private List clients = []; private Dictionary clientMap = new(); private MudForm? form; private bool isDialogOpen; private TaxFilingScheduleForm scheduleForm = new(); protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { if (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) { Snackbar.Add($"데이터 로드 실패: {ex.Message}", Severity.Error); } } private void OpenCreateDialog() { scheduleForm = new TaxFilingScheduleForm { FilingYear = DateTime.Now.Year, DueDate = DateTime.Today, ClientId = clients.FirstOrDefault()?.Id }; isDialogOpen = true; } private async Task SaveSchedule() { if (form != null) { await form.Validate(); if (!form.IsValid) { Snackbar.Add("필수 항목을 입력해주세요.", Severity.Warning); return; } } try { if (scheduleForm.ClientId == null) return; var newId = await TaxFilingClient.CreateAsync( scheduleForm.ClientId.Value, scheduleForm.FilingType, scheduleForm.DueDate ?? DateTime.Today, scheduleForm.FilingYear); if (newId > 0) { Snackbar.Add("신고 일정이 추가되었습니다.", Severity.Success); CloseDialog(); await LoadData(); } else { Snackbar.Add("등록에 실패했습니다.", Severity.Error); } } catch (Exception ex) { Snackbar.Add($"저장 실패: {ex.Message}", Severity.Error); } } private async Task CompleteSchedule(int id) { try { await TaxFilingClient.MarkCompletedAsync(id); Snackbar.Add("신고 일정이 완료 처리되었습니다.", Severity.Success); await LoadData(); } catch (Exception ex) { Snackbar.Add($"처리 실패: {ex.Message}", Severity.Error); } } private async Task DeleteSchedule(int id) { var parameters = new DialogParameters { { "Title", "삭제 확인" }, { "Message", "이 신고 일정을 삭제하시겠습니까?" } }; var dialog = await DialogService.ShowAsync("", parameters); var result = await dialog.Result; if (result?.Canceled ?? true) return; try { await TaxFilingClient.DeleteAsync(id); Snackbar.Add("신고 일정이 삭제되었습니다.", Severity.Success); await LoadData(); } catch (Exception ex) { Snackbar.Add($"삭제 실패: {ex.Message}", Severity.Error); } } 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 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; } }