Browse Source

feat(架构): 优化500异常提示

shizhongming 2 năm trước cách đây
mục cha
commit
539f79de39

+ 2 - 0
src/App.vue

@@ -3,6 +3,7 @@
     <AppProvider>
       <RouterView />
     </AppProvider>
+    <ExceptionModal />
   </ConfigProvider>
 </template>
 
@@ -15,6 +16,7 @@
   import { useDarkModeTheme } from '@/hooks/setting/useDarkModeTheme';
   import 'dayjs/locale/zh-cn';
   import { computed } from 'vue';
+  import { ExceptionModal } from '@/views/sys/exception';
 
   // support Multi-language
   const { getAntdLocale } = useLocale();

+ 1 - 0
src/hooks/web/useMessage.tsx

@@ -114,6 +114,7 @@ export function useMessage() {
     successMessage,
     warnMessage,
     errorMessage,
+    createError500Modal,
   };
 }
 

+ 2 - 0
src/modules/smart-app/i18n/lang/en_US.ts

@@ -87,6 +87,8 @@ export default {
       '404': 'The page you visited does not exist',
       '403': 'You do not have permission to access this page',
       backHome: 'Back Home',
+      exceptionTitle:
+        'An error occurred in the system. Please submit the error and contact the administrator',
     },
     common: {
       notice: {

+ 1 - 0
src/modules/smart-app/i18n/lang/zh_CN.ts

@@ -87,6 +87,7 @@ export default {
       '404': '您访问的页面不存在',
       '403': '您无权限访问此页面',
       backHome: '返回主页',
+      exceptionTitle: '系统发生错误,请提交错误,并联系管理员',
     },
     common: {
       notice: {

+ 13 - 6
src/utils/http/axios/index.ts

@@ -22,7 +22,7 @@ import axios from 'axios';
 
 const globSetting = useGlobSetting();
 const urlPrefix = globSetting.urlPrefix;
-const { createMessage, createErrorModal, createSuccessModal } = useMessage();
+const { createMessage, createErrorModal, createSuccessModal, createError500Modal } = useMessage();
 
 /**
  * @description: 数据处理,方便区分多种处理方式
@@ -70,6 +70,7 @@ const transform: AxiosTransform = {
       return result;
     }
 
+    let continueDeal = true;
     // 在此处根据自己项目的实际情况对不同的code执行不同的操作
     // 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
     let timeoutMsg = '';
@@ -80,6 +81,11 @@ const transform: AxiosTransform = {
         // 被动登出,带redirect地址
         userStore.logout(false);
         break;
+      case ResultEnum.ERROR:
+        // 500错误
+        createError500Modal(data as Result);
+        continueDeal = false;
+        break;
       default:
         if (message) {
           timeoutMsg = message;
@@ -88,12 +94,13 @@ const transform: AxiosTransform = {
 
     // errorMessageMode='modal'的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
     // errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
-    if (options.errorMessageMode === 'modal') {
-      createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
-    } else if (options.errorMessageMode === 'message') {
-      createMessage.error(timeoutMsg);
+    if (continueDeal) {
+      if (options.errorMessageMode === 'modal') {
+        createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
+      } else if (options.errorMessageMode === 'message') {
+        createMessage.error(timeoutMsg);
+      }
     }
-
     throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
   },
 

+ 138 - 0
src/views/sys/exception/ExceptionModal.vue

@@ -0,0 +1,138 @@
+<template>
+  <Modal :z-index="10000" :open="computedModalVisible" :footer="null" @cancel="handleHideModal">
+    <div class="exception-modal">
+      <div class="exception-modal-body">
+        <CloseCircleOutlined class="icon" />
+        <span class="title">{{ t('app.title.exceptionTitle') }}</span>
+        <div class="content">
+          <span style="white-space: pre">NO: {{ computedNoList.join(' ') }}</span>
+          <a-textarea
+            v-model:value="model.feedbackMessage"
+            style="margin-top: 10px"
+            :placeholder="t('common.formValidate.enter')"
+            :rows="5"
+          />
+        </div>
+      </div>
+      <div class="exception-modal-button">
+        <a-button @click="handleHideModal">{{ t('common.button.cancel') }}</a-button>
+        <a-button
+          type="primary"
+          :loading="submitLoading"
+          style="margin-left: 5px"
+          @click="handleSubmit"
+        >
+          {{ t('common.button.submit') }}
+        </a-button>
+      </div>
+    </div>
+  </Modal>
+</template>
+
+<script lang="ts">
+  import { defineComponent, ref } from 'vue';
+  import { useI18n } from 'vue-i18n';
+  import { storeToRefs } from 'pinia';
+
+  import { CloseCircleOutlined } from '@ant-design/icons-vue';
+  import { Modal } from 'ant-design-vue';
+
+  import { useSystemExceptionStore } from '@/store/modules/exception';
+
+  import { successMessage } from '@/utils/message/SystemNotice';
+  import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
+
+  export default defineComponent({
+    name: 'ExceptionModal',
+    components: {
+      CloseCircleOutlined,
+      Modal,
+    },
+    setup() {
+      const { t } = useI18n();
+      const systemExceptionStore = useSystemExceptionStore();
+      const { modalVisible, noList } = storeToRefs(systemExceptionStore);
+
+      const model = ref<any>({});
+      const submitLoading = ref(false);
+      /**
+       * 隐藏弹窗
+       */
+      const handleHideModal = () => {
+        systemExceptionStore.handleHideExceptionModal();
+      };
+      /**
+       * 提交操作
+       */
+      const handleSubmit = async () => {
+        submitLoading.value = true;
+        try {
+          await defHttp.post({
+            service: ApiServiceEnum.SMART_SYSTEM,
+            url: 'sys/exception/feedback',
+            data: {
+              idList: noList.value,
+              ...model.value,
+            },
+          });
+          handleHideModal();
+          successMessage({
+            message: t('common.message.submitSuccess'),
+          });
+        } catch (e) {
+          console.log(e);
+        } finally {
+          submitLoading.value = false;
+        }
+      };
+      return {
+        computedModalVisible: modalVisible,
+        handleHideModal,
+        computedNoList: noList,
+        model,
+        handleSubmit,
+        submitLoading,
+        t,
+      };
+    },
+  });
+</script>
+
+<style lang="less" scoped>
+  .exception-modal {
+    padding: 15px;
+
+    &::after {
+      content: '';
+      display: block;
+      clear: both;
+    }
+
+    .exception-modal-body {
+      .icon {
+        margin-right: 16px;
+        color: red;
+        font-size: 22px;
+      }
+
+      .title {
+        display: inline;
+        overflow: hidden;
+        color: #000000d9;
+        font-size: 16px;
+        font-weight: 500;
+        line-height: 1.4;
+      }
+
+      .content {
+        margin-top: 8px;
+        font-size: 14px;
+      }
+    }
+
+    .exception-modal-button {
+      margin-top: 24px;
+      float: right;
+    }
+  }
+</style>

+ 2 - 0
src/views/sys/exception/index.ts

@@ -1 +1,3 @@
 export { default as Exception } from './Exception.vue';
+
+export { default as ExceptionModal } from './ExceptionModal.vue';