31 lines
5.0 KiB
Vue
31 lines
5.0 KiB
Vue
<script setup lang="ts">
|
|
import type { KbxAsyncState, KbxProblem, KbxScreenDefinition, KbxReconcileSummary, KbxTemplateContext } from '@kbx/contracts'
|
|
import KbxScreenFrame from './KbxScreenFrame.vue'
|
|
import KbxTemplateContextBar from './KbxTemplateContextBar.vue'
|
|
import KbxTemplateStateBoundary from './KbxTemplateStateBoundary.vue'
|
|
import KbxProblemFeedback from './KbxProblemFeedback.vue'
|
|
import KbxSectionHeader from './KbxSectionHeader.vue'
|
|
|
|
withDefaults(defineProps<{ screen:KbxScreenDefinition; summary?:KbxReconcileSummary; selectionCount?:number; can?:(permission:string)=>boolean; breadcrumb?:string; context?:KbxTemplateContext|null; contentState?:KbxAsyncState; refreshing?:boolean; errorRetryable?:boolean; problem?:KbxProblem|null; problemActionAllowlist?:readonly string[]; comparisonTitle?:string; comparisonDescription?:string; comparisonCount?:number; comparisonCountUnit?:string }>(), { contentState:'ready', refreshing:false, errorRetryable:true, problem:null, problemActionAllowlist:()=>[], comparisonTitle:'대사 비교', comparisonDescription:'', comparisonCountUnit:'건' })
|
|
const emit=defineEmits<{ command:[string]; problemAction:[string]; retryProblem:[]; dismissProblem:[] }>()
|
|
</script>
|
|
|
|
<template>
|
|
<KbxScreenFrame expected-type="reconcile" template-code="T07" :screen="screen" :selection-count="selectionCount" :can="can" :breadcrumb="breadcrumb" :suppress-default-utility="Boolean($slots.utility)" @command="emit('command',$event)">
|
|
<template #utility><slot name="utility" /></template><template #notice><KbxProblemFeedback v-if="problem" :problem="problem" :allowed-action-ids="problemActionAllowlist" @action="emit('problemAction',$event)" @retry="emit('retryProblem')" @dismiss="emit('dismissProblem')" /><slot name="notice" /></template>
|
|
<div v-if="$slots.search" class="kbx-reconcile-search" data-kbx-surface="criteria/search"><slot name="search" /></div>
|
|
<div v-if="summary" class="kbx-reconcile-summary" aria-label="대사 요약" data-kbx-surface="summary"><span>전체 <strong>{{summary.totalCount.toLocaleString('ko-KR')}}</strong></span><span>정상 <strong>{{summary.matchedCount.toLocaleString('ko-KR')}}</strong></span><span class="mismatch">불일치 <strong>{{summary.mismatchCount.toLocaleString('ko-KR')}}</strong></span><span>확인중 <strong>{{summary.pendingCount.toLocaleString('ko-KR')}}</strong></span><span>해결 <strong>{{summary.resolvedCount.toLocaleString('ko-KR')}}</strong></span></div>
|
|
<section v-if="$slots.filters" class="kbx-reconcile-filters" data-kbx-surface="filters"><slot name="filters" /></section>
|
|
<div v-if="$slots.context || context" data-kbx-surface="context"><slot name="context"><KbxTemplateContextBar :context="context" /></slot></div>
|
|
<section v-if="$slots.resolution" class="kbx-reconcile-resolution" data-kbx-surface="resolution-action"><slot name="resolution" /></section>
|
|
<main class="kbx-reconcile-content" data-kbx-surface="comparison-grid"><slot name="comparison-heading"><KbxSectionHeader :title="comparisonTitle" :description="comparisonDescription" :count="comparisonCount" :count-unit="comparisonCountUnit"><template #actions><slot name="comparison-actions" /></template></KbxSectionHeader></slot><div class="kbx-reconcile-content__body"><KbxTemplateStateBoundary :state="contentState" :refreshing="refreshing" :error-retryable="errorRetryable" idle-action-label="조회 F3" @idle-action="emit('command','search')" @retry="emit('command','search')"><slot name="content" /></KbxTemplateStateBoundary></div></main>
|
|
<section v-if="$slots.audit" class="kbx-reconcile-audit" data-kbx-surface="audit"><slot name="audit" /></section>
|
|
<footer v-if="$slots.footer" class="kbx-reconcile-footer"><slot name="footer" /></footer>
|
|
<div v-if="$slots.detail" data-kbx-surface="detail"><slot name="detail" /></div>
|
|
</KbxScreenFrame>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.kbx-reconcile-summary{display:flex;flex-wrap:wrap;gap:var(--kbx-space-4);padding:var(--kbx-space-2) var(--kbx-space-3);border:var(--kbx-border-width) solid var(--kbx-color-border);border-left:var(--kbx-accent-border-width) solid var(--kbx-color-module-accent);background:var(--kbx-color-surface);box-shadow:var(--kbx-shadow-shell);font-size:var(--kbx-font-sm)}.kbx-reconcile-summary strong{margin-left:var(--kbx-space-1);font-size:var(--kbx-font-md)}.kbx-reconcile-summary .mismatch strong{color:var(--kbx-color-danger)}.kbx-reconcile-resolution{position:sticky;top:var(--kbx-command-bar-height);z-index:6}.kbx-reconcile-content{min-height:var(--kbx-content-min-height);flex:1;display:flex;flex-direction:column;border:var(--kbx-border-width) solid var(--kbx-color-border);background:var(--kbx-color-surface);box-shadow:var(--kbx-shadow-shell)}.kbx-reconcile-content :deep(.kbx-section-header){padding:0 var(--kbx-space-2);background:var(--kbx-color-section-heading)}.kbx-reconcile-content__body{min-height:0;flex:1}.kbx-reconcile-audit{border-top:var(--kbx-border-width) solid var(--kbx-color-border);padding-top:var(--kbx-space-2)}.kbx-reconcile-footer{min-height:var(--kbx-control-sm);border-top:var(--kbx-border-width) solid var(--kbx-color-border)}
|
|
</style>
|