Browse Source

feat:

添加启用禁用用户
添加审计日志模块
old-3.0 4.3.0.3
王军 5 years ago
parent
commit
88309105f3
  1. 3
      content/aspnetcore/host/CompanyName.ProjectName.HttpApi.Host/CompanyNameProjectNameHttpApiHostModule.cs
  2. 15
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryAuditLogInput.cs
  3. 123
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryAuditLogOutput.cs
  4. 11
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryEntityChangeInput.cs
  5. 107
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryEntityChangeOutput.cs
  6. 6
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Permissions/CompanyNameProjectNamePermissionDefinitionProvider.cs
  7. 16
      content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Users/Dtos/LockUserInput.cs
  8. 69
      content/aspnetcore/src/CompanyName.ProjectName.Application/Audits/AuditAppService.cs
  9. 12
      content/aspnetcore/src/CompanyName.ProjectName.Application/CompanyNameProjectNameApplicationAutoMapperProfile.cs
  10. 1
      content/aspnetcore/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs
  11. 24
      content/aspnetcore/src/CompanyName.ProjectName.Application/Users/UserAppService.cs
  12. 6
      content/aspnetcore/src/CompanyName.ProjectName.Domain.Shared/Localization/CompanyNameProjectName/en.json
  13. 5
      content/aspnetcore/src/CompanyName.ProjectName.Domain.Shared/Localization/CompanyNameProjectName/zh-Hans.json
  14. 4
      content/vue/package.json
  15. 16
      content/vue/src/locales/lang/en/routes/admin.ts
  16. 15
      content/vue/src/locales/lang/zh_CN/routes/admin.ts
  17. 4
      content/vue/src/main.ts
  18. 10
      content/vue/src/router/menus/modules/admin.ts
  19. 11
      content/vue/src/router/routes/modules/admin.ts
  20. 837
      content/vue/src/services/ServiceProxies.ts
  21. 91
      content/vue/src/views/admin/audits/AuditLog.vue
  22. 296
      content/vue/src/views/admin/audits/audit.ts
  23. 1
      content/vue/src/views/admin/roles/AbpRole.ts
  24. 18
      content/vue/src/views/admin/users/AbpUser.ts
  25. 35
      content/vue/src/views/admin/users/AbpUser.vue
  26. 5
      content/vue/src/views/sys/login/Login.vue
  27. 36
      content/vue/yarn.lock

3
content/aspnetcore/host/CompanyName.ProjectName.HttpApi.Host/CompanyNameProjectNameHttpApiHostModule.cs

@ -159,7 +159,8 @@ namespace CompanyNameProjectName
{
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false; //Disables the auditing system
options.IsEnabled = true;
options.EntityHistorySelectors.AddAllEntities();
});
}

15
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryAuditLogInput.cs

@ -0,0 +1,15 @@
using CompanyNameProjectName.Pages.Dtos;
namespace CompanyNameProjectName.Audits.Dtos
{
public class QueryAuditLogInput : CustomeRequestDto
{
public string UserName { get; set; }
public int HttpStatusCode { get; set; }
public string HttpMethod { get; set; }
public string ExecutionTime { get; set; }
}
}

123
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryAuditLogOutput.cs

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;
namespace CompanyNameProjectName.Audits.Dtos
{
public class QueryAuditLogOutput : EntityDto<Guid>
{
public string ApplicationName
{
get;
set;
}
public Guid? UserId
{
get;
set;
}
public string UserName
{
get;
set;
}
public Guid? TenantId
{
get;
set;
}
public string TenantName
{
get;
set;
}
public Guid? ImpersonatorUserId
{
get;
set;
}
public Guid? ImpersonatorTenantId
{
get;
set;
}
public virtual DateTime ExecutionTime
{
get;
set;
}
public int ExecutionDuration
{
get;
set;
}
public string ClientIpAddress
{
get;
set;
}
public string ClientName
{
get;
set;
}
public string ClientId
{
get;
set;
}
public string CorrelationId
{
get;
set;
}
public string BrowserInfo
{
get;
set;
}
public string HttpMethod
{
get;
set;
}
public string Url
{
get;
set;
}
public string Exceptions
{
get;
set;
}
public string Comments
{
get;
set;
}
public int? HttpStatusCode
{
get;
set;
}
}
}

11
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryEntityChangeInput.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CompanyNameProjectName.Audits.Dtos
{
public class QueryEntityChangeInput
{
public Guid Id { get; set; }
}
}

107
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Audits/Dtos/QueryEntityChangeOutput.cs

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
namespace CompanyNameProjectName.Audits.Dtos
{
public class QueryEntityChangeOutput : EntityDto<Guid>
{
public Guid AuditLogId
{
get;
set;
}
public Guid? TenantId
{
get;
set;
}
public DateTime ChangeTime
{
get;
set;
}
public EntityChangeType ChangeType
{
get;
set;
}
public Guid? EntityTenantId
{
get;
set;
}
public string EntityId
{
get;
set;
}
public string EntityTypeFullName
{
get;
set;
}
public ICollection<PropertyChangesDto> PropertyChanges
{
get;
set;
}
public ExtraPropertyDictionary ExtraProperties
{
get;
set;
}
}
public class PropertyChangesDto : EntityDto<Guid>
{
public Guid? TenantId
{
get;
set;
}
public Guid EntityChangeId
{
get;
set;
}
public string NewValue
{
get;
set;
}
public string OriginalValue
{
get;
set;
}
public string PropertyName
{
get;
set;
}
public string PropertyTypeFullName
{
get;
set;
}
}
}

6
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Permissions/CompanyNameProjectNamePermissionDefinitionProvider.cs

@ -8,11 +8,11 @@ namespace CompanyNameProjectName.Permissions
{
public override void Define(IPermissionDefinitionContext context)
{
var abpIdentityGroup = context.GetGroup("AbpIdentity");
abpIdentityGroup.AddPermission("AbpIdentity.Users.Lock", L("Permission:Users:Enable"));
abpIdentityGroup.AddPermission("AbpIdentity.Users.AuditLog", L("Permission:Users:AuditLog"));
//Define your own permissions here. Example:
//myGroup.AddPermission(CompanyNameProjectNamePermissions.MyPermission1, L("Permission:MyPermission1"));
}
private static LocalizableString L(string name)

16
content/aspnetcore/src/CompanyName.ProjectName.Application.Contracts/Users/Dtos/LockUserInput.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace CompanyNameProjectName.Users.Dtos
{
public class LockUserInput
{
[Required]
public Guid UserId { get; set; }
[Required]
public bool Locked { get; set; }
}
}

69
content/aspnetcore/src/CompanyName.ProjectName.Application/Audits/AuditAppService.cs

@ -0,0 +1,69 @@
using CompanyNameProjectName.Audits.Dtos;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.AuditLogging;
using Volo.Abp.Domain.Repositories;
namespace CompanyNameProjectName.Audits
{
[Authorize("AbpIdentity.Users.AuditLog")]
public class AuditAppService : ApplicationService
{
private readonly IRepository<AuditLog, Guid> _auditLogRepository;
public AuditAppService(IRepository<AuditLog, Guid> auditLogRepository)
{
_auditLogRepository = auditLogRepository;
}
/// <summary>
/// 分页查询审计日志
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[SwaggerOperation(summary: "分页获取审计日志信息", Tags = new[] { "Audit" })]
public async Task<PagedResultDto<QueryAuditLogOutput>> ListAsync(QueryAuditLogInput input)
{
var query = _auditLogRepository
.WhereIf(!input.ExecutionTime.IsNullOrWhiteSpace(), e => e.ExecutionTime > Convert.ToDateTime(input.ExecutionTime).AddSeconds(-1))
.WhereIf(!input.ExecutionTime.IsNullOrWhiteSpace(), e => e.ExecutionTime < Convert.ToDateTime(input.ExecutionTime).AddDays(1).AddSeconds(-1))
.WhereIf(!input.UserName.IsNullOrWhiteSpace(), e => e.UserName == input.UserName.Trim())
.WhereIf(!input.HttpMethod.IsNullOrWhiteSpace(), e => e.HttpMethod == input.HttpMethod)
.WhereIf(input.HttpStatusCode > 0, e => e.HttpStatusCode == input.HttpStatusCode);
var totalCount = await query.CountAsync();
var maxResultCount = input.PageSize;
var skipCount = (input.PageIndex - 1) * input.PageSize;
var list = await query.OrderByDescending(e => e.ExecutionTime).PageBy(skipCount, maxResultCount).ToListAsync();
return new PagedResultDto<QueryAuditLogOutput>(
totalCount,
ObjectMapper.Map<List<AuditLog>, List<QueryAuditLogOutput>>(list)
);
}
/// <summary>
/// 查询审计日志的实体变化信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[SwaggerOperation(summary: "获取审计日志详情", Tags = new[] { "Audit" })]
public async Task<List<QueryEntityChangeOutput>> QueryEntity(QueryEntityChangeInput input)
{
var entity = await _auditLogRepository.IncludeDetails().FirstOrDefaultAsync(e => e.Id == input.Id);
if (entity != null)
{
return ObjectMapper.Map<List<EntityChange>, List<QueryEntityChangeOutput>>(entity.EntityChanges.ToList());
}
return null;
}
}
}

12
content/aspnetcore/src/CompanyName.ProjectName.Application/CompanyNameProjectNameApplicationAutoMapperProfile.cs

@ -1,5 +1,7 @@
using AutoMapper;
using CompanyNameProjectName.Audits.Dtos;
using CompanyNameProjectName.Dtos.Users;
using Volo.Abp.AuditLogging;
using Volo.Abp.Identity;
namespace CompanyNameProjectName
@ -11,8 +13,16 @@ namespace CompanyNameProjectName
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
#region 用户
CreateMap<IdentityUser, LoginOutputDto>();
#endregion
#region 审计日志
CreateMap<AuditLog, QueryAuditLogOutput>();
CreateMap<EntityChange, QueryEntityChangeOutput>();
CreateMap<EntityPropertyChange, PropertyChangesDto>();
#endregion
}
}
}

1
content/aspnetcore/src/CompanyName.ProjectName.Application/Users/LoginAppService.cs

@ -41,6 +41,7 @@ namespace CompanyNameProjectName.Users
try
{
var result = await _signInManager.PasswordSignInAsync(input.Name, input.Password, false, true);
if (result.IsLockedOut) throw new Exception("当前用户已被锁定");
if (!result.Succeeded) throw new Exception("用户名或者密码错误");
var user = await _userManager.FindByNameAsync(input.Name);
var roles = await _userManager.GetRolesAsync(user);

24
content/aspnetcore/src/CompanyName.ProjectName.Application/Users/UserAppService.cs

@ -35,7 +35,7 @@ namespace CompanyNameProjectName.Users
request.Filter = input.filter?.Trim();
request.MaxResultCount = input.PageSize;
request.SkipCount = (input.PageIndex - 1) * input.PageSize;
request.Sorting= " LastModificationTime desc";
request.Sorting = " LastModificationTime desc";
return await _identityUserAppService.GetListAsync(request);
}
@ -52,7 +52,7 @@ namespace CompanyNameProjectName.Users
[HttpPost]
public virtual async Task<IdentityUserDto> UpdateAsync(UpdateUserInput input)
{
return await _identityUserAppService.UpdateAsync(input.UserId,input.UserInfo);
return await _identityUserAppService.UpdateAsync(input.UserId, input.UserInfo);
}
[SwaggerOperation(summary: "删除用户", Tags = new[] { "User" })]
@ -91,5 +91,25 @@ namespace CompanyNameProjectName.Users
if (!result.Succeeded) throw new Exception(result.Errors.FirstOrDefault().Description);
return result.Succeeded;
}
/// <summary>
/// 锁定用户
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task LockAsync(LockUserInput input)
{
var identityUser = await _userManager.GetByIdAsync(input.UserId);
await _userManager.SetLockoutEnabledAsync(identityUser, input.Locked);
if (input.Locked)
{
// 如果锁定用户,锁定100年
await _userManager.SetLockoutEndDateAsync(identityUser, DateTimeOffset.UtcNow.AddYears(100));
}
else {
await _userManager.SetLockoutEndDateAsync(identityUser, DateTimeOffset.UtcNow.AddDays(-1));
}
}
}
}

6
content/aspnetcore/src/CompanyName.ProjectName.Domain.Shared/Localization/CompanyNameProjectName/en.json

@ -6,6 +6,10 @@
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"DataExistence": "Existence",
"DataNotExistence": "Not Existence",
"TestSettings": "TestSettings"
"TestSettings": "TestSettings",
"Permission:Users:Enable": "Enable|Disable",
"Permission:Users:AuditLog": "AuditLog"
}
}

5
content/aspnetcore/src/CompanyName.ProjectName.Domain.Shared/Localization/CompanyNameProjectName/zh-Hans.json

@ -7,6 +7,9 @@
"DataExistence": "已存在",
"DataNotExistence": "不存在",
"Permission:Query": "查询",
"TestSettings": "测试Settings"
"TestSettings": "测试Settings",
"Permission:Users:Enable": "启用|禁用",
"Permission:Users:AuditLog": "审计日志"
}
}

4
content/vue/package.json

@ -38,6 +38,7 @@
"@zxcvbn-ts/core": "^0.3.0",
"ant-design-vue": "^2.1.2",
"axios": "^0.21.1",
"clipboard": "^2.0.8",
"crypto-js": "^4.0.0",
"echarts": "^5.0.2",
"jwt-decode": "^3.1.2",
@ -52,7 +53,8 @@
"vue": "3.0.11",
"vue-i18n": "9.0.0",
"vue-router": "^4.0.6",
"vue-types": "^3.0.2"
"vue-types": "^3.0.2",
"vue3-json-viewer": "^1.0.4"
},
"devDependencies": {
"@commitlint/cli": "^12.1.1",

16
content/vue/src/locales/lang/en/routes/admin.ts

@ -6,6 +6,7 @@ export default {
userManagement_userName: 'UserName',
userManagement_name: "Name",
userManagement_email: "Email",
userManagement_locked: "Locked",
userManagement_phone: "phone",
userManagement_createTime: "CreateTime",
userManagement_create_user: 'Create User',
@ -18,5 +19,18 @@ export default {
roleManagement_default: "Default",
roleManagement_edit: "Edit Role",
roleManagement_create_role: "Create Role",
roleManagement_permission: "Permission"
roleManagement_permission: "Permission",
auditManagement: "Audit Log",
audit_executeTime: "ExecutionTime",
audit_endTime: "EndTime",
audit_userName: "UserName",
audit_httpMethod: "HttpMethod",
audit_httpStatusCode: "HttpStatusCode",
audit_httpRequest: "HttpRequest",
audit_ipAdrress: "IP Address",
audit_duration: "Execution Duration(ms)",
audit_url: "URL",
audit_entityInfo: "EntityInformation",
audit_message: "Entity Message",
};

15
content/vue/src/locales/lang/zh_CN/routes/admin.ts

@ -6,6 +6,7 @@ export default {
userManagement_userName: '用户名称',
userManagement_name: "名称",
userManagement_email: "邮箱",
userManagement_locked: "锁定",
userManagement_phone: "手机",
userManagement_createTime: "创建时间",
userManagement_password: "密码",
@ -17,5 +18,17 @@ export default {
roleManagement_default: "默认",
roleManagement_edit: "编辑角色",
roleManagement_create_role: "创建角色",
roleManagement_permission: "授权"
roleManagement_permission: "授权",
auditManagement: "审计日志",
audit_userName: "用户名",
audit_httpMethod: "Http方法",
audit_httpStatusCode: "Http状态码",
audit_httpRequest: "Http请求",
audit_ipAdrress: "IP地址",
audit_executeTime: "执行时间",
audit_duration: "持续时间(ms)",
audit_url: "Url地址",
audit_entityInfo: "实体信息",
audit_message: "实体信息",
};

4
content/vue/src/main.ts

@ -11,7 +11,7 @@ import { setupErrorHandle } from '/@/logics/error-handle';
import { setupGlobDirectives } from '/@/directives';
import { setupI18n } from '/@/locales/setupI18n';
import { registerGlobComp } from '/@/components/registerGlobComp';
import JsonViewer from "vue3-json-viewer"
// Register icon Sprite
import 'vite-plugin-svg-icons/register';
@ -25,7 +25,7 @@ if (import.meta.env.DEV) {
(async () => {
const app = createApp(App);
app.use(JsonViewer);
// Configure vuex store
setupStore(app);

10
content/vue/src/router/menus/modules/admin.ts

@ -12,12 +12,20 @@ const admin: MenuModule = {
tag: {
type: 'warn',
},
}, {
},
{
path: 'abpRole',
name: t('routes.admin.roleManagement'),
tag: {
type: 'warn',
},
},
{
path: 'audit',
name: t('routes.admin.auditManagement'),
tag: {
type: 'warn',
},
}]
},
};

11
content/vue/src/router/routes/modules/admin.ts

@ -6,7 +6,6 @@ const admin: AppRouteModule = {
path: '/admin',
name: 'Admin',
component: LAYOUT,
//redirect: '/admin/abpUser',
meta: {
icon: 'ion:grid-outline',
title: t('routes.admin.systemManagement'),
@ -31,6 +30,16 @@ const admin: AppRouteModule = {
policy: 'AbpIdentity.Roles',
icon: 'ant-design:lock-outlined'
},
},
{
path: 'audit',
name: 'Audit',
component: () => import('/@/views/admin/audits/AuditLog.vue'),
meta: {
title: t('routes.admin.auditManagement'),
policy: "AbpIdentity.Users.AuditLog",
icon: 'ant-design:audit-outlined'
},
}
],
};

837
content/vue/src/services/ServiceProxies.ts

@ -215,6 +215,210 @@ export class AbpApplicationConfigurationServiceProxy extends ServiceProxyBase {
}
}
export class AuditServiceProxy extends ServiceProxyBase {
private instance: AxiosInstance;
private baseUrl: string;
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
constructor(baseUrl?: string, instance?: AxiosInstance) {
super();
this.instance = instance ? instance : axios.create();
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "";
}
/**
*
* @param body (optional)
* @return Success
*/
list(body: QueryAuditLogInput | undefined , cancelToken?: CancelToken | undefined): Promise<QueryAuditLogOutputPagedResultDto> {
let url_ = this.baseUrl + "/api/app/audit/list";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(body);
let options_ = <AxiosRequestConfig>{
data: content_,
method: "POST",
url: url_,
headers: {
"Content-Type": "application/json",
"Accept": "text/plain"
},
cancelToken
};
return this.transformOptions(options_).then(transformedOptions_ => {
return this.instance.request(transformedOptions_);
}).catch((_error: any) => {
if (isAxiosError(_error) && _error.response) {
return _error.response;
} else {
throw _error;
}
}).then((_response: AxiosResponse) => {
return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processList(_response));
});
}
protected processList(response: AxiosResponse): Promise<QueryAuditLogOutputPagedResultDto> {
const status = response.status;
let _headers: any = {};
if (response.headers && typeof response.headers === "object") {
for (let k in response.headers) {
if (response.headers.hasOwnProperty(k)) {
_headers[k] = response.headers[k];
}
}
}
if (status === 200) {
const _responseText = response.data;
let result200: any = null;
let resultData200 = _responseText;
result200 = QueryAuditLogOutputPagedResultDto.fromJS(resultData200);
return result200;
} else if (status === 403) {
const _responseText = response.data;
let result403: any = null;
let resultData403 = _responseText;
result403 = RemoteServiceErrorResponse.fromJS(resultData403);
return throwException("Forbidden", status, _responseText, _headers, result403);
} else if (status === 401) {
const _responseText = response.data;
let result401: any = null;
let resultData401 = _responseText;
result401 = RemoteServiceErrorResponse.fromJS(resultData401);
return throwException("Unauthorized", status, _responseText, _headers, result401);
} else if (status === 400) {
const _responseText = response.data;
let result400: any = null;
let resultData400 = _responseText;
result400 = RemoteServiceErrorResponse.fromJS(resultData400);
return throwException("Bad Request", status, _responseText, _headers, result400);
} else if (status === 404) {
const _responseText = response.data;
let result404: any = null;
let resultData404 = _responseText;
result404 = RemoteServiceErrorResponse.fromJS(resultData404);
return throwException("Not Found", status, _responseText, _headers, result404);
} else if (status === 501) {
const _responseText = response.data;
let result501: any = null;
let resultData501 = _responseText;
result501 = RemoteServiceErrorResponse.fromJS(resultData501);
return throwException("Server Error", status, _responseText, _headers, result501);
} else if (status === 500) {
const _responseText = response.data;
let result500: any = null;
let resultData500 = _responseText;
result500 = RemoteServiceErrorResponse.fromJS(resultData500);
return throwException("Server Error", status, _responseText, _headers, result500);
} else if (status !== 200 && status !== 204) {
const _responseText = response.data;
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
}
return Promise.resolve<QueryAuditLogOutputPagedResultDto>(<any>null);
}
/**
*
* @param body (optional)
* @return Success
*/
queryEntity(body: QueryEntityChangeInput | undefined , cancelToken?: CancelToken | undefined): Promise<QueryEntityChangeOutput[]> {
let url_ = this.baseUrl + "/api/app/audit/query-entity";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(body);
let options_ = <AxiosRequestConfig>{
data: content_,
method: "POST",
url: url_,
headers: {
"Content-Type": "application/json",
"Accept": "text/plain"
},
cancelToken
};
return this.transformOptions(options_).then(transformedOptions_ => {
return this.instance.request(transformedOptions_);
}).catch((_error: any) => {
if (isAxiosError(_error) && _error.response) {
return _error.response;
} else {
throw _error;
}
}).then((_response: AxiosResponse) => {
return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processQueryEntity(_response));
});
}
protected processQueryEntity(response: AxiosResponse): Promise<QueryEntityChangeOutput[]> {
const status = response.status;
let _headers: any = {};
if (response.headers && typeof response.headers === "object") {
for (let k in response.headers) {
if (response.headers.hasOwnProperty(k)) {
_headers[k] = response.headers[k];
}
}
}
if (status === 200) {
const _responseText = response.data;
let result200: any = null;
let resultData200 = _responseText;
if (Array.isArray(resultData200)) {
result200 = [] as any;
for (let item of resultData200)
result200!.push(QueryEntityChangeOutput.fromJS(item));
}
return result200;
} else if (status === 403) {
const _responseText = response.data;
let result403: any = null;
let resultData403 = _responseText;
result403 = RemoteServiceErrorResponse.fromJS(resultData403);
return throwException("Forbidden", status, _responseText, _headers, result403);
} else if (status === 401) {
const _responseText = response.data;
let result401: any = null;
let resultData401 = _responseText;
result401 = RemoteServiceErrorResponse.fromJS(resultData401);
return throwException("Unauthorized", status, _responseText, _headers, result401);
} else if (status === 400) {
const _responseText = response.data;
let result400: any = null;
let resultData400 = _responseText;
result400 = RemoteServiceErrorResponse.fromJS(resultData400);
return throwException("Bad Request", status, _responseText, _headers, result400);
} else if (status === 404) {
const _responseText = response.data;
let result404: any = null;
let resultData404 = _responseText;
result404 = RemoteServiceErrorResponse.fromJS(resultData404);
return throwException("Not Found", status, _responseText, _headers, result404);
} else if (status === 501) {
const _responseText = response.data;
let result501: any = null;
let resultData501 = _responseText;
result501 = RemoteServiceErrorResponse.fromJS(resultData501);
return throwException("Server Error", status, _responseText, _headers, result501);
} else if (status === 500) {
const _responseText = response.data;
let result500: any = null;
let resultData500 = _responseText;
result500 = RemoteServiceErrorResponse.fromJS(resultData500);
return throwException("Server Error", status, _responseText, _headers, result500);
} else if (status !== 200 && status !== 204) {
const _responseText = response.data;
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
}
return Promise.resolve<QueryEntityChangeOutput[]>(<any>null);
}
}
export class LoginServiceProxy extends ServiceProxyBase {
private instance: AxiosInstance;
private baseUrl: string;
@ -1828,49 +2032,138 @@ export class UserServiceProxy extends ServiceProxyBase {
}
return Promise.resolve<boolean>(<any>null);
}
}
export class AbpLoginResult implements IAbpLoginResult {
result?: LoginResultType;
readonly description?: string | undefined;
/**
* @param body (optional)
* @return Success
*/
lock(body: LockUserInput | undefined , cancelToken?: CancelToken | undefined): Promise<void> {
let url_ = this.baseUrl + "/api/app/user/lock";
url_ = url_.replace(/[?&]$/, "");
constructor(data?: IAbpLoginResult) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
const content_ = JSON.stringify(body);
init(_data?: any) {
if (_data) {
this.result = _data["result"];
(<any>this).description = _data["description"];
let options_ = <AxiosRequestConfig>{
data: content_,
method: "POST",
url: url_,
headers: {
"Content-Type": "application/json",
},
cancelToken
};
return this.transformOptions(options_).then(transformedOptions_ => {
return this.instance.request(transformedOptions_);
}).catch((_error: any) => {
if (isAxiosError(_error) && _error.response) {
return _error.response;
} else {
throw _error;
}
}).then((_response: AxiosResponse) => {
return this.transformResult(url_, _response, (_response: AxiosResponse) => this.processLock(_response));
});
}
static fromJS(data: any): AbpLoginResult {
data = typeof data === 'object' ? data : {};
let result = new AbpLoginResult();
result.init(data);
return result;
protected processLock(response: AxiosResponse): Promise<void> {
const status = response.status;
let _headers: any = {};
if (response.headers && typeof response.headers === "object") {
for (let k in response.headers) {
if (response.headers.hasOwnProperty(k)) {
_headers[k] = response.headers[k];
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["result"] = this.result;
data["description"] = this.description;
return data;
}
}
export interface IAbpLoginResult {
result?: LoginResultType;
description?: string | undefined;
}
export class ActionApiDescriptionModel implements IActionApiDescriptionModel {
}
if (status === 200) {
const _responseText = response.data;
return Promise.resolve<void>(<any>null);
} else if (status === 403) {
const _responseText = response.data;
let result403: any = null;
let resultData403 = _responseText;
result403 = RemoteServiceErrorResponse.fromJS(resultData403);
return throwException("Forbidden", status, _responseText, _headers, result403);
} else if (status === 401) {
const _responseText = response.data;
let result401: any = null;
let resultData401 = _responseText;
result401 = RemoteServiceErrorResponse.fromJS(resultData401);
return throwException("Unauthorized", status, _responseText, _headers, result401);
} else if (status === 400) {
const _responseText = response.data;
let result400: any = null;
let resultData400 = _responseText;
result400 = RemoteServiceErrorResponse.fromJS(resultData400);
return throwException("Bad Request", status, _responseText, _headers, result400);
} else if (status === 404) {
const _responseText = response.data;
let result404: any = null;
let resultData404 = _responseText;
result404 = RemoteServiceErrorResponse.fromJS(resultData404);
return throwException("Not Found", status, _responseText, _headers, result404);
} else if (status === 501) {
const _responseText = response.data;
let result501: any = null;
let resultData501 = _responseText;
result501 = RemoteServiceErrorResponse.fromJS(resultData501);
return throwException("Server Error", status, _responseText, _headers, result501);
} else if (status === 500) {
const _responseText = response.data;
let result500: any = null;
let resultData500 = _responseText;
result500 = RemoteServiceErrorResponse.fromJS(resultData500);
return throwException("Server Error", status, _responseText, _headers, result500);
} else if (status !== 200 && status !== 204) {
const _responseText = response.data;
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
}
return Promise.resolve<void>(<any>null);
}
}
export class AbpLoginResult implements IAbpLoginResult {
result?: LoginResultType;
readonly description?: string | undefined;
constructor(data?: IAbpLoginResult) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.result = _data["result"];
(<any>this).description = _data["description"];
}
}
static fromJS(data: any): AbpLoginResult {
data = typeof data === 'object' ? data : {};
let result = new AbpLoginResult();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["result"] = this.result;
data["description"] = this.description;
return data;
}
}
export interface IAbpLoginResult {
result?: LoginResultType;
description?: string | undefined;
}
export class ActionApiDescriptionModel implements IActionApiDescriptionModel {
uniqueName?: string | undefined;
name?: string | undefined;
httpMethod?: string | undefined;
@ -2790,6 +3083,12 @@ export interface IDateTimeFormatDto {
longTimePattern?: string | undefined;
}
export enum EntityChangeType {
_0 = 0,
_1 = 1,
_2 = 2,
}
export class EntityExtensionDto implements IEntityExtensionDto {
properties?: { [key: string]: ExtensionPropertyDto; } | undefined;
configuration?: { [key: string]: any; } | undefined;
@ -4701,6 +5000,46 @@ export interface ILocalizableStringDto {
resource?: string | undefined;
}
export class LockUserInput implements ILockUserInput {
userId!: string;
locked!: boolean;
constructor(data?: ILockUserInput) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.userId = _data["userId"];
this.locked = _data["locked"];
}
}
static fromJS(data: any): LockUserInput {
data = typeof data === 'object' ? data : {};
let result = new LockUserInput();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["userId"] = this.userId;
data["locked"] = this.locked;
return data;
}
}
export interface ILockUserInput {
userId: string;
locked: boolean;
}
export class LoginInputDto implements ILoginInputDto {
name?: string | undefined;
password?: string | undefined;
@ -5449,6 +5788,66 @@ export interface IPropertyApiDescriptionModel {
isRequired?: boolean;
}
export class PropertyChangesDto implements IPropertyChangesDto {
id?: string;
tenantId?: string | undefined;
entityChangeId?: string;
newValue?: string | undefined;
originalValue?: string | undefined;
propertyName?: string | undefined;
propertyTypeFullName?: string | undefined;
constructor(data?: IPropertyChangesDto) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
this.tenantId = _data["tenantId"];
this.entityChangeId = _data["entityChangeId"];
this.newValue = _data["newValue"];
this.originalValue = _data["originalValue"];
this.propertyName = _data["propertyName"];
this.propertyTypeFullName = _data["propertyTypeFullName"];
}
}
static fromJS(data: any): PropertyChangesDto {
data = typeof data === 'object' ? data : {};
let result = new PropertyChangesDto();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["tenantId"] = this.tenantId;
data["entityChangeId"] = this.entityChangeId;
data["newValue"] = this.newValue;
data["originalValue"] = this.originalValue;
data["propertyName"] = this.propertyName;
data["propertyTypeFullName"] = this.propertyTypeFullName;
return data;
}
}
export interface IPropertyChangesDto {
id?: string;
tenantId?: string | undefined;
entityChangeId?: string;
newValue?: string | undefined;
originalValue?: string | undefined;
propertyName?: string | undefined;
propertyTypeFullName?: string | undefined;
}
export class ProviderInfoDto implements IProviderInfoDto {
providerName?: string | undefined;
providerKey?: string | undefined;
@ -5489,6 +5888,374 @@ export interface IProviderInfoDto {
providerKey?: string | undefined;
}
export class QueryAuditLogInput implements IQueryAuditLogInput {
pageIndex?: number;
pageSize?: number;
userName?: string | undefined;
httpStatusCode?: number;
httpMethod?: string | undefined;
executionTime?: string | undefined;
constructor(data?: IQueryAuditLogInput) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.pageIndex = _data["pageIndex"];
this.pageSize = _data["pageSize"];
this.userName = _data["userName"];
this.httpStatusCode = _data["httpStatusCode"];
this.httpMethod = _data["httpMethod"];
this.executionTime = _data["executionTime"];
}
}
static fromJS(data: any): QueryAuditLogInput {
data = typeof data === 'object' ? data : {};
let result = new QueryAuditLogInput();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["pageIndex"] = this.pageIndex;
data["pageSize"] = this.pageSize;
data["userName"] = this.userName;
data["httpStatusCode"] = this.httpStatusCode;
data["httpMethod"] = this.httpMethod;
data["executionTime"] = this.executionTime;
return data;
}
}
export interface IQueryAuditLogInput {
pageIndex?: number;
pageSize?: number;
userName?: string | undefined;
httpStatusCode?: number;
httpMethod?: string | undefined;
executionTime?: string | undefined;
}
export class QueryAuditLogOutput implements IQueryAuditLogOutput {
id?: string;
applicationName?: string | undefined;
userId?: string | undefined;
userName?: string | undefined;
tenantId?: string | undefined;
tenantName?: string | undefined;
impersonatorUserId?: string | undefined;
impersonatorTenantId?: string | undefined;
executionTime?: Date;
executionDuration?: number;
clientIpAddress?: string | undefined;
clientName?: string | undefined;
clientId?: string | undefined;
correlationId?: string | undefined;
browserInfo?: string | undefined;
httpMethod?: string | undefined;
url?: string | undefined;
exceptions?: string | undefined;
comments?: string | undefined;
httpStatusCode?: number | undefined;
readonly entityChanges?: QueryEntityChangeOutput[] | undefined;
readonly actions?: PropertyChangesDto[] | undefined;
constructor(data?: IQueryAuditLogOutput) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
this.applicationName = _data["applicationName"];
this.userId = _data["userId"];
this.userName = _data["userName"];
this.tenantId = _data["tenantId"];
this.tenantName = _data["tenantName"];
this.impersonatorUserId = _data["impersonatorUserId"];
this.impersonatorTenantId = _data["impersonatorTenantId"];
this.executionTime = _data["executionTime"] ? new Date(_data["executionTime"].toString()) : <any>undefined;
this.executionDuration = _data["executionDuration"];
this.clientIpAddress = _data["clientIpAddress"];
this.clientName = _data["clientName"];
this.clientId = _data["clientId"];
this.correlationId = _data["correlationId"];
this.browserInfo = _data["browserInfo"];
this.httpMethod = _data["httpMethod"];
this.url = _data["url"];
this.exceptions = _data["exceptions"];
this.comments = _data["comments"];
this.httpStatusCode = _data["httpStatusCode"];
if (Array.isArray(_data["entityChanges"])) {
(<any>this).entityChanges = [] as any;
for (let item of _data["entityChanges"])
(<any>this).entityChanges!.push(QueryEntityChangeOutput.fromJS(item));
}
if (Array.isArray(_data["actions"])) {
(<any>this).actions = [] as any;
for (let item of _data["actions"])
(<any>this).actions!.push(PropertyChangesDto.fromJS(item));
}
}
}
static fromJS(data: any): QueryAuditLogOutput {
data = typeof data === 'object' ? data : {};
let result = new QueryAuditLogOutput();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["applicationName"] = this.applicationName;
data["userId"] = this.userId;
data["userName"] = this.userName;
data["tenantId"] = this.tenantId;
data["tenantName"] = this.tenantName;
data["impersonatorUserId"] = this.impersonatorUserId;
data["impersonatorTenantId"] = this.impersonatorTenantId;
data["executionTime"] = this.executionTime ? this.executionTime.toISOString() : <any>undefined;
data["executionDuration"] = this.executionDuration;
data["clientIpAddress"] = this.clientIpAddress;
data["clientName"] = this.clientName;
data["clientId"] = this.clientId;
data["correlationId"] = this.correlationId;
data["browserInfo"] = this.browserInfo;
data["httpMethod"] = this.httpMethod;
data["url"] = this.url;
data["exceptions"] = this.exceptions;
data["comments"] = this.comments;
data["httpStatusCode"] = this.httpStatusCode;
if (Array.isArray(this.entityChanges)) {
data["entityChanges"] = [];
for (let item of this.entityChanges)
data["entityChanges"].push(item.toJSON());
}
if (Array.isArray(this.actions)) {
data["actions"] = [];
for (let item of this.actions)
data["actions"].push(item.toJSON());
}
return data;
}
}
export interface IQueryAuditLogOutput {
id?: string;
applicationName?: string | undefined;
userId?: string | undefined;
userName?: string | undefined;
tenantId?: string | undefined;
tenantName?: string | undefined;
impersonatorUserId?: string | undefined;
impersonatorTenantId?: string | undefined;
executionTime?: Date;
executionDuration?: number;
clientIpAddress?: string | undefined;
clientName?: string | undefined;
clientId?: string | undefined;
correlationId?: string | undefined;
browserInfo?: string | undefined;
httpMethod?: string | undefined;
url?: string | undefined;
exceptions?: string | undefined;
comments?: string | undefined;
httpStatusCode?: number | undefined;
entityChanges?: QueryEntityChangeOutput[] | undefined;
actions?: PropertyChangesDto[] | undefined;
}
export class QueryAuditLogOutputPagedResultDto implements IQueryAuditLogOutputPagedResultDto {
items?: QueryAuditLogOutput[] | undefined;
totalCount?: number;
constructor(data?: IQueryAuditLogOutputPagedResultDto) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
if (Array.isArray(_data["items"])) {
this.items = [] as any;
for (let item of _data["items"])
this.items!.push(QueryAuditLogOutput.fromJS(item));
}
this.totalCount = _data["totalCount"];
}
}
static fromJS(data: any): QueryAuditLogOutputPagedResultDto {
data = typeof data === 'object' ? data : {};
let result = new QueryAuditLogOutputPagedResultDto();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
if (Array.isArray(this.items)) {
data["items"] = [];
for (let item of this.items)
data["items"].push(item.toJSON());
}
data["totalCount"] = this.totalCount;
return data;
}
}
export interface IQueryAuditLogOutputPagedResultDto {
items?: QueryAuditLogOutput[] | undefined;
totalCount?: number;
}
export class QueryEntityChangeInput implements IQueryEntityChangeInput {
id?: string;
constructor(data?: IQueryEntityChangeInput) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
}
}
static fromJS(data: any): QueryEntityChangeInput {
data = typeof data === 'object' ? data : {};
let result = new QueryEntityChangeInput();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
return data;
}
}
export interface IQueryEntityChangeInput {
id?: string;
}
export class QueryEntityChangeOutput implements IQueryEntityChangeOutput {
id?: string;
auditLogId?: string;
tenantId?: string | undefined;
changeTime?: Date;
changeType?: EntityChangeType;
entityTenantId?: string | undefined;
entityId?: string | undefined;
entityTypeFullName?: string | undefined;
propertyChanges?: PropertyChangesDto[] | undefined;
extraProperties?: { [key: string]: any; } | undefined;
constructor(data?: IQueryEntityChangeOutput) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
this.auditLogId = _data["auditLogId"];
this.tenantId = _data["tenantId"];
this.changeTime = _data["changeTime"] ? new Date(_data["changeTime"].toString()) : <any>undefined;
this.changeType = _data["changeType"];
this.entityTenantId = _data["entityTenantId"];
this.entityId = _data["entityId"];
this.entityTypeFullName = _data["entityTypeFullName"];
if (Array.isArray(_data["propertyChanges"])) {
this.propertyChanges = [] as any;
for (let item of _data["propertyChanges"])
this.propertyChanges!.push(PropertyChangesDto.fromJS(item));
}
if (_data["extraProperties"]) {
this.extraProperties = {} as any;
for (let key in _data["extraProperties"]) {
if (_data["extraProperties"].hasOwnProperty(key))
this.extraProperties![key] = _data["extraProperties"][key];
}
}
}
}
static fromJS(data: any): QueryEntityChangeOutput {
data = typeof data === 'object' ? data : {};
let result = new QueryEntityChangeOutput();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["auditLogId"] = this.auditLogId;
data["tenantId"] = this.tenantId;
data["changeTime"] = this.changeTime ? this.changeTime.toISOString() : <any>undefined;
data["changeType"] = this.changeType;
data["entityTenantId"] = this.entityTenantId;
data["entityId"] = this.entityId;
data["entityTypeFullName"] = this.entityTypeFullName;
if (Array.isArray(this.propertyChanges)) {
data["propertyChanges"] = [];
for (let item of this.propertyChanges)
data["propertyChanges"].push(item.toJSON());
}
if (this.extraProperties) {
data["extraProperties"] = {};
for (let key in this.extraProperties) {
if (this.extraProperties.hasOwnProperty(key))
data["extraProperties"][key] = this.extraProperties[key];
}
}
return data;
}
}
export interface IQueryEntityChangeOutput {
id?: string;
auditLogId?: string;
tenantId?: string | undefined;
changeTime?: Date;
changeType?: EntityChangeType;
entityTenantId?: string | undefined;
entityId?: string | undefined;
entityTypeFullName?: string | undefined;
propertyChanges?: PropertyChangesDto[] | undefined;
extraProperties?: { [key: string]: any; } | undefined;
}
export class RegisterDto implements IRegisterDto {
readonly extraProperties?: { [key: string]: any; } | undefined;
userName!: string;

91
content/vue/src/views/admin/audits/AuditLog.vue

@ -0,0 +1,91 @@
<template>
<div>
<BasicTable @register="registerAuditTable" size="small">
<template #category="{ record }">
<Tag :color="record.httpStatusCode >= 500 ? 'red' : 'green'">
{{ record.httpStatusCode }}
</Tag>
<Tag :color="record.httpMethod == 'DELETE' ? 'red' : 'green'">
{{ record.httpMethod }}
</Tag>
</template>
<template #action="{ record }">
<a-button type="link" size="small" @click="lookJson(record.id)">
{{ t('routes.admin.audit_entityInfo') }}
</a-button>
</template>
</BasicTable>
<BasicModal
:title="t('routes.admin.audit_message')"
:canFullscreen="false"
@register="registerModal"
:showOkButton="false"
>
<json-viewer :value="jsonRef" copyable boxed sort />
</BasicModal>
</div>
</template>
<script lang="ts">
import { Tag } from 'ant-design-vue';
import { BasicTable, useTable } from '/@/components/Table';
import { BasicModal, useModal } from '/@/components/Modal';
import { defineComponent, ref } from 'vue';
import { tableColumns, getTableListAsync, getEntityInfoAsync } from './audit';
import { searchFormSchema } from './audit';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'AuditLog',
components: {
BasicTable,
Tag,
BasicModal,
},
setup() {
const { t } = useI18n();
const [registerModal, { openModal: openJsonModal }] = useModal();
const [registerAuditTable, { reload }] = useTable({
columns: tableColumns,
formConfig: {
labelWidth: 80,
schemas: searchFormSchema,
},
api: getTableListAsync,
useSearchForm: true,
showTableSetting: true,
bordered: true,
canResize: false,
showIndexColumn: true,
actionColumn: {
title: t('common.action'),
dataIndex: 'action',
slots: {
customRender: 'action',
},
width: 150,
fixed: 'right',
},
});
const jsonRef = ref('');
const lookJson = async (id: string) => {
openJsonModal();
let result = await getEntityInfoAsync(id);
jsonRef.value = result as any;
};
return {
t,
registerAuditTable,
reload,
getTableListAsync,
lookJson,
registerModal,
openJsonModal,
jsonRef,
};
},
});
</script>
<style lang="less" scoped></style>

296
content/vue/src/views/admin/audits/audit.ts

@ -0,0 +1,296 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { useI18n } from '/@/hooks/web/useI18n';
import moment from 'moment';
import { AuditServiceProxy, QueryAuditLogInput, QueryAuditLogOutputPagedResultDto, QueryEntityChangeInput, QueryEntityChangeOutput } from '/@/services/ServiceProxies';
const { t } = useI18n();
export const searchFormSchema: FormSchema[] = [
{
field: 'ExecutionTime',
component: 'DatePicker',
label: t('routes.admin.audit_executeTime'),
colProps: {
span: 3
},
componentProps: {
valueFormat: "YYYY-MM-DD"
}
},
{
field: 'userName',
component: 'Input',
label: t('routes.admin.audit_userName'),
colProps: {
span: 4
},
},
{
field: 'httpMethod',
component: 'Select',
label: t('routes.admin.audit_httpMethod'),
colProps: {
span: 4
},
componentProps: {
options: [
{
label: 'GET',
value: 'GET',
key: '1',
}, {
label: 'HEAD',
value: 'HEAD',
key: '2',
}, {
label: 'POST',
value: 'POST',
key: '3',
}, {
label: 'PUT',
value: 'PUT',
key: '4',
}, {
label: 'DELETE',
value: 'DELETE',
key: '5',
}, {
label: 'CONNECT',
value: 'CONNET',
key: '6',
}, {
label: 'OPTIONS',
value: 'OPTIONS',
key: '7',
}, {
label: 'TRACE',
value: 'TRACE',
key: '8',
}, {
label: 'PATH',
value: 'PATH',
key: '9',
},
]
}
},
{
field: 'httpStatusCode',
component: 'Select',
label: t('routes.admin.audit_httpStatusCode'),
colProps: {
span: 4
},
componentProps: {
options: [
{
label: '100-Continue',
value: '100',
key: '1',
}, {
label: '101-SwitchingProtocols',
value: '101',
key: '2',
}, {
label: '200-OK',
value: '200',
key: '3',
}, {
label: '201-Created',
value: '201',
key: '4',
}, {
label: '202-Accepted',
value: '202',
key: '5',
}, {
label: '203-Non-AuthoritativeInformation',
value: '203',
key: '6',
}, {
label: '204-NoContent',
value: '204',
key: '7',
}, {
label: '205-ResetContent',
value: '205',
key: '8',
}, {
label: '206-PartialContent',
value: '206',
key: '9',
}, {
label: '300-MultipleChoices',
value: '300',
key: '10',
}, {
label: '301-MovedPermanently',
value: '301',
key: '11',
}, {
label: '302-Found',
value: '302',
key: '12',
}, {
label: '303-SeeOther',
value: '303',
key: '13',
}, {
label: '304-NotModified',
value: '304',
key: '14',
}, {
label: '305-UseProxy',
value: '305',
key: '15',
}, {
label: '306-Unused',
value: '306',
key: '16',
}, {
label: '307-TemporaryRedirect',
value: '307',
key: '17',
}, {
label: '400-BadRequest',
value: '400',
key: '18',
}, {
label: '401-Unauthorized',
value: '401',
key: '19',
}, {
label: '402-PaymentRequired',
value: '402',
key: '20',
}, {
label: '403-Forbidden',
value: '403',
key: '21',
}, {
label: '404-NotFound',
value: '404',
key: '22',
}, {
label: '405-MethodNotAllowed',
value: '405',
key: '23',
}, {
label: '406-NotAcceptable',
value: '406',
key: '24',
}, {
label: '407-ProxyAuthenticationRequired',
value: '407',
key: '25',
}, {
label: '408-RequestTime-out',
value: '408',
key: '26',
}, {
label: '409-Conflict',
value: '409',
key: '27',
}, {
label: '410-Gone',
value: '410',
key: '28',
}, {
label: '411-LengthRequired',
value: '411',
key: '29',
}, {
label: '412-PreconditionFailed',
value: '412',
key: '30',
}, {
label: '413-RequestEntityTooLarge',
value: '413',
key: '31',
}, {
label: '414-Request-URITooLarge',
value: '414',
key: '32',
}, {
label: '415-UnsupportedMediaType',
value: '415',
key: '33',
}, {
label: '416-Requestedrangenotsatisfiable',
value: '416',
key: '34',
}, {
label: '417-ExpectationFailed',
value: '417',
key: '35',
}, {
label: '500-InternalServerError',
value: '500',
key: '36',
}, {
label: '501-NotImplemented',
value: '501',
key: '37',
}, {
label: '502-BadGateway',
value: '502',
key: '38',
}, {
label: '503-ServiceUnavailable',
value: '503',
key: '39',
}, {
label: '504-GatewayTime-out',
value: '504',
key: '40',
}, {
label: '505-HTTPVersionnotsupported',
value: '505',
key: '41',
},
]
}
}
]
export const tableColumns: BasicColumn[] = [
{
title: t('routes.admin.audit_httpRequest'),
dataIndex: 'httpMethod',
slots: { customRender: 'category' }
},
{
title: t('routes.admin.audit_url'),
dataIndex: 'url',
},
{
title: t('routes.admin.audit_userName'),
dataIndex: 'userName',
},
{
title: t('routes.admin.audit_ipAdrress'),
dataIndex: 'clientIpAddress',
},
{
title: t('routes.admin.audit_executeTime'),
dataIndex: 'executionTime',
customRender: ({ text }) => {
return moment(text).format("YYYY-MM-DD HH:mm:ss");
}
},
{
title: t('routes.admin.audit_duration'),
dataIndex: 'executionDuration',
}
]
//获取表格列表
export async function getTableListAsync(params: QueryAuditLogInput): Promise<QueryAuditLogOutputPagedResultDto> {
const _auditServiceProxy = new AuditServiceProxy();
return await _auditServiceProxy.list(params);
}
//获取实体信息
export async function getEntityInfoAsync(id: string): Promise<QueryEntityChangeOutput[]> {
const _auditServiceProxy = new AuditServiceProxy();
let request = new QueryEntityChangeInput();
request.id = id;
return _auditServiceProxy.queryEntity(request);
}

1
content/vue/src/views/admin/roles/AbpRole.ts

@ -13,7 +13,6 @@ export const tableColumns: BasicColumn[] = [
{
title: t('routes.admin.userManagement_roleName'),
dataIndex: 'name',
},
{
title: t('routes.admin.roleManagement_default'),

18
content/vue/src/views/admin/users/AbpUser.ts

@ -6,7 +6,8 @@ import {
UserServiceProxy,
IdentityUserDtoPagedResultDto,
IdentityRoleDtoListResultDto,
RoleServiceProxy
RoleServiceProxy,
LockUserInput
} from '/@/services/ServiceProxies';
import { message } from 'ant-design-vue';
import { useLoading } from '/@/components/Loading';
@ -39,6 +40,11 @@ export const tableColumns: BasicColumn[] = [
// dataIndex: 'phoneNumber',
// },
{
title: t('routes.admin.userManagement_locked'),
dataIndex: 'lockoutEnabled',
slots: { customRender: 'lockoutEnabled' }
},
{
title: t('routes.admin.userManagement_createTime'),
dataIndex: 'creationTime',
@ -214,3 +220,13 @@ export async function updateUserAsync({ request, changeOkLoading, validate, clos
closeModal();
}
/**
*
* @param isLock
* @returns
*/
export async function lockUserAsync(request: LockUserInput): Promise<void> {
const _userServiceProxy = new UserServiceProxy();
return _userServiceProxy.lock(request);
}

35
content/vue/src/views/admin/users/AbpUser.vue

@ -10,7 +10,11 @@
{{ t('common.createText') }}
</a-button>
</template>
<template #lockoutEnabled="{ record }">
<Tag :color="record.lockoutEnabled ? 'red' : 'green'">
{{ record.lockoutEnabled ? '已锁定' : '未锁定' }}
</Tag>
</template>
<template #action="{ record }">
<a-button
type="link"
@ -29,6 +33,15 @@
>
{{ t('common.delText') }}
</a-button>
<a-button
type="link"
size="small"
@click="handleLock(record)"
v-auth="'AbpIdentity.User.Lock'"
>
{{ record.lockoutEnabled ? '启用' : '禁用' }}
</a-button>
</template>
</BasicTable>
<CreateAbpUser
@ -47,13 +60,20 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { tableColumns, searchFormSchema, getTableListAsync, deleteUserAsync } from './AbpUser';
import {
tableColumns,
searchFormSchema,
getTableListAsync,
deleteUserAsync,
lockUserAsync,
} from './AbpUser';
import { LockUserInput } from '/@/services/ServiceProxies';
import { useModal } from '/@/components/Modal';
import CreateAbpUser from './CreateAbpUser.vue';
import EditAbpUser from './EditAbpUser.vue';
import { message } from 'ant-design-vue';
import { useI18n } from '/@/hooks/web/useI18n';
import { Tag } from 'ant-design-vue';
export default defineComponent({
name: 'AbpUser',
components: {
@ -61,6 +81,7 @@
TableAction,
CreateAbpUser,
EditAbpUser,
Tag,
},
setup() {
const { t } = useI18n();
@ -108,6 +129,13 @@
await deleteUserAsync({ userId: record.id, reload });
};
const handleLock = async (record: Recordable) => {
let request = new LockUserInput();
request.userId = record.id;
request.locked = !record.lockoutEnabled;
await lockUserAsync(request);
reload();
};
return {
registerTable,
handleEdit,
@ -118,6 +146,7 @@
registerEditAbpUserModal,
t,
reload,
handleLock,
};
},
});

5
content/vue/src/views/sys/login/Login.vue

@ -35,9 +35,6 @@
>
<LoginForm />
<ForgetPasswordForm />
</div>
</div>
</div>
@ -167,7 +164,7 @@
display: flex;
width: 60%;
height: 80px;
margin-left: 85px;
&__title {
font-size: 24px;
color: #fff;

36
content/vue/yarn.lock

@ -2555,6 +2555,15 @@ cli-width@^3.0.0:
resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clipboard@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==
dependencies:
good-listener "^1.2.2"
select "^1.1.2"
tiny-emitter "^2.0.0"
cliui@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
@ -3295,6 +3304,11 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
delegate@^3.1.2:
version "3.2.0"
resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@ -4577,6 +4591,13 @@ gonzales-pe@^4.3.0:
dependencies:
minimist "^1.2.5"
good-listener@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
dependencies:
delegate "^3.1.2"
got@^7.0.0:
version "7.1.0"
resolved "https://registry.npmjs.org/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
@ -7789,6 +7810,11 @@ seek-bzip@^1.0.5:
dependencies:
commander "^2.8.1"
select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
@ -8650,6 +8676,11 @@ timed-out@^4.0.0, timed-out@^4.0.1:
resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
tiny-emitter@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
tinycolor2@^1.4.2:
version "1.4.2"
resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
@ -9308,6 +9339,11 @@ vue-types@^3.0.0, vue-types@^3.0.2:
dependencies:
is-plain-object "3.0.1"
vue3-json-viewer@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/vue3-json-viewer/-/vue3-json-viewer-1.0.4.tgz#cbddcd2c0383315ef1f240f1d5db88e80e20c44a"
integrity sha512-E+FKQ8cGVXeZmS25AMeLlgNkTnewSy6Ex11udMn12ex06XcW3ZTgGfdTvg/oklh49B2pDZN1Osr94QOvgV8h5w==
vue@3.0.11, vue@^3.0.0:
version "3.0.11"
resolved "https://registry.npmjs.org/vue/-/vue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f"

Loading…
Cancel
Save