Переглянути джерело

feat(系统模块): 添加异常信息管理功能

shizhongming 2 роки тому
батько
коміт
64de355a13

+ 22 - 0
src/modules/system/views/exception/SysExceptionListView.api.ts

@@ -0,0 +1,22 @@
+import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
+
+enum Api {
+  list = 'sys/exception/list',
+  getById = 'sys/exception/getById',
+}
+
+export const listApi = (params) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.list,
+    data: params,
+  });
+};
+
+export const getById = (id) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.getById,
+    data: id,
+  });
+};

+ 160 - 0
src/modules/system/views/exception/SysExceptionListView.config.ts

@@ -0,0 +1,160 @@
+import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable';
+import { tableBooleanColumnClass } from '@/components/SmartTable';
+
+export const getTableColumns = (): SmartColumn[] => {
+  return [
+    {
+      type: 'checkbox',
+      width: 60,
+      align: 'center',
+      fixed: 'left',
+    },
+    {
+      field: 'id',
+      visible: false,
+      title: '',
+      width: 120,
+    },
+    {
+      field: 'exceptionMessage',
+      fixed: 'left',
+      title: '{system.views.exception.title.exceptionMessage}',
+      width: 200,
+    },
+    {
+      field: 'requestIp',
+      title: '{system.views.exception.title.requestIp}',
+      width: 120,
+    },
+    {
+      field: 'serverIp',
+      title: '{system.views.exception.title.serverIp}',
+      width: 120,
+    },
+    {
+      field: 'requestPath',
+      title: '{system.views.exception.title.requestPath}',
+      width: 200,
+    },
+    {
+      field: 'operateBy',
+      title: '{system.views.exception.title.operateUser}',
+      width: 120,
+    },
+    {
+      field: 'createTime',
+      sortable: true,
+      title: '{common.table.createTime}',
+      width: 150,
+    },
+    {
+      ...tableBooleanColumnClass('{system.views.exception.title.userFeedback}', 'userFeedback'),
+      width: 120,
+      sortable: true,
+    },
+    {
+      field: 'feedbackMessage',
+      title: '{system.views.exception.title.feedbackMessage}',
+      width: 160,
+    },
+    {
+      field: 'feedbackTime',
+      title: '{system.views.exception.title.feedbackTime}',
+      width: 150,
+    },
+    {
+      ...tableBooleanColumnClass('{system.views.exception.title.resolved}', 'resolved'),
+      width: 120,
+      sortable: true,
+    },
+    {
+      field: 'resolvedMessage',
+      title: '{system.views.exception.title.resolvedMessage}',
+      width: 160,
+    },
+    {
+      field: 'resolvedUserId',
+      title: '{system.views.exception.title.resolvedUserId}',
+      width: 120,
+    },
+    {
+      field: 'resolvedTime',
+      title: '{system.views.exception.title.resolvedTime}',
+      width: 150,
+    },
+    {
+      title: '{common.table.operation}',
+      field: 'operation',
+      width: 120,
+      fixed: 'right',
+      slots: {
+        default: 'table-operation',
+      },
+    },
+  ];
+};
+
+const getYesNoOptions = (t: Function) => {
+  return [
+    {
+      label: t('common.form.yes'),
+      value: 1,
+    },
+    {
+      label: t('common.form.no'),
+      value: 0,
+    },
+  ];
+};
+
+export const getSearchFormSchemas = (t: Function): SmartSearchFormSchema[] => {
+  return [
+    {
+      label: t('system.views.exception.title.exceptionMessage'),
+      field: 'exceptionMessage',
+      component: 'Input',
+      searchSymbol: 'like',
+      componentProps: {
+        style: { width: '150px' },
+      },
+    },
+    {
+      label: t('system.views.exception.title.requestIp'),
+      field: 'requestIp',
+      component: 'Input',
+      searchSymbol: 'like',
+      componentProps: {
+        style: { width: '150px' },
+      },
+    },
+    {
+      label: t('system.views.exception.title.serverIp'),
+      field: 'serverIp',
+      component: 'Input',
+      searchSymbol: 'like',
+      componentProps: {
+        style: { width: '150px' },
+      },
+    },
+    {
+      label: t('system.views.exception.title.userFeedback'),
+      field: 'userFeedback',
+      component: 'Select',
+      searchSymbol: '=',
+      componentProps: {
+        options: getYesNoOptions(t),
+        style: { width: '150px' },
+      },
+    },
+    {
+      label: t('system.views.exception.title.resolved'),
+      field: 'resolved',
+      component: 'Select',
+      searchSymbol: '=',
+      componentProps: {
+        options: getYesNoOptions(t),
+        style: { width: '150px' },
+      },
+    },
+  ];
+};

+ 91 - 0
src/modules/system/views/exception/SysExceptionListView.vue

@@ -0,0 +1,91 @@
+<template>
+  <div class="full-height page-container">
+    <SmartTable @register="registerTable" :size="getTableSize">
+      <template #table-operation="{ row }">
+        <SmartVxeTableAction :actions="getTableActions(row)" />
+      </template>
+    </SmartTable>
+    <ExceptionDetailModal @register="registerModal" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import {
+    useSmartTable,
+    SmartTable,
+    SmartVxeTableAction,
+    ActionItem,
+  } from '@/components/SmartTable';
+  import { useModal } from '@/components/Modal';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { useSizeSetting } from '@/hooks/setting/UseSizeSetting';
+
+  import { getSearchFormSchemas, getTableColumns } from './SysExceptionListView.config';
+  import { listApi } from './SysExceptionListView.api';
+  import ExceptionDetailModal from './components/ExceptionDetailModal.vue';
+
+  const { t } = useI18n();
+  const { getTableSize } = useSizeSetting();
+
+  const getTableActions = (row): ActionItem[] => {
+    return [
+      {
+        label: t('system.views.exception.title.showStackTrace'),
+        onClick: () => {
+          openModal(true, row.id);
+        },
+      },
+    ];
+  };
+
+  const [registerModal, { openModal }] = useModal();
+
+  const [registerTable] = useSmartTable({
+    id: 'smart-system-tool-exception',
+    customConfig: { storage: true },
+    border: true,
+    showOverflow: 'tooltip',
+    height: 'auto',
+    stripe: true,
+    pagerConfig: true,
+    useSearchForm: true,
+    searchFormConfig: {
+      layout: 'inline',
+      searchWithSymbol: true,
+      schemas: getSearchFormSchemas(t),
+      colon: true,
+      actionColOptions: {
+        span: undefined,
+      },
+      compact: true,
+    },
+    toolbarConfig: {
+      refresh: true,
+      zoom: true,
+      column: { columnOrder: true },
+    },
+    sortConfig: {
+      remote: true,
+      defaultSort: {
+        field: 'createTime',
+        order: 'desc',
+      },
+    },
+    columns: getTableColumns(),
+    columnConfig: {
+      resizable: true,
+    },
+    proxyConfig: {
+      ajax: {
+        query: ({ ajaxParameter }) =>
+          listApi({
+            sortName: 'createTime',
+            sortOrder: 'desc',
+            ...ajaxParameter,
+          }),
+      },
+    },
+  });
+</script>
+
+<style scoped></style>

+ 33 - 0
src/modules/system/views/exception/components/ExceptionDetailModal.vue

@@ -0,0 +1,33 @@
+<template>
+  <BasicModal
+    defaultFullscreen
+    @register="registerModal"
+    :title="$t('system.views.exception.title.stackTrace')"
+  >
+    <div style=" height: 100%;overflow: auto">
+      <div style="white-space: pre">
+        {{ exceptionData.stackTrace }}
+      </div>
+    </div>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  import { useModalInner, BasicModal } from '@/components/Modal';
+
+  import { getById } from '../SysExceptionListView.api';
+
+  const exceptionData = ref<Recordable>({});
+  const [registerModal, { changeLoading }] = useModalInner(async (id) => {
+    exceptionData.value = {};
+    try {
+      changeLoading(true);
+      exceptionData.value = await getById(id);
+    } finally {
+      changeLoading(false);
+    }
+  });
+</script>
+
+<style scoped></style>

+ 32 - 0
src/modules/system/views/exception/lang/en_US.ts

@@ -0,0 +1,32 @@
+/**
+ * 系统异常信息 国际化信息
+ */
+export default {
+  trans: true,
+  key: 'system.views.exception',
+  data: {
+    title: {
+      exceptionMessage: 'Error message',
+      requestIp: 'Request IP',
+      serverIp: 'Server IP',
+      requestPath: 'Request path',
+      operateUser: 'Operate user',
+      userFeedback: 'Feedback',
+      feedbackMessage: 'Feedback Message',
+      feedbackTime: 'Feedback time',
+      resolved: 'Resolved',
+      resolvedMessage: 'Resolved message',
+      resolvedUserId: 'Resolved user',
+      resolvedTime: 'Resolved time',
+      showStackTrace: 'Show stackTrace',
+      stackTrace: 'Stack trace',
+    },
+    validate: {},
+    rules: {},
+    search: {
+      exceptionMessage: 'Please select the error message',
+      requestIp: 'Please select the request IP',
+      serverIp: 'Please select the server IP',
+    },
+  },
+};

+ 32 - 0
src/modules/system/views/exception/lang/zh_CN.ts

@@ -0,0 +1,32 @@
+/**
+ * 系统异常信息 国际化信息
+ */
+export default {
+  trans: true,
+  key: 'system.views.exception',
+  data: {
+    title: {
+      exceptionMessage: '异常信息',
+      requestIp: '请求IP',
+      serverIp: '服务器IP',
+      requestPath: '请求路径',
+      operateUser: '操作人员',
+      userFeedback: '用户是否反馈',
+      feedbackMessage: '用户反馈信息',
+      feedbackTime: '反馈时间',
+      resolved: '是否已处理',
+      resolvedMessage: '处理信息',
+      resolvedUserId: '处理人员ID',
+      resolvedTime: '处理时间',
+      showStackTrace: '查看堆栈信息',
+      stackTrace: '堆栈信息',
+    },
+    validate: {},
+    rules: {},
+    search: {
+      exceptionMessage: '请输入异常信息',
+      requestIp: '请输入请求IP',
+      serverIp: '请输入服务器IP',
+    },
+  },
+};