diff --git a/TaxBaik.Web/Components/Admin/Pages/TaxProfiles.razor b/TaxBaik.Web/Components/Admin/Pages/TaxProfiles.razor new file mode 100644 index 0000000..b85a27a --- /dev/null +++ b/TaxBaik.Web/Components/Admin/Pages/TaxProfiles.razor @@ -0,0 +1,258 @@ +@page "/admin/tax-profiles" +@using TaxBaik.Web.Services.AdminClients +@inject ITaxProfileBrowserClient TaxProfileClient +@inject IClientBrowserClient ClientClient +@inject ISnackbar Snackbar +@inject IDialogService DialogService +@attribute [Authorize] + +세무 프로필 관리 + +
+
+ 세무 프로필 관리 + + 새 프로필 추가 + +
+ + @if (profiles == null) + { + + } + else if (profiles.Count == 0) + { + 세무 프로필이 없습니다. + } + else + { + + + + + + @if (clientMap.TryGetValue(context.Item.ClientId, out var clientName)) + { + + @clientName + + } + + + + + + + @context.Item.TaxRiskLevel + + + + + + @if (context.Item.NextFilingDueDate.HasValue) + { + @context.Item.NextFilingDueDate.Value.ToString("yyyy-MM-dd") + } + + + + + + + + + + + + + } +
+ + + + + @(editingProfile == null ? "새 프로필 추가" : "프로필 수정") + + + + + @foreach (var client in clients) + { + @client.CompanyName + } + + + + 낮음 + 보통 + 높음 + + + + + + + 취소 + 저장 + + + +@code { + private List? profiles; + private List clients = []; + private Dictionary clientMap = new(); + private MudForm? form; + private bool isDialogOpen; + private TaxProfile? editingProfile; + private TaxProfileForm profileForm = new(); + + protected override async Task OnInitializedAsync() + { + await LoadData(); + } + + private async Task LoadData() + { + try + { + profiles = await TaxProfileClient.GetAllAsync(); + var (clientItems, _) = await ClientClient.GetPagedAsync(); + clients = clientItems.ToList(); + clientMap = clients.ToDictionary(c => c.Id, c => c.CompanyName ?? ""); + } + catch (Exception ex) + { + Snackbar.Add($"데이터 로드 실패: {ex.Message}", Severity.Error); + } + } + + private void OpenCreateDialog() + { + editingProfile = null; + profileForm = new(); + isDialogOpen = true; + } + + private async Task OpenEditDialog(TaxProfile profile) + { + editingProfile = profile; + profileForm = new TaxProfileForm + { + ClientId = profile.ClientId, + BusinessType = profile.BusinessType ?? "", + TaxRiskLevel = profile.TaxRiskLevel, + NextFilingDueDate = profile.NextFilingDueDate, + SpecialNotes = profile.SpecialNotes + }; + isDialogOpen = true; + } + + private async Task SaveProfile() + { + try + { + if (editingProfile == null) + { + var newId = await TaxProfileClient.CreateAsync( + profileForm.ClientId, + profileForm.BusinessType); + + if (newId > 0) + { + Snackbar.Add("프로필이 생성되었습니다.", Severity.Success); + CloseDialog(); + await LoadData(); + } + } + else + { + await TaxProfileClient.UpdateAsync( + editingProfile.Id, + profileForm.BusinessType, + null, + profileForm.NextFilingDueDate, + profileForm.TaxRiskLevel); + + Snackbar.Add("프로필이 업데이트되었습니다.", Severity.Success); + CloseDialog(); + await LoadData(); + } + } + catch (Exception ex) + { + Snackbar.Add($"저장 실패: {ex.Message}", Severity.Error); + } + } + + private async Task DeleteProfile(int id) + { + var parameters = new DialogParameters(); + parameters.Add("Title", "삭제 확인"); + parameters.Add("Message", "이 프로필을 삭제하시겠습니까?"); + + var dialog = await DialogService.ShowAsync("", parameters); + var result = await dialog.Result; + + if (result?.Canceled ?? true) + return; + + try + { + await TaxProfileClient.DeleteAsync(id); + Snackbar.Add("프로필이 삭제되었습니다.", Severity.Success); + await LoadData(); + } + catch (Exception ex) + { + Snackbar.Add($"삭제 실패: {ex.Message}", Severity.Error); + } + } + + private void CloseDialog() + { + isDialogOpen = false; + editingProfile = null; + profileForm = new(); + } + + private Color GetRiskColor(string level) => level switch + { + "high" => Color.Error, + "normal" => Color.Warning, + "low" => Color.Success, + _ => Color.Default + }; + + private class TaxProfileForm + { + public int ClientId { get; set; } + public string BusinessType { get; set; } = ""; + public string TaxRiskLevel { get; set; } = "normal"; + public DateTime? NextFilingDueDate { get; set; } + public string? SpecialNotes { get; set; } + } +} + + diff --git a/TaxBaik.Web/Components/Admin/Shared/ConfirmDialog.razor b/TaxBaik.Web/Components/Admin/Shared/ConfirmDialog.razor new file mode 100644 index 0000000..4bb568d --- /dev/null +++ b/TaxBaik.Web/Components/Admin/Shared/ConfirmDialog.razor @@ -0,0 +1,20 @@ +@using MudBlazor + + + + @Message + + + 취소 + 삭제 + + + +@code { + [CascadingParameter] MudDialogInstance MudDialog { get; set; } = null!; + [Parameter] public string Title { get; set; } = ""; + [Parameter] public string Message { get; set; } = ""; + + private void Cancel() => MudDialog.Cancel(); + private void Confirm() => MudDialog.Close(); +} diff --git a/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs index 9fb01c6..5096236 100644 --- a/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IConsultingActivityBrowserClient.cs @@ -69,8 +69,8 @@ public class ConsultingActivityBrowserClient(HttpClient httpClient, ILogger(cancellationToken: ct); - return result?["id"]?.ToObject() ?? 0; + var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs index aabfd91..3b44959 100644 --- a/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IContractBrowserClient.cs @@ -116,8 +116,8 @@ public class ContractBrowserClient(HttpClient httpClient, ILogger(cancellationToken: ct); - return result?["id"]?.ToObject() ?? 0; + var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs index f40959b..1435dc1 100644 --- a/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/IRevenueTrackingBrowserClient.cs @@ -104,8 +104,8 @@ public class RevenueTrackingBrowserClient(HttpClient httpClient, ILogger(cancellationToken: ct); - return result?["id"]?.ToObject() ?? 0; + var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs index 8563021..458abf5 100644 --- a/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/ITaxFilingScheduleBrowserClient.cs @@ -83,8 +83,8 @@ public class TaxFilingScheduleBrowserClient(HttpClient httpClient, ILogger(cancellationToken: ct); - return result?["id"]?.ToObject() ?? 0; + var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) { diff --git a/TaxBaik.Web/Services/AdminClients/ITaxProfileBrowserClient.cs b/TaxBaik.Web/Services/AdminClients/ITaxProfileBrowserClient.cs index 0e15a18..0a20931 100644 --- a/TaxBaik.Web/Services/AdminClients/ITaxProfileBrowserClient.cs +++ b/TaxBaik.Web/Services/AdminClients/ITaxProfileBrowserClient.cs @@ -100,8 +100,8 @@ public class TaxProfileBrowserClient(HttpClient httpClient, ILogger(cancellationToken: ct); - return result?["id"]?.ToObject() ?? 0; + var result = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + return result.TryGetProperty("id", out var idProp) ? idProp.GetInt32() : 0; } catch (Exception ex) {