@page "/admin/consulting-activities" @using TaxBaik.Web.Services.AdminClients @inject IConsultingActivityBrowserClient ActivityClient @inject IClientBrowserClient ClientClient @inject IJSRuntime JS @attribute [Authorize] 상담 활동 관리
CRM & 세무관리

상담 활동 관리

고객별 상담 이력과 팔로업을 추적합니다.

@if (activities is null) { } else if (activities.Count == 0) {
상담 활동이 없습니다.
} else {
@foreach (var item in activities) { }
ID 고객 활동 유형 활동일시 설명 다음 팔로업 작업
@item.Id @clientMap.GetValueOrDefault(item.ClientId, $"Client #{item.ClientId}") @item.ActivityType @item.ActivityDate.ToString("g") @Truncate(item.Description) @(item.NextFollowupDate?.ToString("yyyy-MM-dd") ?? "—")
}

@(editingActivity == null ? "새 활동 기록" : "활동 기록 수정")

@code { [CascadingParameter] private Task? AuthStateTask { get; set; } private List? activities; private List clients = []; private Dictionary clientMap = new(); private bool isDialogOpen; private ConsultingActivity? editingActivity; private ConsultingActivityForm activityForm = new(); private string ClientIdText { get => activityForm.ClientId > 0 ? activityForm.ClientId.ToString() : ""; set => activityForm.ClientId = int.TryParse(value, out var id) ? id : 0; } private string ActivityDateText { get => activityForm.ActivityDate?.ToString("yyyy-MM-dd HH:mm") ?? ""; set => activityForm.ActivityDate = DateTime.TryParse(value, out var dt) ? dt : null; } private string NextFollowupText { get => activityForm.NextFollowupDate?.ToString("yyyy-MM-dd") ?? ""; set => activityForm.NextFollowupDate = DateTime.TryParse(value, out var dt) ? dt : null; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender && AuthStateTask != null) { var authState = await AuthStateTask; if (authState.User.Identity?.IsAuthenticated == true) { await LoadData(); StateHasChanged(); } } } private async Task LoadData() { try { activities = await ActivityClient.GetAllAsync(); var (clientItems, _) = await ClientClient.GetPagedAsync(pageSize: 1000); clients = clientItems.ToList(); clientMap = clients.ToDictionary(c => c.Id, GetClientDisplayName); } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"데이터 로드 실패: {ex.Message}"); } } private void OpenCreateDialog() { editingActivity = null; activityForm = new ConsultingActivityForm { ClientId = clients.FirstOrDefault()?.Id ?? 0, ActivityDate = DateTime.Now }; isDialogOpen = true; } private async Task OpenEditDialog(ConsultingActivity activity) { editingActivity = activity; activityForm = new ConsultingActivityForm { ClientId = activity.ClientId, ActivityType = activity.ActivityType, ActivityDate = activity.ActivityDate, Description = activity.Description, NextFollowupDate = activity.NextFollowupDate }; isDialogOpen = true; await Task.CompletedTask; } private async Task SaveActivity() { if (activityForm.ClientId <= 0 || string.IsNullOrWhiteSpace(activityForm.ActivityType) || string.IsNullOrWhiteSpace(activityForm.Description)) { await JS.InvokeVoidAsync("alert", "필수 항목을 입력해주세요."); return; } try { if (editingActivity == null) { var newId = await ActivityClient.CreateAsync(activityForm.ClientId, activityForm.ActivityType, activityForm.ActivityDate ?? DateTime.Now, activityForm.Description, null, activityForm.NextFollowupDate); if (newId > 0) { await JS.InvokeVoidAsync("alert", "활동이 기록되었습니다."); CloseDialog(); await LoadData(); } } else { await ActivityClient.UpdateAsync(editingActivity.Id, null, activityForm.NextFollowupDate); await JS.InvokeVoidAsync("alert", "활동이 업데이트되었습니다."); CloseDialog(); await LoadData(); } } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"저장 실패: {ex.Message}"); } } private async Task DeleteActivity(int id) { if (!await JS.InvokeAsync("confirm", "이 활동을 삭제하시겠습니까?")) return; try { await ActivityClient.DeleteAsync(id); await JS.InvokeVoidAsync("alert", "활동이 삭제되었습니다."); await LoadData(); } catch (Exception ex) { await JS.InvokeVoidAsync("alert", $"삭제 실패: {ex.Message}"); } } private void CloseDialog() { isDialogOpen = false; editingActivity = null; activityForm = new(); } private static string Truncate(string? text) => string.IsNullOrWhiteSpace(text) ? "—" : text.Length > 30 ? text[..30] + "..." : text; private static string GetClientDisplayName(Client client) => !string.IsNullOrWhiteSpace(client.CompanyName) ? client.CompanyName : !string.IsNullOrWhiteSpace(client.Name) ? client.Name : $"Client #{client.Id}"; private sealed class ConsultingActivityForm { public int ClientId { get; set; } public string ActivityType { get; set; } = ""; public DateTime? ActivityDate { get; set; } = DateTime.Now; public string Description { get; set; } = ""; public DateTime? NextFollowupDate { get; set; } } }