54 lines
2.9 KiB
Vue
54 lines
2.9 KiB
Vue
<script setup lang="ts">
|
|
import KsButton from './components/KsButton.vue'
|
|
import KsInlineMessage from './components/KsInlineMessage.vue'
|
|
import SkeletonLoader from './components/SkeletonLoader.vue'
|
|
import EmptyStatePlaceholder from './components/EmptyStatePlaceholder.vue'
|
|
const props = defineProps<{
|
|
loading: boolean
|
|
processing?: boolean
|
|
dirty?: boolean
|
|
error?: Error | null
|
|
empty?: boolean
|
|
partial?: boolean
|
|
staleAt?: string | null
|
|
warning?: string | null
|
|
unauthorized?: boolean
|
|
forbidden?: boolean
|
|
conflict?: boolean
|
|
expired?: boolean
|
|
readonly?: boolean
|
|
correlationId?: string
|
|
skeletonType?: 'text' | 'card' | 'avatar' | 'table' | 'list'
|
|
skeletonRows?: number
|
|
}>()
|
|
const emit = defineEmits<{ retry: [] }>()
|
|
</script>
|
|
<template>
|
|
<section class="ks-query-boundary" :aria-busy="props.loading || props.processing">
|
|
<SkeletonLoader v-if="props.loading" :type="props.skeletonType ?? 'table'" :rows="props.skeletonRows ?? 6" />
|
|
<KsInlineMessage v-else-if="props.unauthorized" severity="warning" title="로그인 필요" message="로그인 후 다시 시도하세요." />
|
|
<KsInlineMessage v-else-if="props.forbidden" severity="danger" title="권한 없음" message="이 작업을 수행할 권한이 없습니다." />
|
|
<KsInlineMessage v-else-if="props.conflict" severity="warning" title="변경 충돌" message="다른 사용자가 먼저 변경했습니다. 최신 버전을 확인하세요." />
|
|
<KsInlineMessage v-else-if="props.expired" severity="warning" title="유효기간 만료" message="만료된 증거 또는 제안은 실행·공개할 수 없습니다." />
|
|
<div v-else-if="props.error" role="alert" class="ks-state-error">
|
|
<KsInlineMessage severity="danger" title="요청 실패" :message="props.error.message" />
|
|
<KsButton label="같은 요청 다시 시도" severity="secondary" @click="emit('retry')" />
|
|
<small v-if="correlationId">Correlation: {{ correlationId }}</small>
|
|
</div>
|
|
<EmptyStatePlaceholder v-else-if="props.empty" />
|
|
<template v-else>
|
|
<KsInlineMessage v-if="props.partial" severity="warning" message="일부 데이터만 표시하고 있습니다. 완전성 경고를 확인하세요." />
|
|
<KsInlineMessage v-if="props.warning" severity="warning" :message="props.warning" />
|
|
<KsInlineMessage v-if="props.readonly" severity="info" message="읽기 전용 상태입니다." />
|
|
<KsInlineMessage v-if="props.dirty" severity="warning" message="저장되지 않은 변경사항이 있습니다." />
|
|
<KsInlineMessage v-if="props.processing" severity="info" message="처리 중입니다. 중복 제출하지 마세요." />
|
|
<slot />
|
|
</template>
|
|
<small v-if="props.staleAt">데이터 기준시각: {{ props.staleAt }}</small>
|
|
</section>
|
|
</template>
|
|
<style scoped>
|
|
.ks-query-boundary { display: flex; flex-direction: column; flex: 1; min-height: 0; height: 100%; }
|
|
.ks-state-error { display: grid; gap: var(--ks-space-2); justify-items: start; }
|
|
</style>
|