Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vben
commit
c9cedbf7a2
|
@ -5,6 +5,7 @@ import { isArray, isString } from '@/utils/is'
|
||||||
import { DictTag } from '@/components/DictTag'
|
import { DictTag } from '@/components/DictTag'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
import TableImg from '../components/TableImg.vue'
|
import TableImg from '../components/TableImg.vue'
|
||||||
|
import { JsonPreview } from '@/components/CodeEditor'
|
||||||
|
|
||||||
export const useRender = {
|
export const useRender = {
|
||||||
/**
|
/**
|
||||||
|
@ -112,5 +113,24 @@ export const useRender = {
|
||||||
if (text) {
|
if (text) {
|
||||||
return h(Icon, { icon: text })
|
return h(Icon, { icon: text })
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 使用JsonPreview组件 方便预览JSON
|
||||||
|
* @param json json字符串/obj
|
||||||
|
* @returns 能转为json返回JsonPreview 否则返回自身
|
||||||
|
*/
|
||||||
|
renderJsonPreview: (json: any) => {
|
||||||
|
if (!json) return ''
|
||||||
|
if (typeof json === 'object') {
|
||||||
|
return h(JsonPreview, { data: json })
|
||||||
|
}
|
||||||
|
if (typeof json === 'string') {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(json)
|
||||||
|
return h(JsonPreview, { data })
|
||||||
|
} catch (e) {
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,110 @@ 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: 'requestParams',
|
||||||
|
label: '请求参数',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderJsonPreview(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,74 @@
|
||||||
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'
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
label: '无'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'processing',
|
||||||
|
label: '主要'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'success',
|
||||||
|
label: '成功'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'default',
|
||||||
|
label: '默认'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'warning',
|
||||||
|
label: '警告'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'error',
|
||||||
|
label: '危险'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'pink',
|
||||||
|
label: 'pink'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'red',
|
||||||
|
label: 'red'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'orange',
|
||||||
|
label: 'orange'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'green',
|
||||||
|
label: 'green'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'cyan',
|
||||||
|
label: 'cyan'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'blue',
|
||||||
|
label: 'blue'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'purple',
|
||||||
|
label: 'purple'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function previewOptions() {
|
||||||
|
return options.map((option) => {
|
||||||
|
const { value, label } = option
|
||||||
|
if (value === '') {
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
label: useRender.renderTag(label, value),
|
||||||
|
value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const dataColumns: BasicColumn[] = [
|
export const dataColumns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
title: '字典编码',
|
title: '字典编码',
|
||||||
|
@ -119,67 +187,15 @@ export const dataFormSchema: FormSchema[] = [
|
||||||
field: 'colorType',
|
field: 'colorType',
|
||||||
component: 'Select',
|
component: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
options: [
|
options: previewOptions()
|
||||||
{
|
|
||||||
value: '',
|
|
||||||
label: '空'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'processing',
|
|
||||||
label: '主要'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'success',
|
|
||||||
label: '成功'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'default',
|
|
||||||
label: '默认'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'warning',
|
|
||||||
label: '警告'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'error',
|
|
||||||
label: '危险'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'pink',
|
|
||||||
label: 'pink'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'red',
|
|
||||||
label: 'red'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'orange',
|
|
||||||
label: 'orange'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'green',
|
|
||||||
label: 'green'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'cyan',
|
|
||||||
label: 'cyan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'blue',
|
|
||||||
label: 'blue'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'purple',
|
|
||||||
label: 'purple'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'CSS Class',
|
label: 'CSS Class',
|
||||||
field: 'cssClass',
|
field: 'cssClass',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
helpMessage: '输入hex模式的颜色,例如#108ee9'
|
helpMessage: '输入hex模式的颜色, 例如#108ee9',
|
||||||
|
rules: [{ required: false, message: '输入正确的16进制颜色', pattern: /^#([0-9a-fA-F]{3}){1,2}$/, trigger: 'blur' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '备注',
|
label: '备注',
|
||||||
|
|
|
@ -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 './operateLog.data'
|
||||||
|
|
||||||
|
defineOptions({ name: 'OperLogInfoModal' })
|
||||||
|
|
||||||
|
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>
|
|
@ -4,16 +4,32 @@
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<a-button type="warning" :preIcon="IconEnum.EXPORT" @click="handleExport"> {{ t('action.export') }} </a-button>
|
<a-button type="warning" :preIcon="IconEnum.EXPORT" @click="handleExport"> {{ t('action.export') }} </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>
|
||||||
|
<OperLogInfoModal @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 { IconEnum } from '@/enums/appEnum'
|
import { IconEnum } from '@/enums/appEnum'
|
||||||
import { BasicTable, useTable } from '@/components/Table'
|
import { BasicTable, useTable, TableAction } from '@/components/Table'
|
||||||
import { OperateLogPageReqVO, exportOperateLog, getOperateLogPage } from '@/api/system/operatelog'
|
import { OperateLogPageReqVO, exportOperateLog, getOperateLogPage } from '@/api/system/operatelog'
|
||||||
import { columns, searchFormSchema } from './operateLog.data'
|
import { columns, searchFormSchema } from './operateLog.data'
|
||||||
|
import { useModal } from '@/components/Modal'
|
||||||
|
import OperLogInfoModal from './LogInfoModal.vue'
|
||||||
|
|
||||||
defineOptions({ name: 'SystemOperateLog' })
|
defineOptions({ name: 'SystemOperateLog' })
|
||||||
|
|
||||||
|
@ -26,7 +42,13 @@ 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: 140,
|
||||||
|
title: t('common.action'),
|
||||||
|
dataIndex: 'action',
|
||||||
|
fixed: 'right'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function handleExport() {
|
async function handleExport() {
|
||||||
|
@ -40,4 +62,9 @@ async function handleExport() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [registerModal, { openModal }] = useModal()
|
||||||
|
function handleShowInfo(record: Recordable) {
|
||||||
|
openModal(true, record)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -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[] = [
|
||||||
{
|
{
|
||||||
|
@ -10,7 +12,7 @@ export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
title: '操作模块',
|
title: '操作模块',
|
||||||
dataIndex: 'module',
|
dataIndex: 'module',
|
||||||
width: 120
|
width: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作名',
|
title: '操作名',
|
||||||
|
@ -20,7 +22,7 @@ export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
title: '操作类型',
|
title: '操作类型',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
width: 180,
|
width: 120,
|
||||||
customRender: ({ text }) => {
|
customRender: ({ text }) => {
|
||||||
return useRender.renderDict(text, DICT_TYPE.SYSTEM_OPERATE_TYPE)
|
return useRender.renderDict(text, DICT_TYPE.SYSTEM_OPERATE_TYPE)
|
||||||
}
|
}
|
||||||
|
@ -30,10 +32,14 @@ export const columns: BasicColumn[] = [
|
||||||
dataIndex: 'userNickname',
|
dataIndex: 'userNickname',
|
||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// title: 'userAgent',
|
||||||
|
// dataIndex: 'userAgent',
|
||||||
|
// width: 400
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
title: 'userAgent',
|
title: '请求路径',
|
||||||
dataIndex: 'userAgent',
|
dataIndex: 'requestUrl'
|
||||||
width: 400
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作结果',
|
title: '操作结果',
|
||||||
|
@ -43,14 +49,6 @@ export const columns: BasicColumn[] = [
|
||||||
return useRender.renderTag(text === 0 ? '成功' : '失败', text === 0 ? '#87d068' : '#f50')
|
return useRender.renderTag(text === 0 ? '成功' : '失败', text === 0 ? '#87d068' : '#f50')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: '操作日期',
|
|
||||||
dataIndex: 'startTime',
|
|
||||||
width: 180,
|
|
||||||
customRender: ({ text }) => {
|
|
||||||
return useRender.renderDate(text)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '执行时长',
|
title: '执行时长',
|
||||||
dataIndex: 'duration',
|
dataIndex: 'duration',
|
||||||
|
@ -58,6 +56,14 @@ export const columns: BasicColumn[] = [
|
||||||
customRender: ({ text }) => {
|
customRender: ({ text }) => {
|
||||||
return useRender.renderText(text, 'ms')
|
return useRender.renderText(text, 'ms')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作日期',
|
||||||
|
dataIndex: 'startTime',
|
||||||
|
width: 180,
|
||||||
|
customRender: ({ text }) => {
|
||||||
|
return useRender.renderDate(text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -102,3 +108,94 @@ 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[] = [
|
||||||
|
{
|
||||||
|
field: 'module',
|
||||||
|
label: '操作模块'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
label: '操作名'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userNickname',
|
||||||
|
label: '操作人',
|
||||||
|
render(_, data) {
|
||||||
|
const { userNickname, userId } = data
|
||||||
|
// return useRender.renderText(userNickname, 'uid: ' + userId)
|
||||||
|
return useRender.renderTags([userNickname, 'uid: ' + userId])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: 'startTime',
|
||||||
|
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: 'javaMethod',
|
||||||
|
label: '操作方法',
|
||||||
|
labelMinWidth: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'javaMethodArgs',
|
||||||
|
label: '请求参数',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderJsonPreview(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'userAgent',
|
||||||
|
label: 'userAgent'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'duration',
|
||||||
|
label: '请求耗时',
|
||||||
|
render(value) {
|
||||||
|
return useRender.renderText(value, 'ms')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
Loading…
Reference in New Issue