Files
skt-vuetify-templates/src/views/errors/ErrorShell.vue
T

136 lines
3.1 KiB
Vue

<template>
<v-container class="fill-height">
<v-row align="center" justify="center" no-gutters>
<v-col cols="12" md="8" sm="10">
<v-card border class="pa-6" variant="flat">
<v-card-title class="d-flex align-center ga-3">
<v-icon :color="color" size="36" :icon="icon" />
<div class="text-h5">{{ title }}</div>
<div class="text-caption text-medium-emphasis">{{ codeLabel }}</div>
<v-spacer />
<img
alt="robot"
class="robot-icon"
height="32"
src="@/assets/robot-svgrepo-com.svg"
width="32"
/>
</v-card-title>
<v-card-text v-if="description" class="text-body-1 mt-4">
<p class="py-3">
{{ description }}
</p>
<v-alert
v-if="backendMessage"
class="mt-6"
:color="color"
density="compact"
type="warning"
variant="tonal"
>
{{ backendMessage }}
</v-alert>
</v-card-text>
<v-card-actions class="mt-6">
<v-btn v-if="showBack" variant="text" @click="router.back()">返回上一頁</v-btn>
<v-spacer />
<v-btn v-if="showHome" color="primary" :to="{ name: 'home' }" variant="flat"
>回到首頁</v-btn
>
<v-btn
v-if="showLogin"
class="ml-2"
color="primary"
:to="{ name: 'login' }"
variant="outlined"
>
前往登入
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup lang="ts">
import { mdiAlertCircleOutline } from '@mdi/js'
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
type Props = {
code: string | number
title: string
description?: string
icon?: string
color?: string
showHome?: boolean
showLogin?: boolean
showBack?: boolean
}
const props = withDefaults(defineProps<Props>(), {
description: undefined,
icon: mdiAlertCircleOutline,
color: 'warning',
showHome: true,
showLogin: true,
showBack: true,
})
const route = useRoute()
const router = useRouter()
const codeLabel = computed(() => {
const code = props.code
return typeof code === 'number' ? `HTTP ${code}` : String(code)
})
const backendMessage = computed(() => {
const raw = route.query.message
if (typeof raw !== 'string') return ''
return raw.trim()
})
</script>
<style scoped>
@keyframes breathe {
0%,
100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
}
@keyframes blink {
0%,
45%,
55%,
100% {
opacity: 1;
}
50% {
opacity: 0.3;
}
}
.robot-icon {
animation: breathe 3s ease-in-out infinite;
}
.robot-icon path:nth-child(2),
.robot-icon path:nth-child(3) {
animation: blink 4s ease-in-out infinite;
}
.robot-icon path:nth-child(3) {
animation-delay: 0.1s;
}
</style>