49 lines
2.0 KiB
Vue
49 lines
2.0 KiB
Vue
<script setup lang="ts">
|
|
import { CircleAlert } from '@lucide/vue'
|
|
|
|
withDefaults(defineProps<{
|
|
title: string
|
|
message?: string
|
|
loading?: boolean
|
|
retryText?: string
|
|
showRetry?: boolean
|
|
compact?: boolean
|
|
}>(), {
|
|
message: '',
|
|
loading: false,
|
|
retryText: '重新加载',
|
|
showRetry: true,
|
|
compact: false,
|
|
})
|
|
|
|
defineEmits<{ retry: [] }>()
|
|
</script>
|
|
|
|
<template>
|
|
<section class="load-error-state" :class="{ 'is-compact': compact }" role="alert">
|
|
<CircleAlert class="load-error-state__icon" :size="20" aria-hidden="true" />
|
|
<div class="load-error-state__content">
|
|
<strong>{{ title }}</strong>
|
|
<p v-if="message">{{ message }}</p>
|
|
<slot name="details" />
|
|
</div>
|
|
<div v-if="showRetry || $slots.actions" class="load-error-state__actions">
|
|
<slot name="actions">
|
|
<el-button type="primary" plain :loading="loading" @click="$emit('retry')">{{ retryText }}</el-button>
|
|
</slot>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.load-error-state { display: flex; min-width: 0; align-items: flex-start; gap: 12px; padding: 16px; border: 1px solid var(--el-color-danger-light-7); border-radius: 8px; background: var(--el-color-danger-light-9); color: var(--el-text-color-primary); }
|
|
.load-error-state.is-compact { padding: 12px; }
|
|
.load-error-state__icon { flex: 0 0 auto; margin-top: 1px; color: var(--el-color-danger); }
|
|
.load-error-state__content { min-width: 0; flex: 1; }
|
|
.load-error-state__content strong { display: block; font-size: 14px; line-height: 1.5; }
|
|
.load-error-state__content p { margin: 4px 0 0; color: var(--el-text-color-secondary); font-size: 13px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
.load-error-state__actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; }
|
|
.load-error-state__actions :deep(.el-button) { margin-left: 0; }
|
|
@media (max-width: 720px) { .load-error-state { flex-wrap: wrap; } .load-error-state__content { flex-basis: calc(100% - 36px); } .load-error-state__actions { width: 100%; padding-left: 32px; } .load-error-state__actions :deep(.el-button) { min-height: 44px; } }
|
|
</style>
|