09420dca0e
TaxBaik CI/CD / build-and-deploy (push) Successful in 1m38s
InquiryDetail and ClientDetail pages were missing the admin-page-hero section, causing the loading overlay to remain stuck on navigation. The loading indicator (admin-session.js) detects page.admin-page-hero to know when to hide the overlay. Now all detail pages show smooth loading indicators on navigation. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
245 lines
11 KiB
Plaintext
245 lines
11 KiB
Plaintext
@page "/admin/clients/{ClientId:int}"
|
|
@attribute [Authorize]
|
|
@using TaxBaik.Application.Services
|
|
@inject ClientService ClientService
|
|
@inject ConsultationService ConsultationService
|
|
@inject NavigationManager Navigation
|
|
@inject ISnackbar Snackbar
|
|
|
|
<PageTitle>고객 상세</PageTitle>
|
|
|
|
<section class="admin-page-hero">
|
|
<div>
|
|
<MudText Typo="Typo.caption" Class="admin-eyebrow">Client Details</MudText>
|
|
<MudText Typo="Typo.h4" Class="admin-page-title">고객 상세</MudText>
|
|
<MudText Typo="Typo.body2" Class="admin-page-subtitle">고객 정보와 상담 이력을 관리합니다.</MudText>
|
|
</div>
|
|
</section>
|
|
|
|
@if (client == null)
|
|
{
|
|
<MudText>고객을 찾을 수 없습니다.</MudText>
|
|
return;
|
|
}
|
|
|
|
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mb-4" Spacing="2">
|
|
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
|
StartIcon="@Icons.Material.Filled.ArrowBack"
|
|
@onclick="@(() => Navigation.NavigateTo("/taxbaik/admin/clients"))">
|
|
목록으로
|
|
</MudButton>
|
|
<MudButton Variant="Variant.Outlined" Color="Color.Warning"
|
|
StartIcon="@Icons.Material.Filled.Edit"
|
|
Href="@($"/taxbaik/admin/clients/{ClientId}/edit")">
|
|
수정
|
|
</MudButton>
|
|
</MudStack>
|
|
|
|
<MudGrid>
|
|
<MudItem xs="12" md="5">
|
|
<MudPaper Class="pa-4" Elevation="1">
|
|
<MudText Typo="Typo.h6" Class="mb-3">고객 정보</MudText>
|
|
<MudGrid Spacing="2">
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">이름</MudText>
|
|
<MudText>@client.Name</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">상호</MudText>
|
|
<MudText>@(client.CompanyName ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">연락처</MudText>
|
|
<MudText>@(client.Phone ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">이메일</MudText>
|
|
<MudText>@(client.Email ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">서비스</MudText>
|
|
<MudText>@(client.ServiceType ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">사업자 유형</MudText>
|
|
<MudText>@(client.TaxType ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">유입 경로</MudText>
|
|
<MudText>@(client.Source ?? "-")</MudText>
|
|
</MudItem>
|
|
<MudItem xs="6">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">등록일</MudText>
|
|
<MudText>@client.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd")</MudText>
|
|
</MudItem>
|
|
@if (!string.IsNullOrWhiteSpace(client.Memo))
|
|
{
|
|
<MudItem xs="12">
|
|
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">메모</MudText>
|
|
<MudText Style="white-space: pre-wrap;">@client.Memo</MudText>
|
|
</MudItem>
|
|
}
|
|
</MudGrid>
|
|
</MudPaper>
|
|
</MudItem>
|
|
|
|
<MudItem xs="12" md="7">
|
|
<MudPaper Class="pa-4" Elevation="1">
|
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="mb-3">
|
|
<MudText Typo="Typo.h6">상담 이력</MudText>
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
|
Size="Size.Small"
|
|
OnClick="OpenAddConsultation">
|
|
+ 상담 추가
|
|
</MudButton>
|
|
</MudStack>
|
|
|
|
@if (showAddForm)
|
|
{
|
|
<MudPaper Class="pa-3 mb-3" Outlined="true">
|
|
<MudGrid Spacing="2">
|
|
<MudItem xs="12" sm="6">
|
|
<MudDatePicker @bind-Date="newDate" Label="상담일" DateFormat="yyyy-MM-dd" />
|
|
</MudItem>
|
|
<MudItem xs="12" sm="6">
|
|
<MudSelect T="string" @bind-Value="newServiceType" Label="서비스 분야">
|
|
@foreach (var t in ClientService.ServiceTypes)
|
|
{
|
|
<MudSelectItem Value="@t">@t</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudItem>
|
|
<MudItem xs="12">
|
|
<MudTextField T="string" @bind-Value="newSummary" Label="상담 내용 *"
|
|
Lines="3" Variant="Variant.Outlined" Required="true" />
|
|
</MudItem>
|
|
<MudItem xs="12" sm="6">
|
|
<MudSelect T="string" @bind-Value="newResult" Label="결과">
|
|
<MudSelectItem Value="@("")">-</MudSelectItem>
|
|
@foreach (var r in ConsultationService.Results)
|
|
{
|
|
<MudSelectItem Value="@r">@r</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudItem>
|
|
<MudItem xs="12" sm="6">
|
|
<MudNumericField T="decimal?" @bind-Value="newFee" Label="수임료 (원)"
|
|
Format="N0" />
|
|
</MudItem>
|
|
</MudGrid>
|
|
<MudStack Row="true" Class="mt-2" Spacing="2">
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddConsultation">저장</MudButton>
|
|
<MudButton Variant="Variant.Outlined" OnClick="@(() => showAddForm = false)">취소</MudButton>
|
|
</MudStack>
|
|
</MudPaper>
|
|
}
|
|
|
|
@if (consultations.Count == 0)
|
|
{
|
|
<MudText Color="Color.Secondary">상담 이력이 없습니다.</MudText>
|
|
}
|
|
else
|
|
{
|
|
<MudList T="string" Dense="true">
|
|
@foreach (var c in consultations)
|
|
{
|
|
<MudListItem>
|
|
<MudPaper Class="pa-3" Outlined="true" Style="width:100%">
|
|
<MudStack Row="true" AlignItems="AlignItems.Start" Justify="Justify.SpaceBetween">
|
|
<div>
|
|
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
|
@c.ConsultationDate.ToString("yyyy-MM-dd")
|
|
@if (!string.IsNullOrEmpty(c.ServiceType)) { <text> · @c.ServiceType</text> }
|
|
</MudText>
|
|
<MudText Style="white-space: pre-wrap;" Class="mt-1">@c.Summary</MudText>
|
|
@if (!string.IsNullOrEmpty(c.Result))
|
|
{
|
|
<MudChip T="string" Size="Size.Small" Color="Color.Info" Class="mt-1">@c.Result</MudChip>
|
|
}
|
|
@if (c.Fee.HasValue)
|
|
{
|
|
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="mt-1">
|
|
수임료: @c.Fee.Value.ToString("N0")원
|
|
</MudText>
|
|
}
|
|
</div>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
|
Size="Size.Small" Color="Color.Error"
|
|
OnClick="@(() => DeleteConsultation(c.Id))" />
|
|
</MudStack>
|
|
</MudPaper>
|
|
</MudListItem>
|
|
}
|
|
</MudList>
|
|
}
|
|
</MudPaper>
|
|
</MudItem>
|
|
</MudGrid>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public int ClientId { get; set; }
|
|
|
|
private Domain.Entities.Client? client;
|
|
private List<Domain.Entities.Consultation> consultations = [];
|
|
|
|
private bool showAddForm;
|
|
private DateTime? newDate = DateTime.Today;
|
|
private string newServiceType = "";
|
|
private string newSummary = "";
|
|
private string newResult = "";
|
|
private decimal? newFee;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadAll();
|
|
}
|
|
|
|
private async Task LoadAll()
|
|
{
|
|
client = await ClientService.GetByIdAsync(ClientId);
|
|
consultations = (await ConsultationService.GetByClientIdAsync(ClientId)).ToList();
|
|
}
|
|
|
|
private void OpenAddConsultation()
|
|
{
|
|
showAddForm = true;
|
|
newDate = DateTime.Today;
|
|
newServiceType = "";
|
|
newSummary = "";
|
|
newResult = "";
|
|
newFee = null;
|
|
}
|
|
|
|
private async Task AddConsultation()
|
|
{
|
|
try
|
|
{
|
|
var c = new Domain.Entities.Consultation
|
|
{
|
|
ClientId = ClientId,
|
|
ConsultationDate = newDate?.ToUniversalTime() ?? DateTime.UtcNow,
|
|
ServiceType = string.IsNullOrWhiteSpace(newServiceType) ? null : newServiceType,
|
|
Summary = newSummary,
|
|
Result = string.IsNullOrWhiteSpace(newResult) ? null : newResult,
|
|
Fee = newFee
|
|
};
|
|
await ConsultationService.CreateAsync(c);
|
|
showAddForm = false;
|
|
consultations = (await ConsultationService.GetByClientIdAsync(ClientId)).ToList();
|
|
Snackbar.Add("상담이 추가되었습니다.", Severity.Success);
|
|
}
|
|
catch (ValidationException ex)
|
|
{
|
|
Snackbar.Add(ex.Message, Severity.Error);
|
|
}
|
|
}
|
|
|
|
private async Task DeleteConsultation(int id)
|
|
{
|
|
await ConsultationService.DeleteAsync(id);
|
|
consultations = (await ConsultationService.GetByClientIdAsync(ClientId)).ToList();
|
|
Snackbar.Add("삭제되었습니다.", Severity.Info);
|
|
}
|
|
}
|