Files
taxbaik/TaxBaik.Web/Components/Admin/Pages/TaxFilingSchedules.razor
T

254 lines
9.7 KiB
Plaintext

@page "/admin/tax-filing-schedules"
@using TaxBaik.Web.Services.AdminClients
@inject ITaxFilingScheduleBrowserClient TaxFilingClient
@inject IClientBrowserClient ClientClient
@inject ISnackbar Snackbar
@inject IDialogService DialogService
@attribute [Authorize]
<PageTitle>신고 일정</PageTitle>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">CRM & 세무관리</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">신고 일정</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">고객별 마감일과 처리 상태를 한 화면에서 관리합니다.</MudText>
</div>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="OpenCreateDialog"
StartIcon="@Icons.Material.Filled.Add">
새 일정 추가
</MudButton>
</section>
<MudPaper Class="admin-surface" Elevation="0">
@if (schedules is null)
{
<MudProgressLinear Indeterminate="true" />
}
else if (schedules.Count == 0)
{
<MudAlert Severity="Severity.Info" Class="mt-4">
<MudIcon Icon="@Icons.Material.Filled.EventBusy" Class="me-2" />
신고 일정이 없습니다.
</MudAlert>
}
else
{
<MudDataGrid T="TaxFilingSchedule"
Items="@schedules"
Dense="true"
Hover="true"
Striped="true"
Virtualize="true"
RowsPerPage="30"
Class="admin-grid">
<Columns>
<PropertyColumn Property="x => x.Id" Title="ID" Sortable="true" />
<TemplateColumn Title="고객">
<CellTemplate>
@if (clientMap.TryGetValue(context.Item.ClientId, out var clientName))
{
<MudLink Href="@($"/taxbaik/admin/clients/{context.Item.ClientId}")" Color="Color.Primary">
@clientName
</MudLink>
}
</CellTemplate>
</TemplateColumn>
<PropertyColumn Property="x => x.FilingType" Title="신고 유형" />
<TemplateColumn Title="마감일">
<CellTemplate>
@{
var daysLeft = (context.Item.DueDate.Date - DateTime.Today).Days;
var statusColor = daysLeft < 0 ? Color.Error : daysLeft <= 7 ? Color.Warning : Color.Success;
}
<MudChip Size="Size.Small" Color="@statusColor" Variant="Variant.Filled">
@context.Item.DueDate.ToString("yyyy-MM-dd")
@if (daysLeft >= 0)
{
<span class="ms-1">(D-@daysLeft)</span>
}
else
{
<span class="ms-1">(마감 @Math.Abs(daysLeft)일 경과)</span>
}
</MudChip>
</CellTemplate>
</TemplateColumn>
<PropertyColumn Property="x => x.FilingYear" Title="신고연도" />
<TemplateColumn Title="상태">
<CellTemplate>
@if (context.Item.Status == "completed")
{
<MudChip Size="Size.Small" Color="Color.Success" Variant="Variant.Filled">완료</MudChip>
}
else
{
<MudChip Size="Size.Small" Color="Color.Default" Variant="Variant.Outlined">대기</MudChip>
}
</CellTemplate>
</TemplateColumn>
<TemplateColumn Title="작업" Sortable="false">
<CellTemplate>
<MudButtonGroup Size="Size.Small" Variant="Variant.Outlined">
@if (context.Item.Status != "completed")
{
<MudIconButton Icon="@Icons.Material.Filled.CheckCircle"
Color="Color.Success"
OnClick="@(async () => await CompleteSchedule(context.Item.Id))"
Title="완료" />
}
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Color="Color.Error"
OnClick="@(async () => await DeleteSchedule(context.Item.Id))"
Title="삭제" />
</MudButtonGroup>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
}
</MudPaper>
<MudDialog @bind-IsVisible="isDialogOpen" Options="new DialogOptions { MaxWidth = MaxWidth.Small, FullWidth = true }">
<TitleContent>
<MudText Typo="Typo.h6">새 신고 일정 추가</MudText>
</TitleContent>
<DialogContent>
<MudForm @ref="form">
<MudSelect T="int"
@bind-Value="scheduleForm.ClientId"
Label="고객"
Required="true"
Variant="Variant.Outlined"
FullWidth="true"
Class="mb-4">
@foreach (var client in clients)
{
<MudSelectItem Value="@client.Id">@client.CompanyName</MudSelectItem>
}
</MudSelect>
<MudTextField T="string" @bind-Value="scheduleForm.FilingType" Label="신고 유형" Variant="Variant.Outlined" FullWidth="true" Class="mb-4" Required="true" />
<MudDatePicker @bind-Date="scheduleForm.DueDate" Label="마감일" Variant="Variant.Outlined" FullWidth="true" Class="mb-4" Required="true" />
<MudNumericField T="int" @bind-Value="scheduleForm.FilingYear" Label="신고연도" Variant="Variant.Outlined" FullWidth="true" Class="mb-4" Required="true" />
</MudForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="CloseDialog">취소</MudButton>
<MudButton Color="Color.Primary" OnClick="SaveSchedule">저장</MudButton>
</DialogActions>
</MudDialog>
@code {
private List<TaxFilingSchedule>? schedules;
private List<Client> clients = [];
private Dictionary<int, string> clientMap = new();
private MudForm? form;
private bool isDialogOpen;
private TaxFilingScheduleForm scheduleForm = new();
protected override async Task OnInitializedAsync() => await LoadData();
private async Task LoadData()
{
try
{
schedules = await TaxFilingClient.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()
{
scheduleForm = new TaxFilingScheduleForm { FilingYear = DateTime.Now.Year };
isDialogOpen = true;
}
private async Task SaveSchedule()
{
try
{
var newId = await TaxFilingClient.CreateAsync(
scheduleForm.ClientId,
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<ConfirmDialog>("", 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 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;
}
}