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)
{