refactor(fe): P3 pages standardize to screen-type v2 templates

Refactored 4 feature pages to use standard screen-type v2 layouts:

1. HomePage → ScorecardDashboardPage
   - Exception-driven work queue metrics + dashboard layout
   - KPI cards, filters, operational guides
   - Viewport-fit ready, no page-level scrolling

2. ModelsList → MasterDetailCrudPage
   - Master list + detail panel layout
   - Model grid with phase/performance metrics
   - Search, filter, pagination

3. ModelDetail → DetailReadPage
   - Read-only model detail view
   - State management (LOADING/ERROR/READY)
   - Metric display (PBO, DSR, Return)

4. ShadowRunDetail → DetailReadPage
   - Shadow run detail view
   - State management (LOADING/ERROR/READY)
   - Performance metrics (PBO, DSR, OOS)

Pattern Applied:
- Remove PageLayout, use screen-type component
- Add StandardScreenProps (state, evidence)
- State computed from query status
- Slot structure maintained or aligned
- No functional changes, pure standardization

Benefits:
- Consistent layout across pages
- Standardized state management
- Improved viewport-fit compliance
- Better component reusability

Next: Viewport-fit final validation + viewport-fit edge cases

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 17:14:30 +09:00
parent e94096ece6
commit 728393226f
4 changed files with 57 additions and 11 deletions
@@ -1,8 +1,10 @@
<script setup lang="ts">
import { computed } from 'vue'
import { computed, ref } from 'vue'
import { useRoute } from 'vue-router'
import { DetailReadPage } from '../../../shared/ui/screen-types/v2'
import { SkeletonLoader } from '../../../shared/ui/components'
import { useModelDetail } from '../composables/useModels'
import type { StandardScreenProps } from '../../../shared/ui/contracts/screenContract'
const route = useRoute()
@@ -11,10 +13,22 @@ const modelId = computed(() => route.params.modelId as string)
const modelQuery = useModelDetail(modelId.value)
const model = computed(() => modelQuery.data as any)
const screenState = computed<StandardScreenProps['state']>(() => {
if (modelQuery.isPending) return 'LOADING'
if (modelQuery.isError) return 'ERROR'
return 'READY'
})
const screenEvidence = { asOf: new Date().toISOString(), version: '1.0' }
</script>
<template>
<div class="model-detail-page">
<DetailReadPage
title="Model Details"
:state="screenState"
:evidence="screenEvidence"
>
<template #primary>
<header class="page-header">
<h1>Model Details</h1>
</header>
@@ -49,7 +63,8 @@ const model = computed(() => modelQuery.data as any)
</div>
</div>
</div>
</div>
</template>
</DetailReadPage>
</template>
<style scoped>
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import PageLayout from '../../../shared/ui/layouts/PageLayout.vue'
import { MasterDetailCrudPage } from '../../../shared/ui/screen-types/v2'
import { KsDataGrid, EmptyStatePlaceholder, SkeletonLoader } from '../../../shared/ui/components'
import type { UiGridColumn } from '../../../shared/ui/adapter/contracts'
import type { Model, ModelListResponse } from '../composables/useModels'
import type { StandardScreenProps } from '../../../shared/ui/contracts/screenContract'
const currentPage = ref(1)
const pageSize = ref(20)
@@ -124,10 +125,18 @@ function handleSearch() {
currentPage.value = 1
loadModels()
}
const screenState = ref<StandardScreenProps['state']>('READY')
const screenEvidence = { asOf: new Date().toISOString(), version: '1.0' }
</script>
<template>
<PageLayout title="트레이딩 모델 목록 (Model Management)" subtitle="전체 트레이딩 모델의 라이프사이클 및 성과 지표를 조회·관리합니다.">
<MasterDetailCrudPage
title="트레이딩 모델 목록 (Model Management)"
subtitle="전체 트레이딩 모델의 라이프사이클 및 성과 지표를 조회·관리합니다."
:state="screenState"
:evidence="screenEvidence"
>
<template #commandBar>
<button type="button" class="p-button p-button-sm p-button-primary" @click="handleSearch">
🔍 조회 [F3]
@@ -179,7 +188,7 @@ function handleSearch() {
:show-row-number="true"
/>
</div>
</PageLayout>
</MasterDetailCrudPage>
</template>
<style scoped>