fallback.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <script setup lang="ts">
  2. import type { FallbackProps } from './fallback';
  3. import { computed, defineAsyncComponent } from 'vue';
  4. import { useRouter } from 'vue-router';
  5. import { $t } from '@vben/locales';
  6. import { IcRoundArrowBackIosNew, IcRoundRefresh } from '@vben-core/iconify';
  7. import { VbenButton } from '@vben-core/shadcn-ui';
  8. interface Props extends FallbackProps {}
  9. defineOptions({
  10. name: 'Fallback',
  11. });
  12. const props = withDefaults(defineProps<Props>(), {
  13. description: '',
  14. homePath: '/',
  15. image: '',
  16. showBack: true,
  17. status: 'hello',
  18. title: '',
  19. });
  20. const Icon403 = defineAsyncComponent(() => import('./icons/icon-403.vue'));
  21. const Icon404 = defineAsyncComponent(() => import('./icons/icon-404.vue'));
  22. const Icon500 = defineAsyncComponent(() => import('./icons/icon-500.vue'));
  23. const IconHello = defineAsyncComponent(() => import('./icons/icon-hello.vue'));
  24. const IconOffline = defineAsyncComponent(
  25. () => import('./icons/icon-offline.vue'),
  26. );
  27. const titleText = computed(() => {
  28. if (props.title) {
  29. return props.title;
  30. }
  31. switch (props.status) {
  32. case '403': {
  33. return $t('fallback.forbidden');
  34. }
  35. case '404': {
  36. return $t('fallback.page-not-found');
  37. }
  38. case '500': {
  39. return $t('fallback.internal-error');
  40. }
  41. case 'offline': {
  42. return $t('fallback.offline-error');
  43. }
  44. case 'hello': {
  45. return $t('fallback.coming-soon');
  46. }
  47. default: {
  48. return '';
  49. }
  50. }
  51. });
  52. const descText = computed(() => {
  53. if (props.description) {
  54. return props.description;
  55. }
  56. switch (props.status) {
  57. case '403': {
  58. return $t('fallback.forbidden-desc');
  59. }
  60. case '404': {
  61. return $t('fallback.page-not-found-desc');
  62. }
  63. case '500': {
  64. return $t('fallback.internal-error-desc');
  65. }
  66. case 'offline': {
  67. return $t('fallback.offline-error-desc');
  68. }
  69. default: {
  70. return '';
  71. }
  72. }
  73. });
  74. const fallbackIcon = computed(() => {
  75. switch (props.status) {
  76. case '403': {
  77. return Icon403;
  78. }
  79. case '404': {
  80. return Icon404;
  81. }
  82. case '500': {
  83. return Icon500;
  84. }
  85. case 'offline': {
  86. return IconOffline;
  87. }
  88. case 'hello': {
  89. return IconHello;
  90. }
  91. default: {
  92. return null;
  93. }
  94. }
  95. });
  96. const showBack = computed(() => {
  97. return ['403', '404'].includes(props.status);
  98. });
  99. const showRefresh = computed(() => {
  100. return ['500', 'offline'].includes(props.status);
  101. });
  102. const { push } = useRouter();
  103. // 返回首页
  104. function back() {
  105. push(props.homePath);
  106. }
  107. function refresh() {
  108. location.reload();
  109. }
  110. </script>
  111. <template>
  112. <div class="flex size-full flex-col items-center justify-center duration-300">
  113. <img v-if="image" :src="image" class="md:1/3 w-1/2 lg:w-1/4" />
  114. <component
  115. :is="fallbackIcon"
  116. v-else-if="fallbackIcon"
  117. class="md:1/3 h-1/3 w-1/2 lg:w-1/4"
  118. />
  119. <div class="flex-col-center">
  120. <slot v-if="$slots.title" name="title"></slot>
  121. <p
  122. v-else-if="titleText"
  123. class="text-foreground mt-12 text-3xl md:text-4xl lg:text-5xl"
  124. >
  125. {{ titleText }}
  126. </p>
  127. <slot v-if="$slots.describe" name="describe"></slot>
  128. <p
  129. v-else-if="descText"
  130. class="text-muted-foreground md:text-md my-6 lg:text-lg"
  131. >
  132. {{ descText }}
  133. </p>
  134. <slot v-if="$slots.action" name="action"></slot>
  135. <VbenButton v-else-if="showBack" size="lg" @click="back">
  136. <IcRoundArrowBackIosNew class="mr-2" />
  137. {{ $t('common.back-to-home') }}
  138. </VbenButton>
  139. <VbenButton v-else-if="showRefresh" size="lg" @click="refresh">
  140. <IcRoundRefresh class="mr-2" />
  141. {{ $t('common.refresh') }}
  142. </VbenButton>
  143. </div>
  144. </div>
  145. </template>