feat: 一些日志的详情查看
parent
02d0c92e89
commit
dae144ccf9
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" title="访问日志详情" @register="registerModalInner" @ok="closeModal" width="800px">
|
||||||
|
<Description @register="registerDescription" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { BasicModal, useModalInner } from '@/components/Modal'
|
||||||
|
import { Description, useDescription } from '@/components/Description/index'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { infoSchema } from './apiAccessLog.data'
|
||||||
|
|
||||||
|
defineOptions({ name: 'AcessLogModal' })
|
||||||
|
|
||||||
|
const logData = ref()
|
||||||
|
const [registerModalInner, { closeModal }] = useModalInner((record: Recordable) => {
|
||||||
|
logData.value = record
|
||||||
|
})
|
||||||
|
|
||||||
|
const [registerDescription] = useDescription({
|
||||||
|
column: 1,
|
||||||
|
schema: infoSchema,
|
||||||
|
data: logData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -1,5 +1,7 @@
|
||||||
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||||
|
import { DescItem } from '@/components/Description/index'
|
||||||
|
import { h } from 'vue'
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
|
@ -58,7 +60,7 @@ export const columns: BasicColumn[] = [
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: ({ record }) => {
|
customRender: ({ record }) => {
|
||||||
const success = record.resultCode === 0
|
const success = record.resultCode === 0
|
||||||
return useRender.renderTag(success ? '成功' : '失败(' + record.resultMsg + ')', success ? '#87d068' : '#f50')
|
return useRender.renderTag(success ? '成功' : '失败', success ? '#87d068' : '#f50')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -110,3 +112,103 @@ export const searchFormSchema: FormSchema[] = [
|
||||||
colProps: { span: 8 }
|
colProps: { span: 8 }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const httpMethods = [
|
||||||
|
{ value: 'GET', color: '#108ee9' },
|
||||||
|
{ value: 'POST', color: '#2db7f5' },
|
||||||
|
{ value: 'PUT', color: 'warning' },
|
||||||
|
{ value: 'DELETE', color: '#f50' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const infoSchema: DescItem[] = [
|
||||||
|
{
|
||||||
|
label: '日志id',
|
||||||
|
field: 'id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '链路id',
|
||||||
|
field: 'traceId',
|
||||||
|
show: (data) => data && data.traceId && data.traceId !== ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '应用名称',
|
||||||
|
field: 'applicationName',
|
||||||
|
labelMinWidth: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userId',
|
||||||
|
label: '用户id',
|
||||||
|
render(value, data) {
|
||||||
|
const tag = useRender.renderDict(data.userType, DICT_TYPE.USER_TYPE)
|
||||||
|
const uidTag = useRender.renderTag('uid: ' + value)
|
||||||
|
return h('span', {}, [tag, uidTag])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'resultCode',
|
||||||
|
label: '请求结果',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderTag(value === 0 ? '成功' : '失败', value === 0 ? '#87d068' : '#f50')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'resultMsg',
|
||||||
|
label: '响应信息',
|
||||||
|
show(data) {
|
||||||
|
return data && data.resultMsg && data.resultMsg !== ''
|
||||||
|
},
|
||||||
|
render(value) {
|
||||||
|
return h('span', { style: { color: 'red', fontWeight: 'bold' } }, value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userIp',
|
||||||
|
label: '请求ip'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userAgent',
|
||||||
|
label: 'userAgent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'beginTime',
|
||||||
|
label: '请求时间',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderDate(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'requestUrl',
|
||||||
|
label: '请求路径',
|
||||||
|
render(_, data) {
|
||||||
|
if (!data) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const { requestMethod, requestUrl } = data
|
||||||
|
const current = httpMethods.find((item) => item.value === requestMethod.toUpperCase())
|
||||||
|
const methodTag = current ? useRender.renderTag(requestMethod, current.color) : requestMethod
|
||||||
|
return h('span', {}, [methodTag, requestUrl])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'beginTime',
|
||||||
|
label: '请求开始时间',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderDate(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'endTime',
|
||||||
|
label: '请求结束时间',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderDate(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'duration',
|
||||||
|
label: '请求耗时',
|
||||||
|
render(value) {
|
||||||
|
// 为0的话需要转为string 否则不会显示
|
||||||
|
return useRender.renderText(String(value), 'ms')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -6,16 +6,32 @@
|
||||||
{{ t('action.export') }}
|
{{ t('action.export') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<TableAction
|
||||||
|
:actions="[
|
||||||
|
{
|
||||||
|
icon: IconEnum.VIEW,
|
||||||
|
label: t('action.detail'),
|
||||||
|
onClick: handleShowInfo.bind(null, record)
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
|
<AccessLogModal @register="registerModal" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useMessage } from '@/hooks/web/useMessage'
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
import { BasicTable, useTable } from '@/components/Table'
|
import { BasicTable, useTable, TableAction } from '@/components/Table'
|
||||||
import { IconEnum } from '@/enums/appEnum'
|
import { IconEnum } from '@/enums/appEnum'
|
||||||
import { getApiAccessLogPage, exportApiAccessLog, ApiAccessLogExportReqVO } from '@/api/infra/apiAccessLog'
|
import { getApiAccessLogPage, exportApiAccessLog, ApiAccessLogExportReqVO } from '@/api/infra/apiAccessLog'
|
||||||
import { columns, searchFormSchema } from './apiAccessLog.data'
|
import { columns, searchFormSchema } from './apiAccessLog.data'
|
||||||
|
import { useModal } from '@/components/Modal'
|
||||||
|
import AccessLogModal from './AccessLogModal.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'InfraApiErrorLog' })
|
defineOptions({ name: 'InfraApiErrorLog' })
|
||||||
|
|
||||||
|
@ -28,9 +44,20 @@ const [registerTable, { getForm }] = useTable({
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema },
|
formConfig: { labelWidth: 120, schemas: searchFormSchema },
|
||||||
useSearchForm: true,
|
useSearchForm: true,
|
||||||
showTableSetting: true,
|
showTableSetting: true,
|
||||||
showIndexColumn: false
|
showIndexColumn: false,
|
||||||
|
actionColumn: {
|
||||||
|
width: 120,
|
||||||
|
title: t('common.action'),
|
||||||
|
dataIndex: 'action',
|
||||||
|
fixed: 'right'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [registerModal, { openModal }] = useModal()
|
||||||
|
function handleShowInfo(record: Recordable) {
|
||||||
|
openModal(true, record)
|
||||||
|
}
|
||||||
|
|
||||||
async function handleExport() {
|
async function handleExport() {
|
||||||
createConfirm({
|
createConfirm({
|
||||||
title: t('common.exportTitle'),
|
title: t('common.exportTitle'),
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<BasicModal v-bind="$attrs" title="错误日志详情" @register="registerModalInner" @ok="closeModal" width="800px">
|
||||||
|
<Description @register="registerDescription" />
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { BasicModal, useModalInner } from '@/components/Modal'
|
||||||
|
import { Description, useDescription } from '@/components/Description/index'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { infoSchema } from './apiErrorLog.data'
|
||||||
|
|
||||||
|
defineOptions({ name: 'ErrorLogModal' })
|
||||||
|
|
||||||
|
const logData = ref()
|
||||||
|
const [registerModalInner, { closeModal }] = useModalInner((record: Recordable) => {
|
||||||
|
logData.value = record
|
||||||
|
})
|
||||||
|
|
||||||
|
const [registerDescription] = useDescription({
|
||||||
|
column: 1,
|
||||||
|
schema: infoSchema,
|
||||||
|
data: logData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -1,5 +1,8 @@
|
||||||
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||||
|
import { Textarea } from 'ant-design-vue'
|
||||||
|
import { h } from 'vue'
|
||||||
|
import { DescItem } from '@/components/Description/index'
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
|
@ -108,3 +111,139 @@ export const searchFormSchema: FormSchema[] = [
|
||||||
colProps: { span: 8 }
|
colProps: { span: 8 }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function renderText(value: string, color: string, bold = true) {
|
||||||
|
return h('span', { style: { color, fontWeight: bold ? 'bold' : 'normal' } }, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const httpMethods = [
|
||||||
|
{ value: 'GET', color: '#108ee9' },
|
||||||
|
{ value: 'POST', color: '#2db7f5' },
|
||||||
|
{ value: 'PUT', color: 'warning' },
|
||||||
|
{ value: 'DELETE', color: '#f50' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const infoSchema: DescItem[] = [
|
||||||
|
{
|
||||||
|
field: 'id',
|
||||||
|
label: '异常id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'traceId',
|
||||||
|
label: '链路ID',
|
||||||
|
show(data) {
|
||||||
|
return data && data.traceId && data.traceId !== ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'applicationName',
|
||||||
|
label: '应用名称',
|
||||||
|
labelMinWidth: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'processStatus',
|
||||||
|
label: '处理状态',
|
||||||
|
render(_, data) {
|
||||||
|
const { processStatus, processUserId } = data
|
||||||
|
const tag = useRender.renderDict(processStatus, DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS)
|
||||||
|
if (!processUserId) {
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
const uidTag = useRender.renderTag('uid: ' + processUserId)
|
||||||
|
return h('span', {}, [tag, uidTag])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'processTime',
|
||||||
|
label: '处理时间',
|
||||||
|
show(data) {
|
||||||
|
return data && data.processTime && data.processTime !== ''
|
||||||
|
},
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderDate(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userId',
|
||||||
|
label: '用户id',
|
||||||
|
render(value, data) {
|
||||||
|
const tag = useRender.renderDict(data.userType, DICT_TYPE.USER_TYPE)
|
||||||
|
const uidTag = useRender.renderTag('uid: ' + value)
|
||||||
|
return h('span', {}, [tag, uidTag])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userIp',
|
||||||
|
label: 'ip地址'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'requestUrl',
|
||||||
|
label: '请求地址',
|
||||||
|
render(_, data) {
|
||||||
|
if (data) {
|
||||||
|
const { requestMethod } = data
|
||||||
|
const current = httpMethods.find((item) => item.value === requestMethod)
|
||||||
|
const tag = current ? useRender.renderTag(requestMethod, current.color) : requestMethod
|
||||||
|
return h('span', {}, [tag, data.requestUrl])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'requestParams',
|
||||||
|
label: '请求参数',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderJsonPreview(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userAgent',
|
||||||
|
label: 'userAgent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionTime',
|
||||||
|
label: '异常时间',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderDate(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionClassName',
|
||||||
|
label: '异常类名/方法',
|
||||||
|
render(_, data) {
|
||||||
|
if (data) {
|
||||||
|
return renderText(data.exceptionClassName + ' / ' + data.exceptionMethodName, 'red')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionMessage',
|
||||||
|
label: '异常信息',
|
||||||
|
render(value) {
|
||||||
|
return renderText(value, 'red')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionFileName',
|
||||||
|
label: '异常文件名',
|
||||||
|
render(_, data) {
|
||||||
|
if (data) {
|
||||||
|
return useRender.renderText(data.exceptionFileName, 'Line: ' + data.exceptionLineNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionName',
|
||||||
|
label: '异常名称'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionRootCauseMessage',
|
||||||
|
label: '异常信息'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'exceptionStackTrace',
|
||||||
|
label: '异常堆栈',
|
||||||
|
render(value) {
|
||||||
|
return h(Textarea, { value, readonly: true, style: { minHeight: '300px' } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
<template v-if="column.key === 'action'">
|
<template v-if="column.key === 'action'">
|
||||||
<TableAction
|
<TableAction
|
||||||
:actions="[
|
:actions="[
|
||||||
|
{
|
||||||
|
icon: IconEnum.VIEW,
|
||||||
|
label: t('action.detail'),
|
||||||
|
onClick: handleShowInfo.bind(null, record)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: IconEnum.EDIT,
|
icon: IconEnum.EDIT,
|
||||||
label: '已处理',
|
label: '已处理',
|
||||||
|
@ -29,6 +34,7 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
|
<ErrorLogModal @register="registerModal" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@ -39,6 +45,8 @@ import { useMessage } from '@/hooks/web/useMessage'
|
||||||
import { BasicTable, useTable, TableAction } from '@/components/Table'
|
import { BasicTable, useTable, TableAction } from '@/components/Table'
|
||||||
import { updateApiErrorLogProcess, getApiErrorLogPage, exportApiErrorLog, ApiErrorLogExportReqVO } from '@/api/infra/apiErrorLog'
|
import { updateApiErrorLogProcess, getApiErrorLogPage, exportApiErrorLog, ApiErrorLogExportReqVO } from '@/api/infra/apiErrorLog'
|
||||||
import { columns, searchFormSchema } from './apiErrorLog.data'
|
import { columns, searchFormSchema } from './apiErrorLog.data'
|
||||||
|
import { useModal } from '@/components/Modal'
|
||||||
|
import ErrorLogModal from './ErrorLogModal.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'InfraApiErrorLog' })
|
defineOptions({ name: 'InfraApiErrorLog' })
|
||||||
|
|
||||||
|
@ -53,13 +61,18 @@ const [registerTable, { getForm, reload }] = useTable({
|
||||||
showTableSetting: true,
|
showTableSetting: true,
|
||||||
showIndexColumn: false,
|
showIndexColumn: false,
|
||||||
actionColumn: {
|
actionColumn: {
|
||||||
width: 180,
|
width: 220,
|
||||||
title: t('common.action'),
|
title: t('common.action'),
|
||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
fixed: 'right'
|
fixed: 'right'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [registerModal, { openModal }] = useModal()
|
||||||
|
function handleShowInfo(record: Recordable) {
|
||||||
|
openModal(true, record)
|
||||||
|
}
|
||||||
|
|
||||||
function handleProcessClick(record, processStatus: number, type: string) {
|
function handleProcessClick(record, processStatus: number, type: string) {
|
||||||
createConfirm({
|
createConfirm({
|
||||||
iconType: 'warning',
|
iconType: 'warning',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
import { BasicColumn, FormSchema, useRender } from '@/components/Table'
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
|
||||||
import { DescItem } from '@/components/Description/index'
|
import { DescItem } from '@/components/Description/index'
|
||||||
|
import { h } from 'vue'
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
|
@ -129,7 +130,8 @@ export const infoSchema: DescItem[] = [
|
||||||
label: '操作人',
|
label: '操作人',
|
||||||
render(_, data) {
|
render(_, data) {
|
||||||
const { userNickname, userId } = data
|
const { userNickname, userId } = data
|
||||||
return useRender.renderText(userNickname, 'uid: ' + userId)
|
// return useRender.renderText(userNickname, 'uid: ' + userId)
|
||||||
|
return useRender.renderTags([userNickname, 'uid: ' + userId])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -144,6 +146,9 @@ export const infoSchema: DescItem[] = [
|
||||||
label: '响应信息',
|
label: '响应信息',
|
||||||
show(data) {
|
show(data) {
|
||||||
return data && data.resultMsg && data.resultMsg !== ''
|
return data && data.resultMsg && data.resultMsg !== ''
|
||||||
|
},
|
||||||
|
render(value) {
|
||||||
|
return h('span', { style: { color: 'red', fontWeight: 'bold' } }, value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -159,17 +164,15 @@ export const infoSchema: DescItem[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'requestUrl',
|
field: 'requestUrl',
|
||||||
label: '请求路径'
|
label: '请求路径',
|
||||||
},
|
render(_, data) {
|
||||||
{
|
if (!data) {
|
||||||
field: 'requestMethod',
|
return ''
|
||||||
label: '请求方法',
|
|
||||||
render(value) {
|
|
||||||
const current = httpMethods.find((item) => item.value === value.toUpperCase())
|
|
||||||
if (current) {
|
|
||||||
return useRender.renderTag(value, current.color)
|
|
||||||
}
|
}
|
||||||
return value
|
const { requestMethod, requestUrl } = data
|
||||||
|
const current = httpMethods.find((item) => item.value === requestMethod.toUpperCase())
|
||||||
|
const methodTag = current ? useRender.renderTag(requestMethod, current.color) : requestMethod
|
||||||
|
return h('span', {}, [methodTag, requestUrl])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue