refactor: admin ui를 fluent v5와 html 기반으로 전환
TaxBaik CI/CD / build-and-deploy (push) Failing after 1m53s
TaxBaik CI/CD / build-and-deploy (push) Failing after 1m53s
This commit is contained in:
@@ -4,185 +4,123 @@
|
||||
@inject ClientService ClientService
|
||||
@inject ConsultationService ConsultationService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<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 class="admin-eyebrow">Client Details</div>
|
||||
<h1 class="admin-page-title">고객 상세</h1>
|
||||
<p class="admin-page-subtitle">고객 정보와 상담 이력을 관리합니다.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@if (client == null)
|
||||
{
|
||||
<MudText>고객을 찾을 수 없습니다.</MudText>
|
||||
return;
|
||||
<div class="admin-surface mt-4">고객을 찾을 수 없습니다.</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="admin-page-actions">
|
||||
<button type="button" class="site-button secondary" @onclick='() => Navigation.NavigateTo("/taxbaik/admin/clients")'>목록으로</button>
|
||||
<a class="site-button secondary" href="@($"/taxbaik/admin/clients/{ClientId}/edit")">수정</a>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<div class="admin-detail-grid">
|
||||
<section class="admin-surface">
|
||||
<h3 class="admin-section-title">고객 정보</h3>
|
||||
<div class="admin-kv-grid">
|
||||
<div><span>이름</span><strong>@client.Name</strong></div>
|
||||
<div><span>상호</span><strong>@(client.CompanyName ?? "-")</strong></div>
|
||||
<div><span>연락처</span><strong>@(client.Phone ?? "-")</strong></div>
|
||||
<div><span>이메일</span><strong>@(client.Email ?? "-")</strong></div>
|
||||
<div><span>서비스</span><strong>@(client.ServiceType ?? "-")</strong></div>
|
||||
<div><span>사업자 유형</span><strong>@(client.TaxType ?? "-")</strong></div>
|
||||
<div><span>유입 경로</span><strong>@(client.Source ?? "-")</strong></div>
|
||||
<div><span>등록일</span><strong>@client.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd")</strong></div>
|
||||
@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>
|
||||
<div class="span-2"><span>메모</span><strong style="white-space: pre-wrap;">@client.Memo</strong></div>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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>
|
||||
<section class="admin-surface">
|
||||
<div class="admin-section-header compact">
|
||||
<div>
|
||||
<h3 class="admin-section-title">상담 이력</h3>
|
||||
</div>
|
||||
<button type="button" class="site-button primary" @onclick="OpenAddConsultation">+ 상담 추가</button>
|
||||
</div>
|
||||
|
||||
@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>
|
||||
<form class="admin-dialog-card mb-4" @onsubmit="AddConsultation" @onsubmit:preventDefault="true">
|
||||
<label>상담일 <input class="admin-input" type="text" placeholder="2026-06-29" @bind="ConsultationDateText" /></label>
|
||||
<label>서비스 분야
|
||||
<select class="admin-input" @bind="newServiceType">
|
||||
<option value="">선택하세요</option>
|
||||
@foreach (var t in ClientService.ServiceTypes)
|
||||
{
|
||||
<option value="@t">@t</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
<label>상담 내용 * <textarea class="admin-input" rows="3" @bind="newSummary"></textarea></label>
|
||||
<label>결과
|
||||
<select class="admin-input" @bind="newResult">
|
||||
<option value="">-</option>
|
||||
@foreach (var r in ConsultationService.Results)
|
||||
{
|
||||
<option value="@r">@r</option>
|
||||
}
|
||||
</select>
|
||||
</label>
|
||||
<label>수임료 (원) <input class="admin-input" type="text" placeholder="100000" @bind="FeeText" /></label>
|
||||
<div class="admin-dialog-actions">
|
||||
<button type="submit" class="site-button primary">저장</button>
|
||||
<button type="button" class="site-button secondary" @onclick='() => showAddForm = false'>취소</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
|
||||
@if (consultations.Count == 0)
|
||||
{
|
||||
<MudText Color="Color.Secondary">상담 이력이 없습니다.</MudText>
|
||||
<p class="muted">상담 이력이 없습니다.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudList T="string" Dense="true">
|
||||
<div class="admin-activity-list">
|
||||
@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>
|
||||
<article class="admin-activity-card">
|
||||
<div class="admin-activity-head">
|
||||
<div>
|
||||
<span class="muted">@c.ConsultationDate.ToString("yyyy-MM-dd") @(string.IsNullOrEmpty(c.ServiceType) ? "" : $"· {c.ServiceType}")</span>
|
||||
</div>
|
||||
<button type="button" class="admin-icon-button danger" @onclick="@(() => DeleteConsultation(c.Id))">✕</button>
|
||||
</div>
|
||||
<p style="white-space: pre-wrap;">@c.Summary</p>
|
||||
@if (!string.IsNullOrEmpty(c.Result))
|
||||
{
|
||||
<span class="status-pill info">@c.Result</span>
|
||||
}
|
||||
@if (c.Fee.HasValue)
|
||||
{
|
||||
<div class="muted">수임료: @c.Fee.Value.ToString("N0")원</div>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</MudList>
|
||||
</div>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public int ClientId { get; set; }
|
||||
|
||||
[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 = "";
|
||||
@@ -190,10 +128,10 @@
|
||||
private string newResult = "";
|
||||
private decimal? newFee;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadAll();
|
||||
}
|
||||
private string ConsultationDateText { get => newDate?.ToString("yyyy-MM-dd") ?? ""; set => newDate = DateTime.TryParse(value, out var dt) ? dt : null; }
|
||||
private string FeeText { get => newFee?.ToString() ?? ""; set => newFee = decimal.TryParse(value, out var d) ? d : null; }
|
||||
|
||||
protected override async Task OnInitializedAsync() => await LoadAll();
|
||||
|
||||
private async Task LoadAll()
|
||||
{
|
||||
@@ -215,6 +153,12 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newSummary))
|
||||
{
|
||||
await JS.InvokeVoidAsync("alert", "상담 내용을 입력하세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
var c = new Domain.Entities.Consultation
|
||||
{
|
||||
ClientId = ClientId,
|
||||
@@ -224,21 +168,23 @@
|
||||
Result = string.IsNullOrWhiteSpace(newResult) ? null : newResult,
|
||||
Fee = newFee
|
||||
};
|
||||
|
||||
await ConsultationService.CreateAsync(c);
|
||||
showAddForm = false;
|
||||
consultations = (await ConsultationService.GetByClientIdAsync(ClientId)).ToList();
|
||||
Snackbar.Add("상담이 추가되었습니다.", Severity.Success);
|
||||
await JS.InvokeVoidAsync("alert", "상담이 추가되었습니다.");
|
||||
}
|
||||
catch (ValidationException ex)
|
||||
{
|
||||
Snackbar.Add(ex.Message, Severity.Error);
|
||||
await JS.InvokeVoidAsync("alert", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteConsultation(int id)
|
||||
{
|
||||
if (!await JS.InvokeAsync<bool>("confirm", "이 상담을 삭제하시겠습니까?")) return;
|
||||
await ConsultationService.DeleteAsync(id);
|
||||
consultations = (await ConsultationService.GetByClientIdAsync(ClientId)).ToList();
|
||||
Snackbar.Add("삭제되었습니다.", Severity.Info);
|
||||
await JS.InvokeVoidAsync("alert", "삭제되었습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user