Merge branch 'abp' of https://gitee.com/ccnetcore/Yi into abp

This commit is contained in:
Xwen
2024-01-02 19:27:07 +08:00
49 changed files with 980 additions and 355 deletions

View File

@@ -1,4 +1,4 @@
<h1 align="center"><img align="left" height="150px" src="https://user-images.githubusercontent.com/68722157/138828506-f58b7c57-5e10-4178-8f7d-5d5e12050113.png"> Yi框架</h1>
<h1 align="center"><img align="left" height="150px" src="https://ccnetcore.com/prod-api/wwwroot/logo.png"> Yi框架</h1>
<h4 align="center">一套以用户体验出发的.Net8 Web开源框架</h4>
<h5 align="center">支持Abp.vNext 版本原生版本、Furion版本前端后台接入Ruoyi Vue3.0</h5>
<h2 align="center">集大成者,终究轮子</h2>

View File

@@ -1,7 +1,11 @@
using System.Diagnostics;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.Mvc;
@@ -75,12 +79,59 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
[scheme] = new string[0]
});
options.SchemaFilter<EnumSchemaFilter>();
}
);
return services;
}
}
/// <summary>
/// Swagger文档枚举字段显示枚举属性和枚举值,以及枚举描述
/// </summary>
public class EnumSchemaFilter : ISchemaFilter
{
/// <summary>
/// 实现接口
/// </summary>
/// <param name="model"></param>
/// <param name="context"></param>
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
model.Type = "string";
model.Format = null;
StringBuilder stringBuilder = new StringBuilder();
Enum.GetNames(context.Type)
.ToList()
.ForEach(name =>
{
Enum e = (Enum)Enum.Parse(context.Type, name);
var descrptionOrNull = GetEnumDescription(e);
model.Enum.Add(new OpenApiString(name));
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
});
model.Description= stringBuilder.ToString();
}
}
private static string? GetEnumDescription(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : null;
}
}
}

View File

@@ -2,6 +2,9 @@
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="MiniExcel" Version="1.31.3" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="8.0.0" />
</ItemGroup>

View File

@@ -3,11 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Validation;
namespace Yi.Framework.Ddd.Application
{
@@ -86,7 +89,7 @@ namespace Yi.Framework.Ddd.Application
/// <param name="id"></param>
/// <returns></returns>
[RemoteService(isEnabled: true)]
public async Task DeleteAsync(IEnumerable<TKey> id)
public virtual async Task DeleteAsync(IEnumerable<TKey> id)
{
await Repository.DeleteManyAsync(id);
}
@@ -95,5 +98,34 @@ namespace Yi.Framework.Ddd.Application
{
return base.DeleteAsync(id);
}
public virtual async Task<IActionResult> GetExportExcelAsync(TGetListInput input)
{
if (input is IPagedResultRequest paged)
{
paged.SkipCount = 0;
paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
}
var output = await this.GetListAsync(input);
var dirPath = $"/wwwroot/temp";
var filePath = $"{dirPath}/{Guid.NewGuid()}.xlsx";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
MiniExcel.SaveAs(filePath, output.Items);
return new FileStreamResult(File.OpenRead(filePath), "application/vnd.ms-excel");
}
public virtual async Task PostImportExcelAsync()
{
}
}
}

View File

@@ -1,4 +1,6 @@
using Volo.Abp.Application;
using Volo.Abp;
using Volo.Abp.Application;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Yi.Framework.Ddd.Application.Contracts;
@@ -8,6 +10,11 @@ namespace Yi.Framework.Ddd.Application
typeof(YiFrameworkDddApplicationContractsModule))]
public class YiFrameworkDddApplicationModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
//分页限制
LimitedResultRequestDto.DefaultMaxResultCount = 10;
LimitedResultRequestDto.MaxMaxResultCount = 10000;
}
}
}

View File

@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore.Repositories
{
public class SqlSugarObjectRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
public ISqlSugarClient _Db => GetDbContextAsync().Result;
private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider;
/// <summary>
/// 获取DB
/// </summary>
/// <returns></returns>
public virtual async Task<ISqlSugarClient> GetDbContextAsync()
{
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
//await Console.Out.WriteLineAsync("获取的id" + db.ContextID);
return db;
}
public IAsyncQueryableExecuter AsyncExecuter => throw new NotImplementedException();
public bool? IsChangeTrackingEnabled => throw new NotImplementedException();
public Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> GetQueryableAsync()
{
throw new NotImplementedException();
}
public async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
await (await GetDbContextAsync()).InsertableByObject(entity).ExecuteCommandAsync();
return entity;
}
public Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails()
{
throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync()
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
}
public class SqlSugarObjectRepository<TEntity, TKey> : SqlSugarObjectRepository<TEntity>, IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>
{
public Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity?> FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
}

View File

@@ -10,7 +10,12 @@ namespace Yi.Framework.SqlSugarCore.Uow
public SqlSugarTransactionApi(ISqlSugarDbContext sqlsugarDbContext)
{
_sqlsugarDbContext = sqlsugarDbContext;
}
public ISqlSugarDbContext GetDbContext()
{
return _sqlsugarDbContext;
}
public async Task CommitAsync(CancellationToken cancellationToken = default)

View File

@@ -82,17 +82,17 @@ namespace Yi.Framework.SqlSugarCore.Uow
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
{
return unitOfWork.Options.IsTransactional
? await CreateDbContextWithTransactionAsync(unitOfWork)
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
return unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
//return unitOfWork.Options.IsTransactional
// ? await CreateDbContextWithTransactionAsync(unitOfWork)
// : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
}
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
{
var transactionApiKey = $"Sqlsugar_Default".ToString();
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarDatabaseApi;
if (activeTransaction == null)
{
var transactionApiKey = $"Sqlsugar_Default"+Guid.NewGuid().ToString();
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
//if (activeTransaction==null|| activeTransaction.Equals(default(SqlSugarTransactionApi)))
//{
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
var transaction = new SqlSugarTransactionApi(
@@ -105,14 +105,15 @@ namespace Yi.Framework.SqlSugarCore.Uow
// Console.WriteLine(dbContext.SqlSugarClient.ContextID);
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
return dbContext;
}
else
{
// await Console.Out.WriteLineAsync("继续老的事务");
// Console.WriteLine(activeTransaction.DbContext.SqlSugarClient);
await activeTransaction.DbContext.SqlSugarClient.Ado.BeginTranAsync();
return (TDbContext)activeTransaction.DbContext;
}
//}
//else
//{
// var db= activeTransaction.GetDbContext().SqlSugarClient;
// // await Console.Out.WriteLineAsync("继续老的事务");
// // Console.WriteLine(activeTransaction.DbContext.SqlSugarClient);
// await activeTransaction.GetDbContext().SqlSugarClient.Ado.BeginTranAsync();
// return (TDbContext)activeTransaction.GetDbContext();
//}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.AuditLogging;
namespace Yi.AuditLogging.SqlSugarCore.Entities
{
public class AuditLogEntity : AuditLog
{
public AuditLogEntity() { }
}
}

View File

@@ -1,266 +1,348 @@
//using System.Linq.Dynamic.Core;
//using System.Net;
//using Volo.Abp.Auditing;
//using Volo.Abp.Domain.Entities;
//using Yi.Framework.SqlSugarCore.Abstractions;
//using Yi.Framework.SqlSugarCore.Repositories;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Net;
using Mapster;
using SqlSugar;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Yi.AuditLogging.SqlSugarCore.Entities;
using Yi.Framework.SqlSugarCore.Repositories;
//namespace Volo.Abp.AuditLogging.EntityFrameworkCore;
namespace Volo.Abp.AuditLogging.EntityFrameworkCore;
//public class SqlSugarCoreAuditLogRepository : SqlSugarRepository<AuditLog, Guid>, IAuditLogRepository
//{
// public SqlSugarCoreAuditLogRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(sugarDbContextProvider)
// {
// }
public class SqlSugarCoreAuditLogRepository : SqlSugarObjectRepository<AuditLog, Guid>,IAuditLogRepository
{
public virtual async Task<List<AuditLog>> GetListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string clientIpAddress = null,
string correlationId = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var query = await GetListQueryAsync(
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
clientIpAddress,
correlationId,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode,
includeDetails
);
// public virtual async Task<List<AuditLog>> GetListAsync(
// string sorting = null,
// int maxResultCount = 50,
// int skipCount = 0,
// DateTime? startTime = null,
// DateTime? endTime = null,
// string httpMethod = null,
// string url = null,
// Guid? userId = null,
// string userName = null,
// string applicationName = null,
// string clientIpAddress = null,
// string correlationId = null,
// int? maxExecutionDuration = null,
// int? minExecutionDuration = null,
// bool? hasException = null,
// HttpStatusCode? httpStatusCode = null,
// bool includeDetails = false,
// CancellationToken cancellationToken = default)
// {
// var query = await GetListQueryAsync(
// startTime,
// endTime,
// httpMethod,
// url,
// userId,
// userName,
// applicationName,
// clientIpAddress,
// correlationId,
// maxExecutionDuration,
// minExecutionDuration,
// hasException,
// httpStatusCode,
// includeDetails
// );
var auditLogs = await query
.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(AuditLog.ExecutionTime) + " DESC") : sorting)
.ToPageListAsync(skipCount, maxResultCount, cancellationToken);
// var auditLogs = await query
// .OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(AuditLog.ExecutionTime) + " DESC") : sorting)
// .PageBy(skipCount, maxResultCount)
// .ToListAsync(GetCancellationToken(cancellationToken));
return auditLogs.Adapt<List<AuditLog>>();
}
// return auditLogs;
// }
public virtual async Task<long> GetCountAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string clientIpAddress = null,
string correlationId = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
CancellationToken cancellationToken = default)
{
var query = await GetListQueryAsync(
startTime,
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
clientIpAddress,
correlationId,
maxExecutionDuration,
minExecutionDuration,
hasException,
httpStatusCode
);
// public virtual async Task<long> GetCountAsync(
// DateTime? startTime = null,
// DateTime? endTime = null,
// string httpMethod = null,
// string url = null,
// Guid? userId = null,
// string userName = null,
// string applicationName = null,
// string clientIpAddress = null,
// string correlationId = null,
// int? maxExecutionDuration = null,
// int? minExecutionDuration = null,
// bool? hasException = null,
// HttpStatusCode? httpStatusCode = null,
// CancellationToken cancellationToken = default)
// {
// var query = await GetListQueryAsync(
// startTime,
// endTime,
// httpMethod,
// url,
// userId,
// userName,
// applicationName,
// clientIpAddress,
// correlationId,
// maxExecutionDuration,
// minExecutionDuration,
// hasException,
// httpStatusCode
// );
var totalCount = await query.CountAsync(cancellationToken);
// var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken));
return totalCount;
}
// return totalCount;
// }
protected virtual async Task<ISugarQueryable<AuditLogEntity>> GetListQueryAsync(
DateTime? startTime = null,
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string clientIpAddress = null,
string correlationId = null,
int? maxExecutionDuration = null,
int? minExecutionDuration = null,
bool? hasException = null,
HttpStatusCode? httpStatusCode = null,
bool includeDetails = false)
{
var nHttpStatusCode = (int?)httpStatusCode;
return (await GetDbContextAsync()).Queryable<AuditLogEntity>()
.WhereIF(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime)
.WhereIF(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime)
.WhereIF(hasException.HasValue && hasException.Value, auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "")
.WhereIF(hasException.HasValue && !hasException.Value, auditLog => auditLog.Exceptions == null || auditLog.Exceptions == "")
.WhereIF(httpMethod != null, auditLog => auditLog.HttpMethod == httpMethod)
.WhereIF(url != null, auditLog => auditLog.Url != null && auditLog.Url.Contains(url))
.WhereIF(userId != null, auditLog => auditLog.UserId == userId)
.WhereIF(userName != null, auditLog => auditLog.UserName == userName)
.WhereIF(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
.WhereIF(clientIpAddress != null, auditLog => auditLog.ClientIpAddress != null && auditLog.ClientIpAddress == clientIpAddress)
.WhereIF(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)
.WhereIF(httpStatusCode != null && httpStatusCode > 0, auditLog => auditLog.HttpStatusCode == nHttpStatusCode)
.WhereIF(maxExecutionDuration != null && maxExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration <= maxExecutionDuration)
.WhereIF(minExecutionDuration != null && minExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration >= minExecutionDuration);
}
// protected virtual async Task<IQueryable<AuditLog>> GetListQueryAsync(
// DateTime? startTime = null,
// DateTime? endTime = null,
// string httpMethod = null,
// string url = null,
// Guid? userId = null,
// string userName = null,
// string applicationName = null,
// string clientIpAddress = null,
// string correlationId = null,
// int? maxExecutionDuration = null,
// int? minExecutionDuration = null,
// bool? hasException = null,
// HttpStatusCode? httpStatusCode = null,
// bool includeDetails = false)
// {
// var nHttpStatusCode = (int?)httpStatusCode;
// return (await GetDbSetAsync()).AsNoTracking()
// .IncludeDetails(includeDetails)
// .WhereIf(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime)
// .WhereIf(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime)
// .WhereIf(hasException.HasValue && hasException.Value, auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "")
// .WhereIf(hasException.HasValue && !hasException.Value, auditLog => auditLog.Exceptions == null || auditLog.Exceptions == "")
// .WhereIf(httpMethod != null, auditLog => auditLog.HttpMethod == httpMethod)
// .WhereIf(url != null, auditLog => auditLog.Url != null && auditLog.Url.Contains(url))
// .WhereIf(userId != null, auditLog => auditLog.UserId == userId)
// .WhereIf(userName != null, auditLog => auditLog.UserName == userName)
// .WhereIf(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
// .WhereIf(clientIpAddress != null, auditLog => auditLog.ClientIpAddress != null && auditLog.ClientIpAddress == clientIpAddress)
// .WhereIf(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)
// .WhereIf(httpStatusCode != null && httpStatusCode > 0, auditLog => auditLog.HttpStatusCode == nHttpStatusCode)
// .WhereIf(maxExecutionDuration != null && maxExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration <= maxExecutionDuration)
// .WhereIf(minExecutionDuration != null && minExecutionDuration.Value > 0, auditLog => auditLog.ExecutionDuration >= minExecutionDuration);
// }
public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
DateTime startDate,
DateTime endDate,
CancellationToken cancellationToken = default)
{
var result = await (await GetDbContextAsync()).Queryable<AuditLogEntity>()
.Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate)
.OrderBy(t => t.ExecutionTime)
.GroupBy(t => new { t.ExecutionTime.Date })
.Select(g => new { Day =SqlFunc.AggregateMin(g.ExecutionTime), avgExecutionTime = SqlFunc.AggregateAvg( g.ExecutionDuration) })
.ToListAsync(cancellationToken);
// public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
// DateTime startDate,
// DateTime endDate,
// CancellationToken cancellationToken = default)
// {
// var result = await (await GetDbSetAsync()).AsNoTracking()
// .Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate)
// .OrderBy(t => t.ExecutionTime)
// .GroupBy(t => new { t.ExecutionTime.Date })
// .Select(g => new { Day = g.Min(t => t.ExecutionTime), avgExecutionTime = g.Average(t => t.ExecutionDuration) })
// .ToListAsync(GetCancellationToken(cancellationToken));
return result.ToDictionary(element => element.Day.ClearTime(), element => (double)element.avgExecutionTime);
}
// return result.ToDictionary(element => element.Day.ClearTime(), element => element.avgExecutionTime);
// }
public virtual async Task<EntityChange> GetEntityChange(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{
var entityChange = await (await GetDbContextAsync()).Queryable<EntityChange>()
.Where(x => x.Id == entityChangeId)
.OrderBy(x => x.Id)
.FirstAsync(cancellationToken);
// [Obsolete("Use WithDetailsAsync method.")]
// public override IQueryable<AuditLog> WithDetails()
// {
// return GetQueryable().IncludeDetails();
// }
if (entityChange == null)
{
throw new EntityNotFoundException(typeof(EntityChange));
}
// public override async Task<IQueryable<AuditLog>> WithDetailsAsync()
// {
// return (await GetQueryableAsync()).IncludeDetails();
// }
return entityChange;
}
// public virtual async Task<EntityChange> GetEntityChange(
// Guid entityChangeId,
// CancellationToken cancellationToken = default)
// {
// var entityChange = await (await GetDbContextAsync()).Set<EntityChange>()
// .AsNoTracking()
// .IncludeDetails()
// .Where(x => x.Id == entityChangeId)
// .OrderBy(x => x.Id)
// .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
public virtual async Task<List<EntityChange>> GetEntityChangeListAsync(
string sorting = null,
int maxResultCount = 50,
int skipCount = 0,
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, includeDetails);
// if (entityChange == null)
// {
// throw new EntityNotFoundException(typeof(EntityChange));
// }
return await query.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(EntityChange.ChangeTime) + " DESC") : sorting)
.ToPageListAsync(skipCount, maxResultCount, cancellationToken);
}
// return entityChange;
// }
public virtual async Task<long> GetEntityChangeCountAsync(
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
CancellationToken cancellationToken = default)
{
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName);
// public virtual async Task<List<EntityChange>> GetEntityChangeListAsync(
// string sorting = null,
// int maxResultCount = 50,
// int skipCount = 0,
// Guid? auditLogId = null,
// DateTime? startTime = null,
// DateTime? endTime = null,
// EntityChangeType? changeType = null,
// string entityId = null,
// string entityTypeFullName = null,
// bool includeDetails = false,
// CancellationToken cancellationToken = default)
// {
// var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName, includeDetails);
var totalCount = await query.CountAsync(cancellationToken);
// return await query.OrderBy(sorting.IsNullOrWhiteSpace() ? (nameof(EntityChange.ChangeTime) + " DESC") : sorting)
// .PageBy(skipCount, maxResultCount)
// .ToListAsync(GetCancellationToken(cancellationToken));
// }
return totalCount;
}
// public virtual async Task<long> GetEntityChangeCountAsync(
// Guid? auditLogId = null,
// DateTime? startTime = null,
// DateTime? endTime = null,
// EntityChangeType? changeType = null,
// string entityId = null,
// string entityTypeFullName = null,
// CancellationToken cancellationToken = default)
// {
// var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId, entityTypeFullName);
public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(
Guid entityChangeId,
CancellationToken cancellationToken = default)
{
var auditLog = await (await GetDbContextAsync()).Queryable<AuditLogEntity>()
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(cancellationToken);
// var totalCount = await query.LongCountAsync(GetCancellationToken(cancellationToken));
return new EntityChangeWithUsername()
{
EntityChange = auditLog.EntityChanges.First(x => x.Id == entityChangeId),
UserName = auditLog.UserName
};
}
// return totalCount;
// }
public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(
string entityId,
string entityTypeFullName,
CancellationToken cancellationToken = default)
{
var dbContext = await GetDbContextAsync();
// public virtual async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(
// Guid entityChangeId,
// CancellationToken cancellationToken = default)
// {
// var auditLog = await (await GetDbSetAsync()).AsNoTracking().IncludeDetails()
// .Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId)).FirstAsync(GetCancellationToken(cancellationToken));
var query = dbContext.Queryable<EntityChange>()
.Where(x => x.EntityId == entityId && x.EntityTypeFullName == entityTypeFullName);
return await query.LeftJoin<AuditLogEntity>((change, audit) => change.AuditLogId == audit.Id)
.Select((change, audit) => new EntityChangeWithUsername { EntityChange = change, UserName = audit.UserName }, true)
.OrderByDescending(x => x.EntityChange.ChangeTime).ToListAsync(cancellationToken);
// return new EntityChangeWithUsername()
// {
// EntityChange = auditLog.EntityChanges.First(x => x.Id == entityChangeId),
// UserName = auditLog.UserName
// };
// }
}
// public virtual async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(
// string entityId,
// string entityTypeFullName,
// CancellationToken cancellationToken = default)
// {
// var dbContext = await GetDbContextAsync();
protected virtual async Task<ISugarQueryable<EntityChange>> GetEntityChangeListQueryAsync(
Guid? auditLogId = null,
DateTime? startTime = null,
DateTime? endTime = null,
EntityChangeType? changeType = null,
string entityId = null,
string entityTypeFullName = null,
bool includeDetails = false)
{
return (await GetDbContextAsync())
.Queryable<EntityChange>()
.WhereIF(auditLogId.HasValue, e => e.AuditLogId == auditLogId)
.WhereIF(startTime.HasValue, e => e.ChangeTime >= startTime)
.WhereIF(endTime.HasValue, e => e.ChangeTime <= endTime)
.WhereIF(changeType.HasValue, e => e.ChangeType == changeType)
.WhereIF(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId)
.WhereIF(!string.IsNullOrWhiteSpace(entityTypeFullName), e => e.EntityTypeFullName.Contains(entityTypeFullName));
}
// var query = dbContext.Set<EntityChange>()
// .AsNoTracking()
// .IncludeDetails()
// .Where(x => x.EntityId == entityId && x.EntityTypeFullName == entityTypeFullName);
Task<List<AuditLog>> IAuditLogRepository.GetListAsync(string sorting, int maxResultCount, int skipCount, DateTime? startTime, DateTime? endTime, string httpMethod, string url, Guid? userId, string userName, string applicationName, string clientIpAddress, string correlationId, int? maxExecutionDuration, int? minExecutionDuration, bool? hasException, HttpStatusCode? httpStatusCode, bool includeDetails, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
// return await (from e in query
// join auditLog in dbContext.AuditLogs on e.AuditLogId equals auditLog.Id
// select new EntityChangeWithUsername { EntityChange = e, UserName = auditLog.UserName })
// .OrderByDescending(x => x.EntityChange.ChangeTime).ToListAsync(GetCancellationToken(cancellationToken));
// }
// protected virtual async Task<IQueryable<EntityChange>> GetEntityChangeListQueryAsync(
// Guid? auditLogId = null,
// DateTime? startTime = null,
// DateTime? endTime = null,
// EntityChangeType? changeType = null,
// string entityId = null,
// string entityTypeFullName = null,
// bool includeDetails = false)
// {
// return (await GetDbContextAsync())
// .Set<EntityChange>()
// .AsNoTracking()
// .IncludeDetails(includeDetails)
// .WhereIf(auditLogId.HasValue, e => e.AuditLogId == auditLogId)
// .WhereIf(startTime.HasValue, e => e.ChangeTime >= startTime)
// .WhereIf(endTime.HasValue, e => e.ChangeTime <= endTime)
// .WhereIf(changeType.HasValue, e => e.ChangeType == changeType)
// .WhereIf(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId)
// .WhereIf(!string.IsNullOrWhiteSpace(entityTypeFullName), e => e.EntityTypeFullName.Contains(entityTypeFullName));
// }
//}
public Task<AuditLog> GetAsync(Expression<Func<AuditLog, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteAsync(Expression<Func<AuditLog, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteDirectAsync(Expression<Func<AuditLog, bool>> predicate, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
IQueryable<AuditLog> IReadOnlyRepository<AuditLog>.WithDetails()
{
throw new NotImplementedException();
}
public IQueryable<AuditLog> WithDetails(params Expression<Func<AuditLog, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
Task<IQueryable<AuditLog>> IReadOnlyRepository<AuditLog>.WithDetailsAsync()
{
throw new NotImplementedException();
}
public Task<IQueryable<AuditLog>> WithDetailsAsync(params Expression<Func<AuditLog, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
Task<IQueryable<AuditLog>> IReadOnlyRepository<AuditLog>.GetQueryableAsync()
{
throw new NotImplementedException();
}
public Task<List<AuditLog>> GetListAsync(Expression<Func<AuditLog, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<AuditLog> InsertAsync(AuditLog entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task InsertManyAsync(IEnumerable<AuditLog> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<AuditLog> UpdateAsync(AuditLog entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task UpdateManyAsync(IEnumerable<AuditLog> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteAsync(AuditLog entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteManyAsync(IEnumerable<AuditLog> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
Task<AuditLog> IReadOnlyBasicRepository<AuditLog, Guid>.GetAsync(Guid id, bool includeDetails, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
Task<AuditLog?> IReadOnlyBasicRepository<AuditLog, Guid>.FindAsync(Guid id, bool includeDetails, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
Task<List<AuditLog>> IReadOnlyBasicRepository<AuditLog>.GetListAsync(bool includeDetails, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
Task<List<AuditLog>> IReadOnlyBasicRepository<AuditLog>.GetPagedListAsync(int skipCount, int maxResultCount, string sorting, bool includeDetails, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

View File

@@ -11,6 +11,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj" />
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj" />
</ItemGroup>

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using SqlSugar;
using Volo.Abp.AuditLogging;
using Volo.Abp.DependencyInjection;
@@ -23,11 +18,11 @@ namespace Yi.AuditLogging.SqlSugarCore
column.DbTableName = AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogs";
column.IfTable<AuditLog>()
.UpdateProperty(x => x.Id,
x =>
{
x.IsPrimarykey = true;
x.IsPrimarykey = true;
})
.UpdateProperty(x => x.ApplicationName,
@@ -38,97 +33,98 @@ namespace Yi.AuditLogging.SqlSugarCore
});
//builder.Entity<AuditLog>(b =>
//{
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogs", AbpAuditLoggingDbProperties.DbSchema);
// builder.Entity<AuditLog>(b =>
// {
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogs", AbpAuditLoggingDbProperties.DbSchema);
// b.ConfigureByConvention();
// b.ConfigureByConvention();
// b.Property(x => x.ApplicationName).HasMaxLength(AuditLogConsts.MaxApplicationNameLength).HasColumnName(nameof(AuditLog.ApplicationName));
// b.Property(x => x.ClientIpAddress).HasMaxLength(AuditLogConsts.MaxClientIpAddressLength).HasColumnName(nameof(AuditLog.ClientIpAddress));
// b.Property(x => x.ClientName).HasMaxLength(AuditLogConsts.MaxClientNameLength).HasColumnName(nameof(AuditLog.ClientName));
// b.Property(x => x.ClientId).HasMaxLength(AuditLogConsts.MaxClientIdLength).HasColumnName(nameof(AuditLog.ClientId));
// b.Property(x => x.CorrelationId).HasMaxLength(AuditLogConsts.MaxCorrelationIdLength).HasColumnName(nameof(AuditLog.CorrelationId));
// b.Property(x => x.BrowserInfo).HasMaxLength(AuditLogConsts.MaxBrowserInfoLength).HasColumnName(nameof(AuditLog.BrowserInfo));
// b.Property(x => x.HttpMethod).HasMaxLength(AuditLogConsts.MaxHttpMethodLength).HasColumnName(nameof(AuditLog.HttpMethod));
// b.Property(x => x.Url).HasMaxLength(AuditLogConsts.MaxUrlLength).HasColumnName(nameof(AuditLog.Url));
// b.Property(x => x.HttpStatusCode).HasColumnName(nameof(AuditLog.HttpStatusCode));
// b.Property(x => x.ApplicationName).HasMaxLength(AuditLogConsts.MaxApplicationNameLength).HasColumnName(nameof(AuditLog.ApplicationName));
// b.Property(x => x.ClientIpAddress).HasMaxLength(AuditLogConsts.MaxClientIpAddressLength).HasColumnName(nameof(AuditLog.ClientIpAddress));
// b.Property(x => x.ClientName).HasMaxLength(AuditLogConsts.MaxClientNameLength).HasColumnName(nameof(AuditLog.ClientName));
// b.Property(x => x.ClientId).HasMaxLength(AuditLogConsts.MaxClientIdLength).HasColumnName(nameof(AuditLog.ClientId));
// b.Property(x => x.CorrelationId).HasMaxLength(AuditLogConsts.MaxCorrelationIdLength).HasColumnName(nameof(AuditLog.CorrelationId));
// b.Property(x => x.BrowserInfo).HasMaxLength(AuditLogConsts.MaxBrowserInfoLength).HasColumnName(nameof(AuditLog.BrowserInfo));
// b.Property(x => x.HttpMethod).HasMaxLength(AuditLogConsts.MaxHttpMethodLength).HasColumnName(nameof(AuditLog.HttpMethod));
// b.Property(x => x.Url).HasMaxLength(AuditLogConsts.MaxUrlLength).HasColumnName(nameof(AuditLog.Url));
// b.Property(x => x.HttpStatusCode).HasColumnName(nameof(AuditLog.HttpStatusCode));
// b.Property(x => x.Comments).HasMaxLength(AuditLogConsts.MaxCommentsLength).HasColumnName(nameof(AuditLog.Comments));
// b.Property(x => x.ExecutionDuration).HasColumnName(nameof(AuditLog.ExecutionDuration));
// b.Property(x => x.ImpersonatorTenantId).HasColumnName(nameof(AuditLog.ImpersonatorTenantId));
// b.Property(x => x.ImpersonatorUserId).HasColumnName(nameof(AuditLog.ImpersonatorUserId));
// b.Property(x => x.ImpersonatorTenantName).HasMaxLength(AuditLogConsts.MaxTenantNameLength).HasColumnName(nameof(AuditLog.ImpersonatorTenantName));
// b.Property(x => x.ImpersonatorUserName).HasMaxLength(AuditLogConsts.MaxUserNameLength).HasColumnName(nameof(AuditLog.ImpersonatorUserName));
// b.Property(x => x.UserId).HasColumnName(nameof(AuditLog.UserId));
// b.Property(x => x.UserName).HasMaxLength(AuditLogConsts.MaxUserNameLength).HasColumnName(nameof(AuditLog.UserName));
// b.Property(x => x.TenantId).HasColumnName(nameof(AuditLog.TenantId));
// b.Property(x => x.TenantName).HasMaxLength(AuditLogConsts.MaxTenantNameLength).HasColumnName(nameof(AuditLog.TenantName));
// b.Property(x => x.Comments).HasMaxLength(AuditLogConsts.MaxCommentsLength).HasColumnName(nameof(AuditLog.Comments));
// b.Property(x => x.ExecutionDuration).HasColumnName(nameof(AuditLog.ExecutionDuration));
// b.Property(x => x.ImpersonatorTenantId).HasColumnName(nameof(AuditLog.ImpersonatorTenantId));
// b.Property(x => x.ImpersonatorUserId).HasColumnName(nameof(AuditLog.ImpersonatorUserId));
// b.Property(x => x.ImpersonatorTenantName).HasMaxLength(AuditLogConsts.MaxTenantNameLength).HasColumnName(nameof(AuditLog.ImpersonatorTenantName));
// b.Property(x => x.ImpersonatorUserName).HasMaxLength(AuditLogConsts.MaxUserNameLength).HasColumnName(nameof(AuditLog.ImpersonatorUserName));
// b.Property(x => x.UserId).HasColumnName(nameof(AuditLog.UserId));
// b.Property(x => x.UserName).HasMaxLength(AuditLogConsts.MaxUserNameLength).HasColumnName(nameof(AuditLog.UserName));
// b.Property(x => x.TenantId).HasColumnName(nameof(AuditLog.TenantId));
// b.Property(x => x.TenantName).HasMaxLength(AuditLogConsts.MaxTenantNameLength).HasColumnName(nameof(AuditLog.TenantName));
// b.HasMany(a => a.Actions).WithOne().HasForeignKey(x => x.AuditLogId).IsRequired();
// b.HasMany(a => a.EntityChanges).WithOne().HasForeignKey(x => x.AuditLogId).IsRequired();
// b.HasMany(a => a.Actions).WithOne().HasForeignKey(x => x.AuditLogId).IsRequired();
// b.HasMany(a => a.EntityChanges).WithOne().HasForeignKey(x => x.AuditLogId).IsRequired();
// b.HasIndex(x => new { x.TenantId, x.ExecutionTime });
// b.HasIndex(x => new { x.TenantId, x.UserId, x.ExecutionTime });
// b.HasIndex(x => new { x.TenantId, x.ExecutionTime });
// b.HasIndex(x => new { x.TenantId, x.UserId, x.ExecutionTime });
// b.ApplyObjectExtensionMappings();
//});
// b.ApplyObjectExtensionMappings();
// });
//builder.Entity<AuditLogAction>(b =>
//{
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogActions", AbpAuditLoggingDbProperties.DbSchema);
// builder.Entity<AuditLogAction>(b =>
// {
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "AuditLogActions", AbpAuditLoggingDbProperties.DbSchema);
// b.ConfigureByConvention();
// b.ConfigureByConvention();
// b.Property(x => x.AuditLogId).HasColumnName(nameof(AuditLogAction.AuditLogId));
// b.Property(x => x.ServiceName).HasMaxLength(AuditLogActionConsts.MaxServiceNameLength).HasColumnName(nameof(AuditLogAction.ServiceName));
// b.Property(x => x.MethodName).HasMaxLength(AuditLogActionConsts.MaxMethodNameLength).HasColumnName(nameof(AuditLogAction.MethodName));
// b.Property(x => x.Parameters).HasMaxLength(AuditLogActionConsts.MaxParametersLength).HasColumnName(nameof(AuditLogAction.Parameters));
// b.Property(x => x.ExecutionTime).HasColumnName(nameof(AuditLogAction.ExecutionTime));
// b.Property(x => x.ExecutionDuration).HasColumnName(nameof(AuditLogAction.ExecutionDuration));
// b.Property(x => x.AuditLogId).HasColumnName(nameof(AuditLogAction.AuditLogId));
// b.Property(x => x.ServiceName).HasMaxLength(AuditLogActionConsts.MaxServiceNameLength).HasColumnName(nameof(AuditLogAction.ServiceName));
// b.Property(x => x.MethodName).HasMaxLength(AuditLogActionConsts.MaxMethodNameLength).HasColumnName(nameof(AuditLogAction.MethodName));
// b.Property(x => x.Parameters).HasMaxLength(AuditLogActionConsts.MaxParametersLength).HasColumnName(nameof(AuditLogAction.Parameters));
// b.Property(x => x.ExecutionTime).HasColumnName(nameof(AuditLogAction.ExecutionTime));
// b.Property(x => x.ExecutionDuration).HasColumnName(nameof(AuditLogAction.ExecutionDuration));
// b.HasIndex(x => new { x.AuditLogId });
// b.HasIndex(x => new { x.TenantId, x.ServiceName, x.MethodName, x.ExecutionTime });
// b.HasIndex(x => new { x.AuditLogId });
// b.HasIndex(x => new { x.TenantId, x.ServiceName, x.MethodName, x.ExecutionTime });
// b.ApplyObjectExtensionMappings();
//});
// b.ApplyObjectExtensionMappings();
// });
//builder.Entity<EntityChange>(b =>
//{
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "EntityChanges", AbpAuditLoggingDbProperties.DbSchema);
// builder.Entity<EntityChange>(b =>
// {
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "EntityChanges", AbpAuditLoggingDbProperties.DbSchema);
// b.ConfigureByConvention();
// b.ConfigureByConvention();
// b.Property(x => x.EntityTypeFullName).HasMaxLength(EntityChangeConsts.MaxEntityTypeFullNameLength).IsRequired().HasColumnName(nameof(EntityChange.EntityTypeFullName));
// b.Property(x => x.EntityId).HasMaxLength(EntityChangeConsts.MaxEntityIdLength).IsRequired().HasColumnName(nameof(EntityChange.EntityId));
// b.Property(x => x.AuditLogId).IsRequired().HasColumnName(nameof(EntityChange.AuditLogId));
// b.Property(x => x.ChangeTime).IsRequired().HasColumnName(nameof(EntityChange.ChangeTime));
// b.Property(x => x.ChangeType).IsRequired().HasColumnName(nameof(EntityChange.ChangeType));
// b.Property(x => x.TenantId).HasColumnName(nameof(EntityChange.TenantId));
// b.Property(x => x.EntityTypeFullName).HasMaxLength(EntityChangeConsts.MaxEntityTypeFullNameLength).IsRequired().HasColumnName(nameof(EntityChange.EntityTypeFullName));
// b.Property(x => x.EntityId).HasMaxLength(EntityChangeConsts.MaxEntityIdLength).IsRequired().HasColumnName(nameof(EntityChange.EntityId));
// b.Property(x => x.AuditLogId).IsRequired().HasColumnName(nameof(EntityChange.AuditLogId));
// b.Property(x => x.ChangeTime).IsRequired().HasColumnName(nameof(EntityChange.ChangeTime));
// b.Property(x => x.ChangeType).IsRequired().HasColumnName(nameof(EntityChange.ChangeType));
// b.Property(x => x.TenantId).HasColumnName(nameof(EntityChange.TenantId));
// b.HasMany(a => a.PropertyChanges).WithOne().HasForeignKey(x => x.EntityChangeId);
// b.HasMany(a => a.PropertyChanges).WithOne().HasForeignKey(x => x.EntityChangeId);
// b.HasIndex(x => new { x.AuditLogId });
// b.HasIndex(x => new { x.TenantId, x.EntityTypeFullName, x.EntityId });
// b.HasIndex(x => new { x.AuditLogId });
// b.HasIndex(x => new { x.TenantId, x.EntityTypeFullName, x.EntityId });
// b.ApplyObjectExtensionMappings();
//});
// b.ApplyObjectExtensionMappings();
// });
//builder.Entity<EntityPropertyChange>(b =>
//{
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "EntityPropertyChanges", AbpAuditLoggingDbProperties.DbSchema);
// builder.Entity<EntityPropertyChange>(b =>
// {
// b.ToTable(AbpAuditLoggingDbProperties.DbTablePrefix + "EntityPropertyChanges", AbpAuditLoggingDbProperties.DbSchema);
// b.ConfigureByConvention();
// b.ConfigureByConvention();
// b.Property(x => x.NewValue).HasMaxLength(EntityPropertyChangeConsts.MaxNewValueLength).HasColumnName(nameof(EntityPropertyChange.NewValue));
// b.Property(x => x.PropertyName).HasMaxLength(EntityPropertyChangeConsts.MaxPropertyNameLength).IsRequired().HasColumnName(nameof(EntityPropertyChange.PropertyName));
// b.Property(x => x.PropertyTypeFullName).HasMaxLength(EntityPropertyChangeConsts.MaxPropertyTypeFullNameLength).IsRequired().HasColumnName(nameof(EntityPropertyChange.PropertyTypeFullName));
// b.Property(x => x.OriginalValue).HasMaxLength(EntityPropertyChangeConsts.MaxOriginalValueLength).HasColumnName(nameof(EntityPropertyChange.OriginalValue));
// b.Property(x => x.NewValue).HasMaxLength(EntityPropertyChangeConsts.MaxNewValueLength).HasColumnName(nameof(EntityPropertyChange.NewValue));
// b.Property(x => x.PropertyName).HasMaxLength(EntityPropertyChangeConsts.MaxPropertyNameLength).IsRequired().HasColumnName(nameof(EntityPropertyChange.PropertyName));
// b.Property(x => x.PropertyTypeFullName).HasMaxLength(EntityPropertyChangeConsts.MaxPropertyTypeFullNameLength).IsRequired().HasColumnName(nameof(EntityPropertyChange.PropertyTypeFullName));
// b.Property(x => x.OriginalValue).HasMaxLength(EntityPropertyChangeConsts.MaxOriginalValueLength).HasColumnName(nameof(EntityPropertyChange.OriginalValue));
// b.HasIndex(x => new { x.EntityChangeId });
// b.HasIndex(x => new { x.EntityChangeId });
// b.ApplyObjectExtensionMappings();
//});
// b.ApplyObjectExtensionMappings();
// });
//}
}
}
}
}

View File

@@ -1,4 +1,7 @@
using Volo.Abp.AuditLogging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.AuditLogging;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Yi.Framework.SqlSugarCore;
@@ -6,11 +9,13 @@ namespace Yi.AuditLogging.SqlSugarCore
{
[DependsOn(typeof(AbpAuditLoggingDomainModule))]
[DependsOn(typeof(YiFrameworkSqlSugarCoreModule))]
public class YiAuditLoggingSqlSugarCoreModule:AbpModule
public class YiAuditLoggingSqlSugarCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(new ServiceDescriptor(typeof(IAuditLogRepository), typeof(SqlSugarCoreAuditLogRepository), lifetime: ServiceLifetime.Transient));
context.Services.AddYiDbContext<YiAuditLoggingDbContext>();
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Article
{
public class ArticleImprotDto
{
/// <summary>
/// 主题id
/// </summary>
[Required]
public Guid DiscussId { get; set; }
public Guid ArticleParentId { get; set; }= Guid.Empty;
public ArticleImportTypeEnum ImportType { get; set; } = ArticleImportTypeEnum.Defalut;
}
}

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@@ -13,8 +15,10 @@ using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Extensions;
using Yi.Framework.Bbs.Domain.Managers;
using Yi.Framework.Bbs.Domain.Repositories;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Model;
using Yi.Framework.Core.Extensions;
using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Domain.Authorization;
@@ -32,18 +36,20 @@ namespace Yi.Framework.Bbs.Application.Services
{
public ArticleService(IArticleRepository articleRepository,
ISqlSugarRepository<DiscussEntity> discussRepository,
IDiscussService discussService) : base(articleRepository)
IDiscussService discussService,
ForumManager forumManager) : base(articleRepository)
{
_articleRepository = articleRepository;
_discussRepository = discussRepository;
_discussService = discussService;
_forumManager = forumManager;
}
private IArticleRepository _articleRepository { get; set; }
private ISqlSugarRepository<DiscussEntity> _discussRepository { get; set; }
private IDiscussService _discussService { get; set; }
private ForumManager _forumManager;
private IArticleRepository _articleRepository;
private ISqlSugarRepository<DiscussEntity> _discussRepository;
private IDiscussService _discussService;
public override async Task<PagedResultDto<ArticleGetListOutputDto>> GetListAsync(ArticleGetListInputVo input)
{
@@ -134,6 +140,41 @@ namespace Yi.Framework.Bbs.Application.Services
}
/// <summary>
/// 导入文章
/// </summary>
/// <returns></returns>
public async Task PostImportAsync([FromQuery] ArticleImprotDto input, [FromForm][Required] IFormFileCollection file)
{
var fileObjs = new List<FileObject>();
if (file.Count > 0)
{
foreach (var item in file)
{
if (item.Length > 0)
{
using (var stream = item.OpenReadStream())
{
using (var fileStream = new MemoryStream())
{
await item.CopyToAsync(fileStream);
var bytes = fileStream.ToArray();
// 将字节转换成字符串
var content = Encoding.UTF8.GetString(bytes);
fileObjs.Add(new FileObject() { FileName = item.FileName, Content = content });
}
}
}
}
}
else
{
throw new UserFriendlyException("未选择文件");
}
//使用简单工厂根据传入的类型进行判断
await _forumManager.PostImportAsync(input.DiscussId, input.ArticleParentId, fileObjs, input.ImportType);
}
/// <summary>

View File

@@ -18,5 +18,16 @@ namespace Yi.Framework.Bbs.Application.Services
{
return Task.FromResult("你好世界");
}
/// <summary>
/// 获取头像文件
/// </summary>
/// <returns></returns>
public List<string> GetIcon()
{
return Directory.GetFiles("wwwroot/icon").Select(x => "wwwroot/icon/"+ Path.GetFileName(x)).ToList();
}
}
}

View File

@@ -0,0 +1,16 @@
using System.ComponentModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Yi.Framework.Bbs.Domain.Shared.Enums
{
[JsonConverter(typeof(StringEnumConverter))]
public enum ArticleImportTypeEnum
{
[Description("默认导入方式")]
Defalut,
[Description("vuePresss方式")]
VuePress
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Bbs.Domain.Shared.Model
{
public class FileObject
{
public string Content { get; set; }
public string FileName { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Model;
namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
{
public abstract class AbstractArticleImport
{
public virtual List<ArticleEntity> Import(Guid discussId,Guid articleParentId, List<FileObject> fileObjs)
{
var articles = Convert(fileObjs);
articles.ForEach(article =>
{
article.DiscussId = discussId;
article.ParentId = articleParentId;
});
return articles;
}
public abstract List<ArticleEntity> Convert(List<FileObject> fileObjs);
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Model;
namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
{
internal class DefaultArticleImport : AbstractArticleImport
{
public override List<ArticleEntity> Convert(List<FileObject> fileObjs)
{
return fileObjs.OrderBy(x => x.FileName).Select(x => new ArticleEntity { Name = x.FileName, Content = x.Content }).ToList();
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Model;
namespace Yi.Framework.Bbs.Domain.Managers.ArticleImport
{
internal class VuePressArticleImport : AbstractArticleImport
{
public override List<ArticleEntity> Convert(List<FileObject> fileObjs)
{
//排序及处理目录名称
var fileNameHandler = fileObjs.OrderBy(x => x.FileName).Select(x =>
{
var f = new FileObject { Content = x.Content };
//除去数字
f.FileName = x.FileName.Split('.')[1];
return f;
});
//处理内容
var fileContentHandler= fileNameHandler.Select(x =>
{
var f = new FileObject { FileName = x.FileName };
var lines = x.Content.SplitToLines();
var num = 0;
var startIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
if (lines[i] == "---")
{
num++;
if (num == 2)
{
startIndex = i;
break;
}
}
}
var linesRef = lines.ToList();
linesRef.RemoveRange(0, startIndex+1);
var result = string.Join(Environment.NewLine, linesRef);
f.Content = result;
return f;
});
var output = fileContentHandler.Select(x => new ArticleEntity() { Content = x.Content, Name = x.FileName }).ToList();
return output;
}
}
}

View File

@@ -1,5 +1,10 @@
using Volo.Abp.Domain.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Domain.Services;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Managers.ArticleImport;
using Yi.Framework.Bbs.Domain.Shared.Enums;
using Yi.Framework.Bbs.Domain.Shared.Model;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Domain.Managers
@@ -9,14 +14,16 @@ namespace Yi.Framework.Bbs.Domain.Managers
/// </summary>
public class ForumManager : DomainService
{
public readonly ISqlSugarRepository<DiscussEntity,Guid> _discussRepository;
public readonly ISqlSugarRepository<DiscussEntity, Guid> _discussRepository;
public readonly ISqlSugarRepository<PlateEntity, Guid> _plateEntityRepository;
public readonly ISqlSugarRepository<CommentEntity, Guid> _commentRepository;
public ForumManager(ISqlSugarRepository<DiscussEntity, Guid> discussRepository, ISqlSugarRepository<PlateEntity, Guid> plateEntityRepository, ISqlSugarRepository<CommentEntity, Guid> commentRepository)
public readonly ISqlSugarRepository<ArticleEntity, Guid> _articleRepository;
public ForumManager(ISqlSugarRepository<DiscussEntity, Guid> discussRepository, ISqlSugarRepository<PlateEntity, Guid> plateEntityRepository, ISqlSugarRepository<CommentEntity, Guid> commentRepository, ISqlSugarRepository<ArticleEntity, Guid> articleRepository)
{
_discussRepository = discussRepository;
_plateEntityRepository = plateEntityRepository;
_commentRepository = commentRepository;
_articleRepository = articleRepository;
}
//主题是不能直接创建的,需要由领域服务统一创建
@@ -36,5 +43,35 @@ namespace Yi.Framework.Bbs.Domain.Managers
entity.RootId = rootId;
return await _commentRepository.InsertReturnEntityAsync(entity);
}
/// <summary>
/// 导入文章
/// </summary>
/// <param name="discussId"></param>
/// <param name="articleParentId"></param>
/// <param name="fileObjs"></param>
/// <param name="importType"></param>
/// <returns></returns>
public async Task PostImportAsync(Guid discussId,Guid articleParentId, List<FileObject> fileObjs, ArticleImportTypeEnum importType)
{
AbstractArticleImport abstractArticleImport = default;
switch (importType)
{
case ArticleImportTypeEnum.Defalut:
abstractArticleImport = new DefaultArticleImport();
break;
case ArticleImportTypeEnum.VuePress:
abstractArticleImport = new VuePressArticleImport();
break;
default: abstractArticleImport = new DefaultArticleImport(); break;
}
var articleHandled = abstractArticleImport.Import(discussId, articleParentId, fileObjs);
//await _articleRepository.InsertManyAsync(articleHandled);
}
}
}

View File

@@ -248,6 +248,17 @@ namespace Yi.Framework.Rbac.Application.Services
throw new UserFriendlyException("验证码错误");
}
private void ValidateUserName(RegisterDto input)
{
// 正则表达式,匹配只包含数字和字母的字符串
string pattern = @"^[a-zA-Z0-9]+$";
bool isMatch = Regex.IsMatch(input.UserName, pattern);
if (!isMatch)
{
throw new UserFriendlyException("用户名不能包含除【字母】与【数字】的其他字符");
}
}
/// <summary>
/// 注册,需要验证码通过
@@ -276,6 +287,10 @@ namespace Yi.Framework.Rbac.Application.Services
{
throw new UserFriendlyException("密码需大于等于6位");
}
//效验用户名
ValidateUserName(input);
//效验验证码,根据电话号码获取 value比对验证码已经uuid
await ValidationPhoneCaptchaAsync(input);
@@ -283,7 +298,7 @@ namespace Yi.Framework.Rbac.Application.Services
//输入的用户名与电话号码都不能在数据库中存在
UserEntity user = new();
var isExist = await _userRepository.IsAnyAsync(x =>x.UserName == input.UserName|| x.Phone == input.Phone);
var isExist = await _userRepository.IsAnyAsync(x => x.UserName == input.UserName || x.Phone == input.Phone);
if (isExist)
{
throw new UserFriendlyException("用户已存在,注册失败");

View File

@@ -21,13 +21,11 @@ namespace Yi.Framework.Rbac.Application.Services
public class FileService : ApplicationService, IFileService
{
private readonly IRepository<FileAggregateRoot> _repository;
private readonly HttpContext _httpContext;
private IGuidGenerator _guidGenerator;
public FileService(IRepository<FileAggregateRoot> repository, IHttpContextAccessor httpContextAccessor, IGuidGenerator guidGenerator)
public FileService(IRepository<FileAggregateRoot> repository, IGuidGenerator guidGenerator)
{
_guidGenerator = guidGenerator;
_repository = repository;
_httpContext = httpContextAccessor.HttpContext;
}
/// <summary>

View File

@@ -16,6 +16,7 @@ namespace Yi.Abp.SqlSugarCore
base.CustomDataFilter();
}
protected override void DataExecuted(object oldValue, DataAfterModel entityInfo)
{
base.DataExecuted(oldValue, entityInfo);

View File

@@ -27,6 +27,9 @@
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\icon\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
@@ -37,7 +40,7 @@
<ItemGroup>
<Folder Include="logs\" />
<Folder Include="wwwroot\" />
<Folder Include="wwwroot\icon\" />
</ItemGroup>
</Project>

View File

@@ -1,8 +1,10 @@
using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;
@@ -64,6 +66,7 @@ namespace Yi.Abp.Web
service.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
options.SerializerSettings.Converters.Add(new StringEnumConverter());
});
Configure<AbpAntiForgeryOptions>(options =>
@@ -150,6 +153,11 @@ namespace Yi.Abp.Web
//swagger
app.UseYiSwagger();
//静态资源
app.UseStaticFiles("/api/app/wwwroot");
app.UseDefaultFiles();
app.UseDirectoryBrowser("/api/app/wwwroot");
//工作单元
app.UseUnitOfWork();

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -6,7 +6,7 @@ import { Session } from "@/utils/storage";
import useAuths from "@/hooks/useAuths";
const { VITE_APP_ENV_NAME } = import.meta.env;
const { getToken } = useAuths();
const { getToken, removeToken } = useAuths();
const { base_url, request_timeout, pre_interface } = config;
export const PATH_URL = base_url[VITE_APP_ENV_NAME];
@@ -69,6 +69,7 @@ service.interceptors.response.use(
cancelButtonText: "取消",
type: "warning",
}).then(() => {
removeToken();
router.push("/login");
});
return;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 116 KiB