Browse Source

optional tracking entity changed

pull/96/head
cKey 5 years ago
parent
commit
c71a2a5a89
  1. 2
      aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
  2. 14
      aspnet-core/services/admin/LINGYUN.Abp.BackendAdmin.HttpApi.Host/BackendAdminHostModule.cs
  3. 14
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
  4. 13
      aspnet-core/services/identity-server/LINGYUN.Abp.IdentityServer4.HttpApi.Host/AbpIdentityServerAdminHttpApiHostModule.cs
  5. 14
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs
  6. 10
      vueJs/src/api/auditing.ts
  7. 137
      vueJs/src/views/admin/auditing/audit-log/components/AuditLogProfile.vue
  8. 31
      vueJs/src/views/admin/auditing/audit-log/index.vue

2
aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs

@ -140,7 +140,7 @@ namespace AuthServer.Host
Configure<AbpAuditingOptions>(options =>
{
// options.IsEnabledForGetRequests = true;
options.ApplicationName = "AuthServer";
options.ApplicationName = "Identity-Server-STS";
});
Configure<AppUrlOptions>(options =>

14
aspnet-core/services/admin/LINGYUN.Abp.BackendAdmin.HttpApi.Host/BackendAdminHostModule.cs

@ -28,6 +28,7 @@ using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
@ -209,6 +210,19 @@ namespace LINGYUN.Abp.BackendAdmin
options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Backend-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
// Swagger
context.Services.AddSwaggerGen(
options =>

14
aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs

@ -16,6 +16,7 @@ using System;
using System.Text;
using Volo.Abp;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
@ -122,6 +123,19 @@ namespace LINGYUN.ApiGateway
options.IsEnabled = false;
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "ApiGateWay-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
//Configure<AbpTenantResolveOptions>(options =>
//{
// options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());

13
aspnet-core/services/identity-server/LINGYUN.Abp.IdentityServer4.HttpApi.Host/AbpIdentityServerAdminHttpApiHostModule.cs

@ -24,6 +24,7 @@ using Volo.Abp.Account;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
@ -150,6 +151,18 @@ namespace LINGYUN.Abp.IdentityServer4
options.DefaultReceiveEmail = "colin.in@foxmail.com";
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Identity-Server-Admin";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
Configure<AbpDistributedCacheOptions>(options =>
{

14
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs

@ -26,6 +26,7 @@ using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.Auditing;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac;
using Volo.Abp.BlobStoring;
@ -184,6 +185,19 @@ namespace LINGYUN.Platform
options.IsEnabled = true;
});
Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "Platform";
// 是否启用实体变更记录
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged");
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>())
{
options
.EntityHistorySelectors
.AddAllEntities();
}
});
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor());

10
vueJs/src/api/auditing.ts

@ -82,6 +82,12 @@ export class SecurityLog {
extraProperties?: {[key: string]: any}
}
export enum ChangeType {
Created = 0,
Updated = 1,
Deleted = 2
}
export class PropertyChange {
id!: string
newValue?: string
@ -93,7 +99,7 @@ export class PropertyChange {
export class EntityChange {
id!: string
changeTime?: Date
changeType?: number
changeType?: ChangeType
entityTenantId?: string
entityId?: string
entityTypeFullName?: string
@ -106,7 +112,7 @@ export class Action {
serviceName?: string
methodName?: string
parameters?: string
executionTime?: Date
executionTime!: Date
executionDuration?: number
extraProperties?: {[key: string]: any}
}

137
vueJs/src/views/admin/auditing/audit-log/components/AuditLogProfile.vue

@ -136,7 +136,7 @@
v-for="(action, index) in getActions"
:key="index"
:timestamp="getFormatDateTime(action.executionTime)"
:type="auditLog.httpStatusCode | httpStatusCodeFilter"
:type="auditLog.httpStatusCode | httpStatusCodeTimelineFilter"
placement="top"
>
<el-card>
@ -167,6 +167,100 @@
</el-timeline-item>
</el-timeline>
</el-tab-pane>
<el-tab-pane
v-if="getEntitiesChanges.length > 0"
label="实体变更"
name="entitiesChanged"
style="height:300px;overflow-y:auto;overflow-x:hidden;"
>
<el-timeline>
<el-timeline-item
v-for="(entity, index) in getEntitiesChanges"
:key="index"
:timestamp="getFormatDateTime(entity.changeTime)"
:type="entity.changeType | entityChangeTypeTimelineFilter"
placement="top"
>
<el-card>
<el-form-item label="变更类型">
<el-input
:value="entity.changeType | entityChangeTypeNameFilter"
readonly
/>
</el-form-item>
<el-form-item label="实体类型">
<el-input
v-model="entity.entityTypeFullName"
readonly
/>
</el-form-item>
<el-form-item label="实体标识">
<el-input
v-model="entity.entityId"
readonly
/>
</el-form-item>
<el-form-item label="租户标识">
<el-input
v-model="entity.entityTenantId"
readonly
/>
</el-form-item>
<el-form-item label="属性变更">
<el-table
row-key="id"
:data="entity.propertyChanges"
border
fit
highlight-current-row
style="width: 100%;"
>
<el-table-column
label="属性名称"
prop="propertyName"
sortable
width="200px"
>
<template slot-scope="{row}">
<span>{{ row.propertyName }}</span>
</template>
</el-table-column>
<el-table-column
label="当前值"
prop="newValue"
sortable
width="320px"
>
<template slot-scope="{row}">
<span>{{ row.newValue }}</span>
</template>
</el-table-column>
<el-table-column
label="原始值"
prop="originalValue"
sortable
width="320px"
>
<template slot-scope="{row}">
<span>{{ row.originalValue }}</span>
</template>
</el-table-column>
<el-table-column
label="属性类型"
prop="propertyTypeFullName"
sortable
width="500px"
>
<template slot-scope="{row}">
<span>{{ row.propertyTypeFullName }}</span>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-card>
</el-timeline-item>
</el-timeline>
</el-tab-pane>
<el-tab-pane
v-if="hasException"
label="异常信息"
@ -204,17 +298,28 @@
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import AuditingService, { Action, AuditLog } from '@/api/auditing'
import AuditingService, { Action, AuditLog, EntityChange, ChangeType } from '@/api/auditing'
import { dateFormat } from '@/utils'
import JsonEditor from '@/components/JsonEditor/index.vue'
const entityChangeTypeNameMap: { [key: number]: string } = {
[ChangeType.Created]: '新增',
[ChangeType.Updated]: '修改',
[ChangeType.Deleted]: '删除'
}
const entityChangeTypeTimelineMap: { [key: number]: string } = {
[ChangeType.Created]: 'success',
[ChangeType.Updated]: 'warning',
[ChangeType.Deleted]: 'danger'
}
@Component({
name: 'AuditLogProfile',
components: {
JsonEditor
},
filters: {
httpStatusCodeFilter(httpStatusCode: number) {
httpStatusCodeTimelineFilter(httpStatusCode: number) {
if (httpStatusCode >= 200 && httpStatusCode < 300) {
return 'success'
}
@ -225,6 +330,12 @@ import JsonEditor from '@/components/JsonEditor/index.vue'
return 'danger'
}
return 'primary'
},
entityChangeTypeNameFilter(type: ChangeType) {
return entityChangeTypeNameMap[type]
},
entityChangeTypeTimelineFilter(type: ChangeType) {
return entityChangeTypeTimelineMap[type]
}
},
computed: {
@ -276,10 +387,28 @@ export default class extends Vue {
get getActions() {
if (this.auditLog.actions && this.auditLog.actions.length > 0) {
return this.auditLog.actions.reverse()
return this.sortByDateTime(this.auditLog.actions, 'executionTime')
}
return new Array<Action>()
}
get getEntitiesChanges() {
if (this.auditLog.entityChanges && this.auditLog.entityChanges.length > 0) {
return this.sortByDateTime(this.auditLog.entityChanges, 'changeTime')
}
return new Array<EntityChange>()
}
private sortByDateTime(array: Array<any>, sortField: string) {
return array.sort((obj1, obj2) => {
if (obj1[sortField] && obj2[sortField]) {
const time1 = new Date(obj1[sortField])
const time2 = new Date(obj2[sortField])
return time1.getTime() - time2.getTime()
}
return 0
})
}
}
</script>

31
vueJs/src/views/admin/auditing/audit-log/index.vue

@ -157,6 +157,21 @@
</el-tag>
</template>
</el-table-column>
<el-table-column
label="响应时间"
prop="executionDuration"
sortable
width="130px"
align="center"
>
<template slot-scope="{row}">
<el-tag
:type="row.executionDuration | executionDurationFilter"
>
{{ row.executionDuration }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="状态码"
prop="httpStatusCode"
@ -312,6 +327,20 @@ const statusMap: { [key: string]: string } = {
return 'danger'
}
return ''
},
executionDurationFilter(executionDuration: number) {
if (executionDuration < 100) {
return 'success'
}
if (executionDuration < 500) {
return 'primary'
}
if (executionDuration < 1000) {
return 'warning'
}
if (executionDuration > 1000) {
return 'danger'
}
}
},
methods: {
@ -361,7 +390,7 @@ export default class extends mixins(DataListMiXin) {
}
</script>
<style lang="scss" scoped>
<style lang="scss">
.data-filter-collapse-title {
font-size: 15px;
}

Loading…
Cancel
Save