13 changed files with 627 additions and 5 deletions
@ -0,0 +1,15 @@ |
|||
<script lang="ts" setup> |
|||
import { Page } from '@vben/common-ui'; |
|||
|
|||
import { LoggingTable } from '@abp/auditing'; |
|||
|
|||
defineOptions({ |
|||
name: 'AuditingLoggings', |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
<Page> |
|||
<LoggingTable /> |
|||
</Page> |
|||
</template> |
|||
@ -1,2 +1,3 @@ |
|||
export { useAuditLogsApi } from './useAuditLogsApi'; |
|||
export { useEntityChangesApi } from './useEntityChangesApi'; |
|||
export { useLoggingsApi } from './useLoggingsApi'; |
|||
|
|||
@ -0,0 +1,38 @@ |
|||
import type { PagedResultDto } from '@abp/core'; |
|||
|
|||
import type { LogDto, LogGetListInput } from '../types/loggings'; |
|||
|
|||
import { useRequest } from '@abp/request'; |
|||
|
|||
export function useLoggingsApi() { |
|||
const { cancel, request } = useRequest(); |
|||
|
|||
/** |
|||
* 获取系统日志 |
|||
* @param id 日志id |
|||
*/ |
|||
function getApi(id: string): Promise<LogDto> { |
|||
return request<LogDto>(`/api/auditing/logging/${id}`, { |
|||
method: 'GET', |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 获取系统日志分页列表 |
|||
* @param input 参数 |
|||
*/ |
|||
function getPagedListApi( |
|||
input: LogGetListInput, |
|||
): Promise<PagedResultDto<LogDto>> { |
|||
return request<PagedResultDto<LogDto>>('/api/auditing/logging', { |
|||
method: 'GET', |
|||
params: input, |
|||
}); |
|||
} |
|||
|
|||
return { |
|||
cancel, |
|||
getApi, |
|||
getPagedListApi, |
|||
}; |
|||
} |
|||
@ -1,2 +1,3 @@ |
|||
export { default as AuditLogTable } from './audit-logs/AuditLogTable.vue'; |
|||
export { default as EntityChangeDrawer } from './entity-changes/EntityChangeDrawer.vue'; |
|||
export { default as LoggingTable } from './loggings/LoggingTable.vue'; |
|||
|
|||
@ -0,0 +1,138 @@ |
|||
<script setup lang="ts"> |
|||
import type { LogDto, LogLevel } from '../../types/loggings'; |
|||
|
|||
import { ref } from 'vue'; |
|||
|
|||
import { useVbenDrawer } from '@vben/common-ui'; |
|||
import { $t } from '@vben/locales'; |
|||
|
|||
import { formatToDateTime } from '@abp/core'; |
|||
import { Descriptions, Tabs, Tag } from 'ant-design-vue'; |
|||
|
|||
import { useLoggingsApi } from '../../api/useLoggingsApi'; |
|||
|
|||
defineOptions({ |
|||
name: 'LoggingDrawer', |
|||
}); |
|||
|
|||
defineProps<{ |
|||
logLevelOptions: { color: string; label: string; value: LogLevel }[]; |
|||
}>(); |
|||
const TabPane = Tabs.TabPane; |
|||
const DescriptionsItem = Descriptions.Item; |
|||
|
|||
const activedTab = ref('basic'); |
|||
const logModel = ref<LogDto>({} as LogDto); |
|||
|
|||
const { getApi } = useLoggingsApi(); |
|||
const [Drawer, drawerApi] = useVbenDrawer({ |
|||
class: 'w-auto', |
|||
onCancel() { |
|||
drawerApi.close(); |
|||
}, |
|||
onConfirm: async () => { |
|||
drawerApi.close(); |
|||
}, |
|||
onOpenChange: async (isOpen: boolean) => { |
|||
if (isOpen) { |
|||
try { |
|||
logModel.value = {} as LogDto; |
|||
drawerApi.setState({ loading: true }); |
|||
const dto = drawerApi.getData<LogDto>(); |
|||
await onGet(dto.fields.id); |
|||
} finally { |
|||
drawerApi.setState({ loading: false }); |
|||
} |
|||
} |
|||
}, |
|||
title: $t('AbpAuditLogging.AuditLog'), |
|||
}); |
|||
async function onGet(id: string) { |
|||
const dto = await getApi(id); |
|||
logModel.value = dto; |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<Drawer> |
|||
<div style="width: 800px"> |
|||
<Tabs v-model="activedTab"> |
|||
<TabPane key="basic" :tab="$t('AbpAuditLogging.Operation')"> |
|||
<Descriptions |
|||
:colon="false" |
|||
:column="1" |
|||
bordered |
|||
size="small" |
|||
:label-style="{ minWidth: '110px' }" |
|||
> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.TimeStamp')"> |
|||
{{ formatToDateTime(logModel.timeStamp) }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.Level')"> |
|||
<Tag :color="logLevelOptions[logModel.level]?.color"> |
|||
{{ logLevelOptions[logModel.level]?.label }} |
|||
</Tag> |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.Message')" :span="2"> |
|||
{{ logModel.message }} |
|||
</DescriptionsItem> |
|||
</Descriptions> |
|||
</TabPane> |
|||
<TabPane key="fields" :tab="$t('AbpAuditLogging.Fields')"> |
|||
<Descriptions |
|||
:colon="false" |
|||
:column="1" |
|||
bordered |
|||
size="small" |
|||
:label-style="{ minWidth: '110px' }" |
|||
> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ApplicationName')"> |
|||
{{ logModel.fields.application }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.MachineName')"> |
|||
{{ logModel.fields.machineName }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.Environment')"> |
|||
{{ logModel.fields.environment }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ProcessId')"> |
|||
{{ logModel.fields.processId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ThreadId')"> |
|||
{{ logModel.fields.threadId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.Context')"> |
|||
{{ logModel.fields.context }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ActionId')"> |
|||
{{ logModel.fields.actionId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.MethodName')"> |
|||
{{ logModel.fields.actionName }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.RequestId')"> |
|||
{{ logModel.fields.requestId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.RequestPath')"> |
|||
{{ logModel.fields.requestPath }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ConnectionId')"> |
|||
{{ logModel.fields.connectionId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.CorrelationId')"> |
|||
{{ logModel.fields.correlationId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.ClientId')"> |
|||
{{ logModel.fields.clientId }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem :label="$t('AbpAuditLogging.UserId')"> |
|||
{{ logModel.fields.userId }} |
|||
</DescriptionsItem> |
|||
</Descriptions> |
|||
</TabPane> |
|||
</Tabs> |
|||
</div> |
|||
</Drawer> |
|||
</template> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,345 @@ |
|||
<script setup lang="ts"> |
|||
import type { SortOrder } from '@abp/core'; |
|||
import type { VxeGridListeners, VxeGridProps } from '@abp/ui'; |
|||
|
|||
import type { VbenFormProps } from '@vben/common-ui'; |
|||
|
|||
import type { LogDto } from '../../types/loggings'; |
|||
|
|||
import { defineAsyncComponent, h, reactive, ref } from 'vue'; |
|||
|
|||
import { useVbenDrawer } from '@vben/common-ui'; |
|||
import { $t } from '@vben/locales'; |
|||
|
|||
import { formatToDateTime } from '@abp/core'; |
|||
import { useVbenVxeGrid } from '@abp/ui'; |
|||
import { EditOutlined } from '@ant-design/icons-vue'; |
|||
import { Button, Tag } from 'ant-design-vue'; |
|||
|
|||
import { useLoggingsApi } from '../../api/useLoggingsApi'; |
|||
import { SystemLogPermissions } from '../../constants/permissions'; |
|||
import { LogLevel } from '../../types/loggings'; |
|||
|
|||
defineOptions({ |
|||
name: 'LoggingTable', |
|||
}); |
|||
const { getPagedListApi } = useLoggingsApi(); |
|||
|
|||
const selectedKeys = ref<string[]>([]); |
|||
const logLevelOptions = reactive([ |
|||
{ |
|||
color: 'purple', |
|||
label: 'Trace', |
|||
value: LogLevel.Trace, |
|||
}, |
|||
{ |
|||
color: 'blue', |
|||
label: 'Debug', |
|||
value: LogLevel.Debug, |
|||
}, |
|||
{ |
|||
color: 'green', |
|||
label: 'Information', |
|||
value: LogLevel.Information, |
|||
}, |
|||
{ |
|||
color: 'orange', |
|||
label: 'Warning', |
|||
value: LogLevel.Warning, |
|||
}, |
|||
{ |
|||
color: 'red', |
|||
label: 'Error', |
|||
value: LogLevel.Error, |
|||
}, |
|||
{ |
|||
color: '#f50', |
|||
label: 'Critical', |
|||
value: LogLevel.Critical, |
|||
}, |
|||
{ |
|||
color: '', |
|||
label: 'None', |
|||
value: LogLevel.None, |
|||
}, |
|||
]); |
|||
const formOptions: VbenFormProps = { |
|||
// 默认展开 |
|||
collapsed: true, |
|||
collapsedRows: 2, |
|||
fieldMappingTime: [ |
|||
[ |
|||
'timeStamp', |
|||
['startTime', 'endTime'], |
|||
['YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss'], |
|||
], |
|||
], |
|||
schema: [ |
|||
{ |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: logLevelOptions, |
|||
}, |
|||
fieldName: 'level', |
|||
label: $t('AbpAuditLogging.Level'), |
|||
}, |
|||
{ |
|||
component: 'RangePicker', |
|||
componentProps: { |
|||
showTime: true, |
|||
}, |
|||
fieldName: 'timeStamp', |
|||
formItemClass: 'col-span-2 items-baseline', |
|||
label: $t('AbpAuditLogging.TimeStamp'), |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'application', |
|||
label: $t('AbpAuditLogging.ApplicationName'), |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'machineName', |
|||
label: $t('AbpAuditLogging.MachineName'), |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'environment', |
|||
label: $t('AbpAuditLogging.Environment'), |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'requestId', |
|||
formItemClass: 'col-span-2 items-baseline', |
|||
label: $t('AbpAuditLogging.RequestId'), |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'requestPath', |
|||
formItemClass: 'col-span-2 items-baseline', |
|||
label: $t('AbpAuditLogging.RequestPath'), |
|||
labelWidth: 150, |
|||
}, |
|||
{ |
|||
component: 'Input', |
|||
fieldName: 'correlationId', |
|||
formItemClass: 'col-span-2 items-baseline', |
|||
label: $t('AbpAuditLogging.CorrelationId'), |
|||
}, |
|||
{ |
|||
component: 'Checkbox', |
|||
componentProps: { |
|||
render: () => { |
|||
return h('span', $t('AbpAuditLogging.HasException')); |
|||
}, |
|||
}, |
|||
fieldName: 'hasException', |
|||
label: $t('AbpAuditLogging.HasException'), |
|||
}, |
|||
], |
|||
// 控制表单是否显示折叠按钮 |
|||
showCollapseButton: true, |
|||
// 按下回车时是否提交表单 |
|||
submitOnEnter: true, |
|||
wrapperClass: 'grid-cols-4', |
|||
}; |
|||
|
|||
const gridOptions: VxeGridProps<LogDto> = { |
|||
columns: [ |
|||
{ |
|||
align: 'left', |
|||
field: 'applicationName', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.application; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.ApplicationName'), |
|||
width: 150, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'timeStamp', |
|||
formatter: ({ cellValue }) => { |
|||
return cellValue ? formatToDateTime(cellValue) : cellValue; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.TimeStamp'), |
|||
width: 150, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'level', |
|||
slots: { default: 'level' }, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.Level'), |
|||
width: 120, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'message', |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.Message'), |
|||
width: 500, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'machineName', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.machineName; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.MachineName'), |
|||
width: 140, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'environment', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.environment; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.Environment'), |
|||
width: 150, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'requestId', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.requestId; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.RequestId'), |
|||
width: 200, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'requestPath', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.requestPath; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.RequestPath'), |
|||
width: 300, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'connectionId', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.connectionId; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.ConnectionId'), |
|||
width: 150, |
|||
}, |
|||
{ |
|||
align: 'left', |
|||
field: 'correlationId', |
|||
formatter: ({ row }) => { |
|||
return row.fields?.correlationId; |
|||
}, |
|||
sortable: true, |
|||
title: $t('AbpAuditLogging.CorrelationId'), |
|||
width: 240, |
|||
}, |
|||
{ |
|||
field: 'action', |
|||
fixed: 'right', |
|||
slots: { default: 'action' }, |
|||
title: $t('AbpUi.Actions'), |
|||
width: 180, |
|||
}, |
|||
], |
|||
exportConfig: {}, |
|||
keepSource: true, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: async ({ page }, formValues) => { |
|||
return await getPagedListApi({ |
|||
maxResultCount: page.pageSize, |
|||
skipCount: (page.currentPage - 1) * page.pageSize, |
|||
...formValues, |
|||
}); |
|||
}, |
|||
}, |
|||
response: { |
|||
total: 'totalCount', |
|||
list: 'items', |
|||
}, |
|||
}, |
|||
sortConfig: { |
|||
remote: true, |
|||
}, |
|||
toolbarConfig: { |
|||
custom: true, |
|||
export: true, |
|||
// import: true, |
|||
refresh: true, |
|||
zoom: true, |
|||
}, |
|||
}; |
|||
|
|||
const gridEvents: VxeGridListeners<LogDto> = { |
|||
checkboxAll: (params) => { |
|||
selectedKeys.value = params.records.map((x) => x.fields.id); |
|||
}, |
|||
checkboxChange: (params) => { |
|||
selectedKeys.value = params.records.map((x) => x.fields.id); |
|||
}, |
|||
sortChange: onSort, |
|||
}; |
|||
|
|||
const [Grid, gridApi] = useVbenVxeGrid({ |
|||
formOptions, |
|||
gridEvents, |
|||
gridOptions, |
|||
}); |
|||
const [LoggingDrawer, logDrawerApi] = useVbenDrawer({ |
|||
connectedComponent: defineAsyncComponent(() => import('./LoggingDrawer.vue')), |
|||
}); |
|||
|
|||
function onUpdate(row: LogDto) { |
|||
logDrawerApi.setData(row); |
|||
logDrawerApi.open(); |
|||
} |
|||
|
|||
function onSort(params: { field: string; order: SortOrder }) { |
|||
const sorting = params.order ? `${params.field} ${params.order}` : undefined; |
|||
gridApi.query({ sorting }); |
|||
} |
|||
|
|||
function onFilter(field: string, value: any) { |
|||
gridApi.formApi.setFieldValue(field, value); |
|||
gridApi.formApi.validateAndSubmitForm(); |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<Grid :table-title="$t('AbpAuditLogging.Logging')"> |
|||
<template #level="{ row }"> |
|||
<Tag :color="logLevelOptions[row.level]?.color"> |
|||
<a |
|||
class="link" |
|||
href="javaScript:void(0);" |
|||
@click="onFilter('level', row.level)" |
|||
>{{ logLevelOptions[row.level]?.label }} |
|||
</a> |
|||
</Tag> |
|||
</template> |
|||
<template #action="{ row }"> |
|||
<div class="flex flex-row"> |
|||
<Button |
|||
:icon="h(EditOutlined)" |
|||
block |
|||
type="link" |
|||
v-access:code="[SystemLogPermissions.Default]" |
|||
@click="onUpdate(row)" |
|||
> |
|||
{{ $t('AbpAuditLogging.ShowLogDialog') }} |
|||
</Button> |
|||
</div> |
|||
</template> |
|||
</Grid> |
|||
<LoggingDrawer :log-level-options="logLevelOptions" /> |
|||
</template> |
|||
|
|||
<style lang="scss" scoped></style> |
|||
@ -1,2 +1,3 @@ |
|||
export * from './audit-logs'; |
|||
export * from './entity-changes'; |
|||
export * from './loggings'; |
|||
|
|||
@ -0,0 +1,65 @@ |
|||
interface LogExceptionDto { |
|||
class?: string; |
|||
depth?: number; |
|||
helpUrl?: string; |
|||
hResult?: number; |
|||
message?: string; |
|||
source?: string; |
|||
stackTrace?: string; |
|||
} |
|||
|
|||
interface LogFieldDto { |
|||
actionId?: string; |
|||
actionName?: string; |
|||
application?: string; |
|||
clientId?: string; |
|||
connectionId?: string; |
|||
context?: string; |
|||
correlationId?: string; |
|||
environment?: string; |
|||
id: string; |
|||
machineName?: string; |
|||
processId?: number; |
|||
requestId?: string; |
|||
requestPath?: string; |
|||
threadId?: number; |
|||
userId?: string; |
|||
} |
|||
|
|||
enum LogLevel { |
|||
Critical = 5, |
|||
Debug = 1, |
|||
Error = 4, |
|||
Information = 2, |
|||
None = 6, |
|||
Trace = 0, |
|||
Warning = 3, |
|||
} |
|||
|
|||
interface LogDto { |
|||
exceptions: LogExceptionDto[]; |
|||
fields: LogFieldDto; |
|||
level: LogLevel; |
|||
message: string; |
|||
timeStamp: Date; |
|||
} |
|||
|
|||
interface LogGetListInput { |
|||
application?: string; |
|||
context?: string; |
|||
correlationId?: string; |
|||
endTime?: Date; |
|||
environment?: string; |
|||
hasException?: boolean; |
|||
level?: LogLevel; |
|||
machineName?: string; |
|||
processId?: number; |
|||
requestId?: string; |
|||
requestPath?: string; |
|||
startTime?: Date; |
|||
threadId?: number; |
|||
} |
|||
|
|||
export type { LogDto, LogExceptionDto, LogFieldDto, LogGetListInput }; |
|||
|
|||
export { LogLevel }; |
|||
Loading…
Reference in new issue