fallback.vue 3.7 KB

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