feat(ui): Blazor WebAssembly 마이그레이션 및 API-First 로그인 구현
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
@page "/"
|
||||
@using QuantEngine.Core.Infrastructure
|
||||
@inject HttpClient Http
|
||||
|
||||
<PageTitle>Quant Engine - Dashboard</PageTitle>
|
||||
|
||||
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Quant Engine</h1>
|
||||
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
|
||||
루트 화면은 운영 진입점입니다. 가짜 성과 수치 없이 현재 스냅샷 상태와 리포트 경로만 보여줍니다.
|
||||
</p>
|
||||
|
||||
<!-- Top 3 Cards -->
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
|
||||
<FluentCard Style="flex: 1; min-width: 200px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Operational Report</p>
|
||||
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@ReportStateLabel</h3>
|
||||
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@ReportPath</p>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<FluentCard Style="flex: 1; min-width: 200px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Sections</p>
|
||||
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@SectionCountLabel</h3>
|
||||
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">Temp/operational_report.json</p>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<FluentCard Style="flex: 1; min-width: 200px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Primary Route</p>
|
||||
<FluentButton Appearance="ButtonAppearance.Primary" Href="/operations" Style="margin-top: 8px;">
|
||||
Open Operations
|
||||
</FluentButton>
|
||||
</div>
|
||||
</FluentCard>
|
||||
</FluentStack>
|
||||
|
||||
<!-- Current State & Routing Notes -->
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
|
||||
<FluentCard Style="flex: 2; min-width: 300px;">
|
||||
<div style="padding: 16px;">
|
||||
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Current State</h3>
|
||||
<FluentStack Orientation="Orientation.Vertical" VerticalGap="8">
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Status:</strong> <FluentBadge Appearance="BadgeAppearance.Filled">@ReportChipLabel</FluentBadge></p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Generated:</strong> @GeneratedAtLabel</p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Source:</strong> @SourceLabel</p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Decision feed:</strong> @DecisionFeedLabel</p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Factor feed:</strong> @FactorFeedLabel</p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Raw feed:</strong> @RawFeedLabel</p>
|
||||
</FluentStack>
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
<FluentCard Style="flex: 1; min-width: 250px;">
|
||||
<div style="padding: 16px;">
|
||||
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Routing Notes</h3>
|
||||
<ul style="margin: 0; padding-left: 16px; font-size: 14px;">
|
||||
<li>운영 데이터는 snapshot 우선입니다.</li>
|
||||
<li>Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.</li>
|
||||
<li>숫자는 provenance 없으면 표시하지 않습니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</FluentCard>
|
||||
</FluentStack>
|
||||
|
||||
<!-- Coverage Summary -->
|
||||
<FluentCard>
|
||||
<div style="padding: 16px;">
|
||||
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Coverage Summary</h3>
|
||||
@if (Sections.Count == 0)
|
||||
{
|
||||
<div style="padding: 12px; background: var(--warning-background-1); border: 1px solid var(--warning-stroke-1); border-radius: 4px; color: var(--warning-foreground-1); font-size: 14px;">
|
||||
DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<FluentDataGrid Items="@Sections.AsQueryable()">
|
||||
<PropertyColumn Property="@(x => x.Name)" Title="Name" />
|
||||
<PropertyColumn Property="@(x => x.Title)" Title="Title" />
|
||||
<PropertyColumn Property="@(x => x.Preview)" Title="Preview" />
|
||||
</FluentDataGrid>
|
||||
}
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
@code {
|
||||
private readonly List<OperationalReportSection> Sections = new();
|
||||
private string ReportStateLabel = "DATA_MISSING";
|
||||
private string ReportChipLabel = "DATA_MISSING";
|
||||
private string SectionCountLabel = "0";
|
||||
private string GeneratedAtLabel = "n/a";
|
||||
private string SourceLabel = "n/a";
|
||||
private string DecisionFeedLabel = "DISCONNECTED";
|
||||
private string FactorFeedLabel = "DISCONNECTED";
|
||||
private string RawFeedLabel = "DISCONNECTED";
|
||||
private string ReportPath = "n/a";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var report = await Http.GetFromJsonAsync<OperationalReportData>("api/operational-report");
|
||||
if (report != null)
|
||||
{
|
||||
Sections.Clear();
|
||||
Sections.AddRange(report.Sections);
|
||||
SectionCountLabel = report.SectionCount.ToString();
|
||||
GeneratedAtLabel = report.GeneratedAt;
|
||||
SourceLabel = report.SourceJson;
|
||||
ReportStateLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
|
||||
ReportChipLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
ReportStateLabel = "DATA_MISSING";
|
||||
ReportChipLabel = "DATA_MISSING";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user