6 changed files with 370 additions and 0 deletions
@ -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, |
|||
}); |
|||
}; |
|||
@ -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' }, |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
@ -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> |
|||
@ -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> |
|||
@ -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', |
|||
}, |
|||
}, |
|||
}; |
|||
@ -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', |
|||
}, |
|||
}, |
|||
}; |
|||
Loading…
Reference in new issue