mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-04-17 06:36:36 +08:00
Compare commits
27 Commits
watermelon
...
AbpUnitOfW
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b7abd4fe0 | ||
|
|
bbc18dcaf9 | ||
|
|
7cb78e70cb | ||
|
|
59d9674aeb | ||
|
|
36ed5400be | ||
|
|
6378c69764 | ||
|
|
b44db20938 | ||
|
|
61cd7b42d4 | ||
|
|
77d64796e0 | ||
|
|
a4001c21b1 | ||
|
|
9e1d01774f | ||
|
|
be4f0a2a90 | ||
|
|
c45c17748e | ||
|
|
57ad7ae1a3 | ||
|
|
998d97b669 | ||
|
|
453d95a460 | ||
|
|
d55545849a | ||
|
|
22ba44c271 | ||
|
|
ae2cc7ad9b | ||
|
|
c880f32d33 | ||
|
|
7b20b68b6a | ||
|
|
974f264272 | ||
|
|
bcbb2b5139 | ||
|
|
e09aaa2dc7 | ||
|
|
e3178d7579 | ||
|
|
b59dfbc3fd | ||
|
|
0f21688b3c |
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore;
|
||||||
|
|
||||||
|
public class RealIpHttpContextWebClientInfoProvider : HttpContextWebClientInfoProvider
|
||||||
|
{
|
||||||
|
public RealIpHttpContextWebClientInfoProvider(ILogger<HttpContextWebClientInfoProvider> logger,
|
||||||
|
IHttpContextAccessor httpContextAccessor) : base(logger, httpContextAccessor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string? GetClientIpAddress()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpContext = HttpContextAccessor.HttpContext;
|
||||||
|
|
||||||
|
var headers = httpContext?.Request?.Headers;
|
||||||
|
|
||||||
|
if (headers != null && headers.ContainsKey("X-Forwarded-For"))
|
||||||
|
{
|
||||||
|
httpContext.Connection.RemoteIpAddress =
|
||||||
|
IPAddress.Parse(headers["X-Forwarded-For"].FirstOrDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpContext?.Connection?.RemoteIpAddress?.ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogException(ex, LogLevel.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.AspNetCore.Mvc;
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
using Yi.Framework.AspNetCore.Mvc;
|
using Yi.Framework.AspNetCore.Mvc;
|
||||||
@@ -22,6 +23,11 @@ namespace Yi.Framework.AspNetCore
|
|||||||
)]
|
)]
|
||||||
public class YiFrameworkAspNetCoreModule : AbpModule
|
public class YiFrameworkAspNetCoreModule : AbpModule
|
||||||
{
|
{
|
||||||
|
public override void PostConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
var services = context.Services;
|
||||||
|
services.Replace(new ServiceDescriptor(typeof(IWebClientInfoProvider),
|
||||||
|
typeof(RealIpHttpContextWebClientInfoProvider), ServiceLifetime.Transient));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,7 @@ namespace Yi.Framework.AuditLogging.Domain.Entities
|
|||||||
|
|
||||||
public virtual string? Url { get; protected set; }
|
public virtual string? Url { get; protected set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||||
public virtual string? Exceptions { get; protected set; }
|
public virtual string? Exceptions { get; protected set; }
|
||||||
|
|
||||||
public virtual string? Comments { get; protected set; }
|
public virtual string? Comments { get; protected set; }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Yi.Framework.Rbac.Application.Contracts.Dtos.User;
|
|||||||
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Comment
|
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Comment
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单返回,返回单条评论即可
|
/// 单返回,返回单条评论即可
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommentGetOutputDto : EntityDto<Guid>
|
public class CommentGetOutputDto : EntityDto<Guid>
|
||||||
{
|
{
|
||||||
@@ -17,17 +17,17 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Comment
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户id联表为用户对象
|
/// 用户id联表为用户对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public BbsUserGetOutputDto User { get; set; }
|
public BbsUserGetOutputDto User { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根节点的评论id
|
/// 根节点的评论id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid RootId { get; set; }
|
public Guid RootId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被回复的CommentId
|
/// 被回复的CommentId
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid ParentId { get; set; }
|
public Guid ParentId { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,15 @@ namespace Yi.Framework.Bbs.Application.Contracts.IServices
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Comment服务抽象
|
/// Comment服务抽象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ICommentService : IYiCrudAppService<CommentGetOutputDto, CommentGetListOutputDto, Guid, CommentGetListInputVo, CommentCreateInputVo, CommentUpdateInputVo>
|
public interface ICommentService{
|
||||||
{
|
/// <summary>
|
||||||
|
/// 发表评论
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="UserFriendlyException"></exception>
|
||||||
|
// [Permission("bbs:comment:add")]
|
||||||
|
// [Authorize]
|
||||||
|
Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Volo.Abp.Caching;
|
using Volo.Abp.Caching;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.EventBus;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Caches;
|
using Yi.Framework.Bbs.Domain.Shared.Caches;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Application.Extensions;
|
namespace Yi.Framework.Bbs.Application.Extensions;
|
||||||
|
|
||||||
@@ -14,6 +16,29 @@ namespace Yi.Framework.Bbs.Application.Extensions;
|
|||||||
/// 需考虑一致性问题,又不能上锁影响性能
|
/// 需考虑一致性问题,又不能上锁影响性能
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AccessLogMiddleware : IMiddleware, ITransientDependency
|
public class AccessLogMiddleware : IMiddleware, ITransientDependency
|
||||||
|
{
|
||||||
|
private static int _accessLogNumber = 0;
|
||||||
|
|
||||||
|
internal static void ResetAccessLogNumber()
|
||||||
|
{
|
||||||
|
_accessLogNumber = 0;
|
||||||
|
}
|
||||||
|
internal static int GetAccessLogNumber()
|
||||||
|
{
|
||||||
|
return _accessLogNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||||
|
{
|
||||||
|
await next(context);
|
||||||
|
|
||||||
|
Interlocked.Increment(ref _accessLogNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AccessLogResetEventHandler : ILocalEventHandler<AccessLogResetArgs>,
|
||||||
|
ITransientDependency
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存前缀
|
/// 缓存前缀
|
||||||
@@ -40,12 +65,27 @@ public class AccessLogMiddleware : IMiddleware, ITransientDependency
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
//该事件由job定时10秒触发
|
||||||
|
public async Task HandleEventAsync(AccessLogResetArgs eventData)
|
||||||
{
|
{
|
||||||
await next(context);
|
|
||||||
if (EnableRedisCache)
|
if (EnableRedisCache)
|
||||||
{
|
{
|
||||||
await RedisClient.IncrByAsync($"{CacheKeyPrefix}:{AccessLogCacheConst.Key}:{DateTime.Now.Date}", 1);
|
//分布式锁
|
||||||
|
if (await RedisClient.SetNxAsync("AccessLogLock",true,TimeSpan.FromSeconds(5)))
|
||||||
|
{
|
||||||
|
//自增长数
|
||||||
|
var incrNumber= AccessLogMiddleware.GetAccessLogNumber();
|
||||||
|
//立即重置,开始计算,方式丢失
|
||||||
|
AccessLogMiddleware.ResetAccessLogNumber();
|
||||||
|
if (incrNumber>0)
|
||||||
|
{
|
||||||
|
await RedisClient.IncrByAsync(
|
||||||
|
$"{CacheKeyPrefix}{AccessLogCacheConst.Key}:{DateTime.Now.Date:yyyyMMdd}", incrNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using FreeRedis;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Quartz;
|
||||||
|
using Volo.Abp.BackgroundWorkers.Quartz;
|
||||||
|
using Volo.Abp.Caching;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
using Volo.Abp.EventBus.Local;
|
||||||
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Caches;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Application.Jobs;
|
||||||
|
|
||||||
|
public class AccessLogCacheJob : QuartzBackgroundWorkerBase
|
||||||
|
{
|
||||||
|
private readonly ILocalEventBus _localEventBus;
|
||||||
|
|
||||||
|
public AccessLogCacheJob(ILocalEventBus localEventBus)
|
||||||
|
{
|
||||||
|
_localEventBus = localEventBus;
|
||||||
|
JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
//每10秒执行一次,将本地缓存转入redis,防止丢数据
|
||||||
|
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob))
|
||||||
|
.WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; })
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
await _localEventBus.PublishAsync(new AccessLogResetArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase
|
|||||||
{
|
{
|
||||||
//当天的访问量
|
//当天的访问量
|
||||||
var number =
|
var number =
|
||||||
await RedisClient.GetAsync<long>($"{CacheKeyPrefix}:{AccessLogCacheConst.Key}:{DateTime.Now.Date}");
|
await RedisClient.GetAsync<long>($"{CacheKeyPrefix}{AccessLogCacheConst.Key}:{DateTime.Now.Date:yyyyMMdd}");
|
||||||
|
|
||||||
|
|
||||||
var entity = await _repository._DbQueryable.Where(x => x.AccessLogType == AccessLogTypeEnum.Request)
|
var entity = await _repository._DbQueryable.Where(x => x.AccessLogType == AccessLogTypeEnum.Request)
|
||||||
@@ -81,7 +81,7 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
//删除前一天的缓存
|
//删除前一天的缓存
|
||||||
await RedisClient.DelAsync($"{CacheKeyPrefix}:{AccessLogCacheConst.Key}:{DateTime.Now.Date.AddDays(-1)}");
|
await RedisClient.DelAsync($"{CacheKeyPrefix}{AccessLogCacheConst.Key}:{DateTime.Now.Date.AddDays(-1):yyyyMMdd}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.Application.Dtos;
|
using Volo.Abp.Application.Dtos;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
using Volo.Abp.Domain.Repositories;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.BbsUser;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Comment;
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Comment;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.IServices;
|
using Yi.Framework.Bbs.Application.Contracts.IServices;
|
||||||
@@ -21,19 +23,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 评论
|
/// 评论
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CommentService : YiCrudAppService<CommentAggregateRoot, CommentGetOutputDto, CommentGetListOutputDto, Guid, CommentGetListInputVo, CommentCreateInputVo, CommentUpdateInputVo>,
|
public class CommentService : ApplicationService,
|
||||||
ICommentService
|
ICommentService
|
||||||
{
|
{
|
||||||
private readonly ISqlSugarRepository<CommentAggregateRoot, Guid> _repository;
|
private readonly ISqlSugarRepository<CommentAggregateRoot, Guid> _repository;
|
||||||
private readonly BbsUserManager _bbsUserManager;
|
private readonly BbsUserManager _bbsUserManager;
|
||||||
public CommentService(ForumManager forumManager, ISqlSugarRepository<DiscussAggregateRoot> discussRepository, IDiscussService discussService, ISqlSugarRepository<CommentAggregateRoot, Guid> CommentRepository, BbsUserManager bbsUserManager) : base(CommentRepository)
|
|
||||||
{
|
|
||||||
_forumManager = forumManager;
|
|
||||||
_discussRepository = discussRepository;
|
|
||||||
_discussService = discussService;
|
|
||||||
_repository = CommentRepository;
|
|
||||||
_bbsUserManager = bbsUserManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ForumManager _forumManager { get; set; }
|
private ForumManager _forumManager { get; set; }
|
||||||
|
|
||||||
@@ -42,116 +36,50 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository { get; set; }
|
private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository { get; set; }
|
||||||
|
|
||||||
private IDiscussService _discussService { get; set; }
|
private IDiscussService _discussService { get; set; }
|
||||||
/// <summary>
|
|
||||||
/// 获取改主题下的评论,结构为二维列表,该查询无分页
|
|
||||||
/// Todo: 可放入领域层
|
public async Task<CommentGetOutputDto> Create2Async(CommentCreateInputVo input)
|
||||||
/// </summary>
|
|
||||||
/// <param name="discussId"></param>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<PagedResultDto<CommentGetListOutputDto>> GetDiscussIdAsync([FromRoute] Guid discussId, [FromQuery] CommentGetListInputVo input)
|
|
||||||
{
|
{
|
||||||
await _discussService.VerifyDiscussPermissionAsync(discussId);
|
var entity = new CommentAggregateRoot(Guid.Empty);
|
||||||
|
return new CommentGetOutputDto();
|
||||||
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Content), x => x.Content.Contains(input.Content))
|
|
||||||
.Where(x => x.DiscussId == discussId)
|
|
||||||
.Includes(x => x.CreateUser)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
//该实体需要进行转换
|
|
||||||
|
|
||||||
//同时为所有用户id进行bbs的扩展即可
|
|
||||||
List<Guid> userIds = entities.Where(x => x.CreatorId != null).Select(x => x.CreatorId ?? Guid.Empty).ToList();
|
|
||||||
var bbsUserInfoDic = (await _bbsUserManager.GetBbsUserInfoAsync(userIds)).ToDictionary(x => x.Id);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------数据查询完成------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//从根目录开始组装
|
|
||||||
//结果初始值,第一层等于全部根节点
|
|
||||||
var allOutPut = entities.OrderByDescending(x => x.CreationTime).ToList();
|
|
||||||
|
|
||||||
//获取全量主题评论, 先获取顶级的,将其他子组合到顶级下,形成一个二维,先转成dto
|
|
||||||
List<CommentGetListOutputDto> allOutoutDto = await MapToGetListOutputDtosAsync(allOutPut);
|
|
||||||
|
|
||||||
//开始映射额外用户信息字段
|
|
||||||
allOutoutDto?.ForEach(x => x.CreateUser = bbsUserInfoDic[x.CreatorId ?? Guid.Empty].Adapt<BbsUserGetOutputDto>());
|
|
||||||
|
|
||||||
//开始组装dto的层级关系
|
|
||||||
//将全部数据进行hash
|
|
||||||
var dic = allOutoutDto.ToDictionary(x => x.Id);
|
|
||||||
|
|
||||||
foreach (var comment in allOutoutDto)
|
|
||||||
{
|
|
||||||
//不是根节点,需要赋值 被评论者用户信息等
|
|
||||||
if (comment.ParentId != Guid.Empty)
|
|
||||||
{
|
|
||||||
if (dic.ContainsKey(comment.ParentId))
|
|
||||||
{
|
|
||||||
var parentComment = dic[comment.ParentId];
|
|
||||||
comment.CommentedUser = parentComment.CreateUser;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//root或者parent id,根节点都是等于0的
|
|
||||||
var id = comment.RootId;
|
|
||||||
if (id != Guid.Empty)
|
|
||||||
{
|
|
||||||
dic[id].Children.Add(comment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
[HttpGet("Create22")]
|
||||||
|
public async Task<CommentGetOutputDto> Create22Async(CommentCreateInputVo input)
|
||||||
//子类需要排序
|
|
||||||
var rootOutoutDto = allOutoutDto.Where(x => x.ParentId == Guid.Empty).ToList();
|
|
||||||
rootOutoutDto?.ForEach(x =>
|
|
||||||
{
|
{
|
||||||
x.Children = x.Children.OrderByDescending(x => x.CreationTime).ToList();
|
var entity = new CommentAggregateRoot(Guid.Empty);
|
||||||
|
return new CommentGetOutputDto();
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return new PagedResultDto<CommentGetListOutputDto>(entities.Count(), rootOutoutDto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发表评论
|
/// 发表评论
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="UserFriendlyException"></exception>
|
/// <exception cref="UserFriendlyException"></exception>
|
||||||
[Permission("bbs:comment:add")]
|
// [Permission("bbs:comment:add")]
|
||||||
[Authorize]
|
// [Authorize]
|
||||||
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
|
public async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
|
||||||
{
|
{
|
||||||
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
|
// var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
|
||||||
if (discuess is null)
|
// if (discuess is null)
|
||||||
{
|
// {
|
||||||
throw new UserFriendlyException(DiscussConst.No_Exist);
|
// throw new UserFriendlyException(DiscussConst.No_Exist);
|
||||||
}
|
// }
|
||||||
//不是超级管理员,且主题开启禁止评论
|
//不是超级管理员,且主题开启禁止评论
|
||||||
|
|
||||||
if (discuess.IsDisableCreateComment == true && !CurrentUser.GetPermissions().Contains(UserConst.AdminPermissionCode))
|
// if (discuess.IsDisableCreateComment == true && !CurrentUser.GetPermissions().Contains(UserConst.AdminPermissionCode))
|
||||||
|
// {
|
||||||
|
// throw new UserFriendlyException("该主题已禁止评论功能");
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// var entity = await _forumManager.CreateCommentAsync(input.DiscussId, input.ParentId, input.RootId, input.Content);
|
||||||
|
var entity = new CommentAggregateRoot(Guid.Empty);
|
||||||
|
return new CommentGetOutputDto();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommentService(IRepository<CommentAggregateRoot, Guid> repository)
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("该主题已禁止评论功能");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var entity = await _forumManager.CreateCommentAsync(input.DiscussId, input.ParentId, input.RootId, input.Content);
|
|
||||||
return await MapToGetOutputDtoAsync(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
|
||||||
|
public class AccessLogResetArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,73 +1,73 @@
|
|||||||
using TencentCloud.Tbm.V20180129.Models;
|
// using TencentCloud.Tbm.V20180129.Models;
|
||||||
using Volo.Abp.DependencyInjection;
|
// using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities.Events;
|
// using Volo.Abp.Domain.Entities.Events;
|
||||||
using Volo.Abp.EventBus;
|
// using Volo.Abp.EventBus;
|
||||||
using Volo.Abp.EventBus.Local;
|
// using Volo.Abp.EventBus.Local;
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
// using Yi.Framework.Bbs.Domain.Entities;
|
||||||
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
// using Yi.Framework.Bbs.Domain.Entities.Forum;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Consts;
|
// using Yi.Framework.Bbs.Domain.Shared.Consts;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
// using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
// using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
using Yi.Framework.Rbac.Domain.Entities;
|
// using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
// using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
//
|
||||||
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
// namespace Yi.Framework.Bbs.Domain.EventHandlers
|
||||||
{
|
// {
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 评论创建的领域事件
|
// /// 评论创建的领域事件
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public class CommentCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<CommentAggregateRoot>>,
|
// public class CommentCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<CommentAggregateRoot>>,
|
||||||
ITransientDependency
|
// ITransientDependency
|
||||||
{
|
// {
|
||||||
private ILocalEventBus _localEventBus;
|
// private ILocalEventBus _localEventBus;
|
||||||
private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository;
|
// private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository;
|
||||||
private ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
// private ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
||||||
public CommentCreatedEventHandler(ILocalEventBus localEventBus, ISqlSugarRepository<DiscussAggregateRoot> discussRepository, ISqlSugarRepository<UserAggregateRoot> userRepository)
|
// public CommentCreatedEventHandler(ILocalEventBus localEventBus, ISqlSugarRepository<DiscussAggregateRoot> discussRepository, ISqlSugarRepository<UserAggregateRoot> userRepository)
|
||||||
{
|
// {
|
||||||
_userRepository = userRepository;
|
// _userRepository = userRepository;
|
||||||
_localEventBus = localEventBus;
|
// _localEventBus = localEventBus;
|
||||||
_discussRepository = discussRepository;
|
// _discussRepository = discussRepository;
|
||||||
}
|
// }
|
||||||
public async Task HandleEventAsync(EntityCreatedEventData<CommentAggregateRoot> eventData)
|
// public async Task HandleEventAsync(EntityCreatedEventData<CommentAggregateRoot> eventData)
|
||||||
{
|
// {
|
||||||
var commentEntity = eventData.Entity;
|
// var commentEntity = eventData.Entity;
|
||||||
|
//
|
||||||
//给创建者发布数量+1
|
// //给创建者发布数量+1
|
||||||
await _userRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
// await _userRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
||||||
.SetColumns(it => it.CommentNumber == it.CommentNumber + 1)
|
// .SetColumns(it => it.CommentNumber == it.CommentNumber + 1)
|
||||||
.Where(it => it.UserId == commentEntity.CreatorId)
|
// .Where(it => it.UserId == commentEntity.CreatorId)
|
||||||
.ExecuteCommandAsync();
|
// .ExecuteCommandAsync();
|
||||||
var disucssDto = await _discussRepository._DbQueryable
|
// var disucssDto = await _discussRepository._DbQueryable
|
||||||
.Where(x => x.Id == commentEntity.DiscussId)
|
// .Where(x => x.Id == commentEntity.DiscussId)
|
||||||
.LeftJoin<UserAggregateRoot>((dicuss, user) => dicuss.CreatorId == user.Id)
|
// .LeftJoin<UserAggregateRoot>((dicuss, user) => dicuss.CreatorId == user.Id)
|
||||||
.Select((dicuss, user) =>
|
// .Select((dicuss, user) =>
|
||||||
new
|
// new
|
||||||
{
|
// {
|
||||||
DiscussUserId = user.Id,
|
// DiscussUserId = user.Id,
|
||||||
DiscussTitle = dicuss.Title,
|
// DiscussTitle = dicuss.Title,
|
||||||
|
//
|
||||||
})
|
// })
|
||||||
.FirstAsync();
|
// .FirstAsync();
|
||||||
|
//
|
||||||
var commentUser = await _userRepository.GetFirstAsync(x => x.Id == commentEntity.CreatorId);
|
// var commentUser = await _userRepository.GetFirstAsync(x => x.Id == commentEntity.CreatorId);
|
||||||
|
//
|
||||||
//截取30个长度
|
// //截取30个长度
|
||||||
var content = commentEntity.Content.Length >= 30 ? commentEntity.Content.Substring(0, 30)+"..." : commentEntity.Content;
|
// var content = commentEntity.Content.Length >= 30 ? commentEntity.Content.Substring(0, 30)+"..." : commentEntity.Content;
|
||||||
//通知主题作者,有人评论
|
// //通知主题作者,有人评论
|
||||||
await _localEventBus.PublishAsync(new BbsNoticeEventArgs(disucssDto.DiscussUserId, string.Format(DiscussConst.CommentNotice, disucssDto.DiscussTitle, commentUser.UserName, content,commentEntity.DiscussId)), false);
|
// await _localEventBus.PublishAsync(new BbsNoticeEventArgs(disucssDto.DiscussUserId, string.Format(DiscussConst.CommentNotice, disucssDto.DiscussTitle, commentUser.UserName, content,commentEntity.DiscussId)), false);
|
||||||
|
//
|
||||||
//如果为空,表示根路径,没有回复者
|
// //如果为空,表示根路径,没有回复者
|
||||||
if (commentEntity.ParentId != Guid.Empty)
|
// if (commentEntity.ParentId != Guid.Empty)
|
||||||
{
|
// {
|
||||||
//通知回复者,有人评论
|
// //通知回复者,有人评论
|
||||||
await _localEventBus.PublishAsync(new BbsNoticeEventArgs(commentEntity.ParentId, string.Format(DiscussConst.CommentNoticeToReply, disucssDto.DiscussTitle, commentUser.UserName, content,commentEntity.DiscussId)), false);
|
// await _localEventBus.PublishAsync(new BbsNoticeEventArgs(commentEntity.ParentId, string.Format(DiscussConst.CommentNoticeToReply, disucssDto.DiscussTitle, commentUser.UserName, content,commentEntity.DiscussId)), false);
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
//最后发布任务触发事件
|
// //最后发布任务触发事件
|
||||||
await _localEventBus.PublishAsync(
|
// await _localEventBus.PublishAsync(
|
||||||
new AssignmentEventArgs(AssignmentRequirementTypeEnum.Comment, commentUser.Id),false);
|
// new AssignmentEventArgs(AssignmentRequirementTypeEnum.Comment, commentUser.Id),false);
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
|||||||
entity.Content = content;
|
entity.Content = content;
|
||||||
entity.ParentId = parentId;
|
entity.ParentId = parentId;
|
||||||
entity.RootId = rootId;
|
entity.RootId = rootId;
|
||||||
return await _commentRepository.InsertReturnEntityAsync(entity);
|
await _commentRepository.InsertAsync(entity);
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -4,5 +4,7 @@
|
|||||||
{
|
{
|
||||||
public Guid Uuid { get; set; } = Guid.Empty;
|
public Guid Uuid { get; set; } = Guid.Empty;
|
||||||
public byte[] Img { get; set; }
|
public byte[] Img { get; set; }
|
||||||
|
|
||||||
|
public bool IsEnableCaptcha { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,9 @@
|
|||||||
public class PhoneCaptchaImageDto
|
public class PhoneCaptchaImageDto
|
||||||
{
|
{
|
||||||
public string Phone { get; set; }
|
public string Phone { get; set; }
|
||||||
|
|
||||||
|
public string Uuid { get; set; }
|
||||||
|
|
||||||
|
public string Code { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DictionaryCreateInputVo
|
public class DictionaryCreateInputVo
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
public string? ListClass { get; set; }
|
public string? ListClass { get; set; }
|
||||||
public string? CssClass { get; set; }
|
public string? CssClass { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryGetListOutputDto : EntityDto<Guid>
|
public class DictionaryGetListOutputDto : EntityDto<Guid>
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public DateTime CreationTime { get; set; } = DateTime.Now;
|
public DateTime CreationTime { get; set; } = DateTime.Now;
|
||||||
public Guid? CreatorId { get; set; }
|
public Guid? CreatorId { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryGetOutputDto : EntityDto<Guid>
|
public class DictionaryGetOutputDto : EntityDto<Guid>
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public DateTime CreationTime { get; set; } = DateTime.Now;
|
public DateTime CreationTime { get; set; } = DateTime.Now;
|
||||||
public Guid? CreatorId { get; set; }
|
public Guid? CreatorId { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryUpdateInputVo
|
public class DictionaryUpdateInputVo
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
public string? ListClass { get; set; }
|
public string? ListClass { get; set; }
|
||||||
public string? CssClass { get; set; }
|
public string? CssClass { get; set; }
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Menu
|
|||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
public string? Component { get; set; }
|
public string? Component { get; set; }
|
||||||
public string? Query { get; set; }
|
public string? Query { get; set; }
|
||||||
|
public string? RouterName { get; set; }
|
||||||
public int OrderNum { get; set; }
|
public int OrderNum { get; set; }
|
||||||
//public List<MenuEntity>? Children { get; set; }
|
//public List<MenuEntity>? Children { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Menu
|
|||||||
|
|
||||||
public int OrderNum { get; set; }
|
public int OrderNum { get; set; }
|
||||||
|
|
||||||
|
public string? RouterName { get; set; }
|
||||||
|
|
||||||
//public List<MenuEntity>? Children { get; set; }
|
//public List<MenuEntity>? Children { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Post
|
|||||||
public class PostUpdateInputVo
|
public class PostUpdateInputVo
|
||||||
{
|
{
|
||||||
public bool? State { get; set; }
|
public bool? State { get; set; }
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string PostCode { get; set; }
|
public string PostCode { get; set; }
|
||||||
public string PostName { get; set; }
|
public string PostName { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -82,12 +82,12 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// 校验图片登录验证码,无需和账号绑定
|
/// 校验图片登录验证码,无需和账号绑定
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
private void ValidationImageCaptcha(LoginInputVo input)
|
private void ValidationImageCaptcha(string? uuid,string? code )
|
||||||
{
|
{
|
||||||
if (_rbacOptions.EnableCaptcha)
|
if (_rbacOptions.EnableCaptcha)
|
||||||
{
|
{
|
||||||
//登录不想要验证码 ,可不校验
|
//登录不想要验证码 ,可不校验
|
||||||
if (!_captcha.Validate(input.Uuid, input.Code))
|
if (!_captcha.Validate(uuid, code))
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("验证码错误");
|
throw new UserFriendlyException("验证码错误");
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
//校验验证码
|
//校验验证码
|
||||||
ValidationImageCaptcha(input);
|
ValidationImageCaptcha(input.Uuid,input.Code);
|
||||||
|
|
||||||
UserAggregateRoot user = new();
|
UserAggregateRoot user = new();
|
||||||
//校验
|
//校验
|
||||||
@@ -157,7 +157,8 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
var uuid = _guidGenerator.Create();
|
var uuid = _guidGenerator.Create();
|
||||||
var captcha = _captcha.Generate(uuid.ToString());
|
var captcha = _captcha.Generate(uuid.ToString());
|
||||||
return new CaptchaImageDto { Img = captcha.Bytes, Uuid = uuid };
|
var enableCaptcha = _rbacOptions.EnableCaptcha;
|
||||||
|
return new CaptchaImageDto { Img = captcha.Bytes, Uuid = uuid,IsEnableCaptcha= enableCaptcha };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -198,12 +199,15 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 手机验证码
|
/// 手机验证码-需通过图形验证码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<object> PostCaptchaPhoneAsync(ValidationPhoneTypeEnum validationPhoneType,
|
private async Task<object> PostCaptchaPhoneAsync(ValidationPhoneTypeEnum validationPhoneType,
|
||||||
PhoneCaptchaImageDto input)
|
PhoneCaptchaImageDto input)
|
||||||
{
|
{
|
||||||
|
//验证uuid 和 验证码
|
||||||
|
ValidationImageCaptcha(input.Uuid,input.Code);
|
||||||
|
|
||||||
await ValidationPhone(input.Phone);
|
await ValidationPhone(input.Phone);
|
||||||
|
|
||||||
//注册的手机号验证,是不能已经注册过的
|
//注册的手机号验证,是不能已经注册过的
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Yi.Framework.Ddd.Application;
|
|||||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary;
|
using Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary;
|
||||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||||
using Yi.Framework.Rbac.Domain.Entities;
|
using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.Rbac.Domain.Shared.Consts;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
|
||||||
@@ -15,29 +14,27 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary服务实现
|
/// Dictionary服务实现
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DictionaryService : YiCrudAppService<DictionaryEntity, DictionaryGetOutputDto,
|
public class DictionaryService : YiCrudAppService<DictionaryEntity, DictionaryGetOutputDto, DictionaryGetListOutputDto, Guid, DictionaryGetListInputVo, DictionaryCreateInputVo, DictionaryUpdateInputVo>,
|
||||||
DictionaryGetListOutputDto, Guid, DictionaryGetListInputVo, DictionaryCreateInputVo,
|
|
||||||
DictionaryUpdateInputVo>,
|
|
||||||
IDictionaryService
|
IDictionaryService
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<DictionaryEntity, Guid> _repository;
|
private ISqlSugarRepository<DictionaryEntity, Guid> _repository;
|
||||||
|
|
||||||
public DictionaryService(ISqlSugarRepository<DictionaryEntity, Guid> repository) : base(repository)
|
public DictionaryService(ISqlSugarRepository<DictionaryEntity, Guid> repository) : base(repository)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository= repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询
|
/// 查询
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override async Task<PagedResultDto<DictionaryGetListOutputDto>> GetListAsync(
|
|
||||||
DictionaryGetListInputVo input)
|
public override async Task<PagedResultDto<DictionaryGetListOutputDto>> GetListAsync(DictionaryGetListInputVo input)
|
||||||
{
|
{
|
||||||
RefAsync<int> total = 0;
|
RefAsync<int> total = 0;
|
||||||
var entities = await _repository._DbQueryable
|
var entities = await _repository._DbQueryable
|
||||||
.WhereIF(input.DictType is not null, x => x.DictType == input.DictType)
|
.WhereIF(input.DictType is not null, x => x.DictType == input.DictType)
|
||||||
.WhereIF(input.DictLabel is not null, x => x.DictLabel!.Contains(input.DictLabel!))
|
.WhereIF(input.DictLabel is not null, x => x.DictLabel!.Contains(input.DictLabel!))
|
||||||
.WhereIF(input.State is not null, x => x.State == input.State)
|
.WhereIF(input.State is not null, x => x.State == input.State)
|
||||||
|
.OrderByDescending(x => x.OrderNum)
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<DictionaryGetListOutputDto>
|
return new PagedResultDto<DictionaryGetListOutputDto>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ namespace Yi.Framework.Rbac.Application.Services.RecordLog
|
|||||||
public override async Task<PagedResultDto<LoginLogGetListOutputDto>> GetListAsync(LoginLogGetListInputVo input)
|
public override async Task<PagedResultDto<LoginLogGetListOutputDto>> GetListAsync(LoginLogGetListInputVo input)
|
||||||
{
|
{
|
||||||
RefAsync<int> total = 0;
|
RefAsync<int> total = 0;
|
||||||
if (input.Sorting.IsNullOrWhiteSpace())
|
//if (input.Sorting.IsNullOrWhiteSpace())
|
||||||
input.Sorting = $"{nameof(LoginLogAggregateRoot.CreationTime)} Desc";
|
// input.Sorting = $"{nameof(LoginLogAggregateRoot.CreationTime)} Desc";
|
||||||
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.LoginIp), x => x.LoginIp.Contains(input.LoginIp!))
|
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.LoginIp), x => x.LoginIp.Contains(input.LoginIp!))
|
||||||
.WhereIF(!string.IsNullOrEmpty(input.LoginUser), x => x.LoginUser!.Contains(input.LoginUser!))
|
.WhereIF(!string.IsNullOrEmpty(input.LoginUser), x => x.LoginUser!.Contains(input.LoginUser!))
|
||||||
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
||||||
.OrderBy(input.Sorting)
|
.OrderByDescending(it => it.CreationTime) //降序
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<LoginLogGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
return new PagedResultDto<LoginLogGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ namespace Yi.Framework.Rbac.Application.Services.RecordLog
|
|||||||
public override async Task<PagedResultDto<OperationLogGetListOutputDto>> GetListAsync(OperationLogGetListInputVo input)
|
public override async Task<PagedResultDto<OperationLogGetListOutputDto>> GetListAsync(OperationLogGetListInputVo input)
|
||||||
{
|
{
|
||||||
RefAsync<int> total = 0;
|
RefAsync<int> total = 0;
|
||||||
if (input.Sorting.IsNullOrWhiteSpace())
|
//if (input.Sorting.IsNullOrWhiteSpace())
|
||||||
input.Sorting = $"{nameof(OperationLogEntity.CreationTime)} Desc";
|
// input.Sorting = $"{nameof(OperationLogEntity.CreationTime)} Desc";
|
||||||
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.OperUser), x => x.OperUser.Contains(input.OperUser!))
|
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.OperUser), x => x.OperUser.Contains(input.OperUser!))
|
||||||
.WhereIF(input.OperType is not null, x => x.OperType == input.OperType)
|
.WhereIF(input.OperType is not null, x => x.OperType == input.OperType)
|
||||||
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
||||||
.OrderBy(input.Sorting)
|
.OrderByDescending(it => it.CreationTime) //降序
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<OperationLogGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
return new PagedResultDto<OperationLogGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace Yi.Framework.Rbac.Application.Services.System
|
|||||||
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.PostName),
|
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.PostName),
|
||||||
x => x.PostName.Contains(input.PostName!))
|
x => x.PostName.Contains(input.PostName!))
|
||||||
.WhereIF(input.State is not null, x => x.State == input.State)
|
.WhereIF(input.State is not null, x => x.State == input.State)
|
||||||
|
.OrderByDescending(x => x.OrderNum)
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<PostGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
return new PagedResultDto<PostGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Lazy.Captcha.Core.Generator;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.BackgroundWorkers;
|
using Volo.Abp.BackgroundWorkers;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
using Volo.Abp.BackgroundWorkers.Quartz;
|
||||||
@@ -24,7 +25,11 @@ namespace Yi.Framework.Rbac.Application
|
|||||||
{
|
{
|
||||||
var service = context.Services;
|
var service = context.Services;
|
||||||
|
|
||||||
service.AddCaptcha();
|
service.AddCaptcha(options =>
|
||||||
|
{
|
||||||
|
options.CaptchaType = CaptchaType.ARITHMETIC;
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ namespace Yi.Framework.Rbac.Domain.Entities
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 部门名称
|
/// 部门名称
|
||||||
///</summary>
|
///</summary>
|
||||||
public string DeptName { get; set; } = string.Empty;
|
public string DeptName { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 部门编码
|
/// 部门编码
|
||||||
///</summary>
|
///</summary>
|
||||||
[SugarColumn(ColumnName = "DeptCode")]
|
[SugarColumn(ColumnName = "DeptCode")]
|
||||||
public string DeptCode { get; set; } = string.Empty;
|
public string DeptCode { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 负责人
|
/// 负责人
|
||||||
///</summary>
|
///</summary>
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ namespace Yi.Framework.Rbac.Domain
|
|||||||
{
|
{
|
||||||
var service = context.Services;
|
var service = context.Services;
|
||||||
var configuration = context.Services.GetConfiguration();
|
var configuration = context.Services.GetConfiguration();
|
||||||
service.AddControllers(options =>
|
// service.AddControllers(options =>
|
||||||
{
|
// {
|
||||||
options.Filters.Add<PermissionGlobalAttribute>();
|
// options.Filters.Add<PermissionGlobalAttribute>();
|
||||||
options.Filters.Add<OperLogGlobalAttribute>();
|
// // options.Filters.Add<OperLogGlobalAttribute>();
|
||||||
});
|
// });
|
||||||
|
|
||||||
//配置阿里云短信
|
//配置阿里云短信
|
||||||
Configure<AliyunOptions>(configuration.GetSection(nameof(AliyunOptions)));
|
Configure<AliyunOptions>(configuration.GetSection(nameof(AliyunOptions)));
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot shenzhenDept = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot shenzhenDept = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "SZ",
|
||||||
DeptName = "深圳总公司",
|
DeptName = "深圳总公司",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -52,7 +52,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot jiangxiDept = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot jiangxiDept = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "JX",
|
||||||
DeptName = "江西总公司",
|
DeptName = "江西总公司",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -64,7 +64,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot szDept1 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot szDept1 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "YF",
|
||||||
DeptName = "研发部门",
|
DeptName = "研发部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -74,7 +74,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot szDept2 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot szDept2 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "SC",
|
||||||
DeptName = "市场部门",
|
DeptName = "市场部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -84,7 +84,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot szDept3 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot szDept3 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "CS",
|
||||||
DeptName = "测试部门",
|
DeptName = "测试部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -94,7 +94,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot szDept4 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot szDept4 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "CW",
|
||||||
DeptName = "财务部门",
|
DeptName = "财务部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -104,7 +104,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot szDept5 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot szDept5 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "YW",
|
||||||
DeptName = "运维部门",
|
DeptName = "运维部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -115,7 +115,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot jxDept1 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot jxDept1 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "SC",
|
||||||
DeptName = "市场部门",
|
DeptName = "市场部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
@@ -126,7 +126,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
DeptAggregateRoot jxDept2 = new DeptAggregateRoot(_guidGenerator.Create())
|
DeptAggregateRoot jxDept2 = new DeptAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
DeptCode = "CW2",
|
||||||
DeptName = "财务部门",
|
DeptName = "财务部门",
|
||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
|
|||||||
@@ -228,6 +228,21 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
};
|
};
|
||||||
entities.Add(swagger);
|
entities.Add(swagger);
|
||||||
|
|
||||||
|
//表单构建
|
||||||
|
MenuAggregateRoot builder = new MenuAggregateRoot(_guidGenerator.Create(), tool.Id)
|
||||||
|
{
|
||||||
|
MenuName = "表单生成器",
|
||||||
|
MenuType = MenuTypeEnum.Menu,
|
||||||
|
Router = "build",
|
||||||
|
IsShow = true,
|
||||||
|
IsLink = false,
|
||||||
|
MenuIcon = "form",
|
||||||
|
Component = "tool/build/index",
|
||||||
|
IsCache = true,
|
||||||
|
OrderNum = 101,
|
||||||
|
IsDeleted = false,
|
||||||
|
};
|
||||||
|
entities.Add(builder);
|
||||||
|
|
||||||
// //ERP
|
// //ERP
|
||||||
// MenuAggregateRoot erp = new MenuAggregateRoot(_guidGenerator.Create())
|
// MenuAggregateRoot erp = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Volo.Abp.Application.Services;
|
|||||||
using Volo.Abp.Settings;
|
using Volo.Abp.Settings;
|
||||||
using Volo.Abp.Uow;
|
using Volo.Abp.Uow;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
||||||
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Comment;
|
||||||
|
using Yi.Framework.Bbs.Application.Contracts.IServices;
|
||||||
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
||||||
using Yi.Framework.Rbac.Domain.Authorization;
|
using Yi.Framework.Rbac.Domain.Authorization;
|
||||||
using Yi.Framework.Rbac.Domain.Extensions;
|
using Yi.Framework.Rbac.Domain.Extensions;
|
||||||
@@ -19,160 +21,15 @@ namespace Yi.Abp.Application.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TestService : ApplicationService
|
public class TestService : ApplicationService
|
||||||
{
|
{
|
||||||
/// <summary>
|
[HttpGet("hello-world/string")]
|
||||||
/// 属性注入
|
public async Task<string> GetHelloWorld1(string? name)
|
||||||
/// 不推荐,坑太多,容易把自己玩死,简单的东西可以用一用
|
|
||||||
/// </summary>
|
|
||||||
public ISqlSugarRepository<BannerAggregateRoot> sqlSugarRepository { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 动态Api
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("hello-world")]
|
|
||||||
public string GetHelloWorld(string? name)
|
|
||||||
{
|
{
|
||||||
//会自动添加前缀,而不是重置,更符合习惯
|
return "1";
|
||||||
//如果需要重置以"/"根目录开头即可
|
|
||||||
//你好世界
|
|
||||||
return name ?? "HelloWord";
|
|
||||||
}
|
}
|
||||||
|
[HttpGet("hello-world/dto")]
|
||||||
/// <summary>
|
public async Task<CommentGetOutputDto> GetHelloWorld2(string? name)
|
||||||
/// 异常处理
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("error")]
|
|
||||||
public string GetError()
|
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("业务异常");
|
return new CommentGetOutputDto();
|
||||||
throw new Exception("系统异常");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SqlSugar
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<object> GetSqlSugarDbAsync()
|
|
||||||
{
|
|
||||||
//用户体验优先,可直接使用Db操作,依赖抽象
|
|
||||||
return await sqlSugarRepository._DbQueryable.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 工作单元
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task GetUowAsync()
|
|
||||||
{
|
|
||||||
//魔改
|
|
||||||
// 用户体验优先,万金油模式,支持高并发。支持单、多线程并发安全,支持多线程工作单元,支持多线程无工作单元,支持。。。
|
|
||||||
// 请注意,如果requiresNew: true只有在没有工作单元内使用,嵌套子工作单元,默认值false即可
|
|
||||||
// 自动在各个情况处理db客户端最优解之一
|
|
||||||
int i = 3;
|
|
||||||
List<Task> tasks = new List<Task>();
|
|
||||||
await sqlSugarRepository.GetListAsync();
|
|
||||||
await sqlSugarRepository.GetListAsync();
|
|
||||||
while (i > 0)
|
|
||||||
{
|
|
||||||
tasks.Add(Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入2" });
|
|
||||||
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
|
|
||||||
{
|
|
||||||
await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入1" });
|
|
||||||
await uow.CompleteAsync();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入3" });
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.WhenAll(tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前用户
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void GetCurrentUser()
|
|
||||||
{
|
|
||||||
//当token鉴权之后,可以直接获取
|
|
||||||
if (CurrentUser.Id is not null)
|
|
||||||
{
|
|
||||||
//权限
|
|
||||||
CurrentUser.GetPermissions();
|
|
||||||
|
|
||||||
//角色信息
|
|
||||||
CurrentUser.GetRoleInfo();
|
|
||||||
|
|
||||||
//部门id
|
|
||||||
CurrentUser.GetDeptId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据权限
|
|
||||||
/// </summary>
|
|
||||||
public void GetDataFilter()
|
|
||||||
{
|
|
||||||
//这里会数据权限过滤
|
|
||||||
using (DataFilter.DisablePermissionHandler())
|
|
||||||
{
|
|
||||||
//这里不会数据权限过滤
|
|
||||||
}
|
|
||||||
//这里会数据权限过滤
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对象映射
|
|
||||||
/// </summary>
|
|
||||||
public void GetMapper()
|
|
||||||
{
|
|
||||||
//直接无脑Adapt,无需配置
|
|
||||||
var entity = new BannerAggregateRoot();
|
|
||||||
var dto = entity.Adapt<BannerGetListOutputDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int RequestNumber { get; set; } = 0;
|
|
||||||
/// <summary>
|
|
||||||
/// 速率限制
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
// [DisableRateLimiting]
|
|
||||||
//[EnableRateLimiting("sliding")]
|
|
||||||
public int GetRateLimiting()
|
|
||||||
{
|
|
||||||
RequestNumber++;
|
|
||||||
return RequestNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ISettingProvider _settingProvider { get; set; }
|
|
||||||
|
|
||||||
public ISettingManager _settingManager { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 系统配置模块
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<string> GetSettingAsync()
|
|
||||||
{
|
|
||||||
//DDD需要提前定义
|
|
||||||
//默认来说,不提供修改操作,配置应该独立
|
|
||||||
var enableOrNull = await _settingProvider.GetOrNullAsync("DDD");
|
|
||||||
|
|
||||||
//如果要进行修改,可使用yi.framework下的ISettingManager
|
|
||||||
await _settingManager.SetGlobalAsync("DDD", "false");
|
|
||||||
|
|
||||||
var enableOrNull2 = await _settingManager.GetOrNullGlobalAsync("DDD");
|
|
||||||
|
|
||||||
//当然,他的独特地方,是支持来自多个模块,例如配置文件?
|
|
||||||
var result = await _settingManager.GetOrNullConfigurationAsync("Test");
|
|
||||||
|
|
||||||
|
|
||||||
return result ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
65
Yi.Abp.Net8/src/Yi.Abp.Web/AbpUnitOfWorkMiddleware2.cs
Normal file
65
Yi.Abp.Net8/src/Yi.Abp.Web/AbpUnitOfWorkMiddleware2.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Decompiled with JetBrains decompiler
|
||||||
|
// Type: Volo.Abp.AspNetCore.Uow.AbpUnitOfWorkMiddleware
|
||||||
|
// Assembly: Volo.Abp.AspNetCore, Version=8.2.0.0, Culture=neutral, PublicKeyToken=null
|
||||||
|
// MVID: E24BDAEE-E92D-4420-84F7-3DD088C817A4
|
||||||
|
// Assembly location: C:\Users\Administrator\.nuget\packages\volo.abp.aspnetcore\8.2.0\lib\net8.0\Volo.Abp.AspNetCore.dll
|
||||||
|
// XML documentation location: C:\Users\Administrator\.nuget\packages\volo.abp.aspnetcore\8.2.0\lib\net8.0\Volo.Abp.AspNetCore.xml
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components.Endpoints;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Volo.Abp.AspNetCore.Middleware;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
namespace Volo.Abp.AspNetCore.Uow
|
||||||
|
{
|
||||||
|
public class AbpUnitOfWorkMiddleware2 : AbpMiddlewareBase, ITransientDependency
|
||||||
|
{
|
||||||
|
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
||||||
|
private readonly AbpAspNetCoreUnitOfWorkOptions _options;
|
||||||
|
|
||||||
|
public AbpUnitOfWorkMiddleware2(
|
||||||
|
IUnitOfWorkManager unitOfWorkManager,
|
||||||
|
IOptions<AbpAspNetCoreUnitOfWorkOptions> options)
|
||||||
|
{
|
||||||
|
this._unitOfWorkManager = unitOfWorkManager;
|
||||||
|
this._options = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||||
|
{
|
||||||
|
// await next(context);
|
||||||
|
// await next(context).ConfigureAwait(false);
|
||||||
|
if (await ShouldSkipAsync(context, next).ConfigureAwait(false) || IsIgnoredUrl(context))
|
||||||
|
{
|
||||||
|
await next(context).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (IUnitOfWork uow = _unitOfWorkManager.Reserve("_AbpActionUnitOfWork"))
|
||||||
|
{
|
||||||
|
await next(context).ConfigureAwait(false);
|
||||||
|
await uow.CompleteAsync(context.RequestAborted).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsIgnoredUrl(HttpContext context)
|
||||||
|
{
|
||||||
|
return context.Request.Path.Value != null && this._options.IgnoredUrls.Any<string>(
|
||||||
|
(Func<string, bool>)(x =>
|
||||||
|
context.Request.Path.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<bool> ShouldSkipAsync(HttpContext context, RequestDelegate next)
|
||||||
|
{
|
||||||
|
return context.GetEndpoint()?.Metadata?.GetMetadata<RootComponentMetadata>() != null ||
|
||||||
|
await base.ShouldSkipAsync(context, next).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,15 +4,17 @@ using Yi.Abp.Web;
|
|||||||
|
|
||||||
//创建日志,可使用{SourceContext}记录
|
//创建日志,可使用{SourceContext}记录
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.MinimumLevel.Debug()
|
.MinimumLevel.Debug()
|
||||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Error)
|
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Error)
|
||||||
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
|
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug))
|
.WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day,
|
||||||
.WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Error))
|
restrictedToMinimumLevel: LogEventLevel.Debug))
|
||||||
.WriteTo.Async(c => c.Console())
|
.WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day,
|
||||||
.CreateLogger();
|
restrictedToMinimumLevel: LogEventLevel.Error))
|
||||||
|
.WriteTo.Async(c => c.Console())
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -36,6 +38,22 @@ try
|
|||||||
builder.Host.UseSerilog();
|
builder.Host.UseSerilog();
|
||||||
await builder.Services.AddApplicationAsync<YiAbpWebModule>();
|
await builder.Services.AddApplicationAsync<YiAbpWebModule>();
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
app.Use(async (http, next) =>
|
||||||
|
{
|
||||||
|
var id = Guid.NewGuid();
|
||||||
|
Console.WriteLine("之前-----" + id);
|
||||||
|
http.Response.OnStarting(() =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("之中-----" + id);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
await next();
|
||||||
|
if (http.Request.Path.Value.Contains("hello-world"))
|
||||||
|
{
|
||||||
|
Console.WriteLine("之后-----" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
await app.InitializeApplicationAsync();
|
await app.InitializeApplicationAsync();
|
||||||
await app.RunAsync();
|
await app.RunAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
42
Yi.Abp.Net8/src/Yi.Abp.Web/TestService.cs
Normal file
42
Yi.Abp.Net8/src/Yi.Abp.Web/TestService.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
|
||||||
|
namespace Yi.Abp.Application.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 常用魔改及扩展示例
|
||||||
|
/// </summary>
|
||||||
|
public class TestService : ApplicationService
|
||||||
|
{
|
||||||
|
[HttpGet("hello-world/string")]
|
||||||
|
public async Task<string> GetHelloWorld1(string? name)
|
||||||
|
{
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
[HttpGet("hello-world/dto")]
|
||||||
|
public async Task<CommentGetOutputDto> GetHelloWorld2(string? name)
|
||||||
|
{
|
||||||
|
return new CommentGetOutputDto();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommentGetOutputDto
|
||||||
|
{
|
||||||
|
|
||||||
|
public DateTime? CreateTime { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
public Guid DiscussId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根节点的评论id
|
||||||
|
/// </summary>
|
||||||
|
public Guid RootId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 被回复的CommentId
|
||||||
|
/// </summary>
|
||||||
|
public Guid ParentId { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,14 +42,14 @@ using Yi.Framework.TenantManagement.Application;
|
|||||||
namespace Yi.Abp.Web
|
namespace Yi.Abp.Web
|
||||||
{
|
{
|
||||||
[DependsOn(
|
[DependsOn(
|
||||||
typeof(YiAbpSqlSugarCoreModule),
|
// typeof(YiAbpSqlSugarCoreModule),
|
||||||
typeof(YiAbpApplicationModule),
|
// typeof(YiAbpApplicationModule),
|
||||||
typeof(AbpAspNetCoreMultiTenancyModule),
|
// typeof(AbpAspNetCoreMultiTenancyModule),
|
||||||
typeof(AbpAspNetCoreMvcModule),
|
typeof(AbpAspNetCoreMvcModule),
|
||||||
typeof(AbpAutofacModule),
|
typeof(AbpAutofacModule),
|
||||||
typeof(AbpSwashbuckleModule),
|
typeof(AbpSwashbuckleModule),
|
||||||
typeof(AbpAspNetCoreSerilogModule),
|
typeof(AbpAspNetCoreSerilogModule),
|
||||||
typeof(AbpAuditingModule),
|
// typeof(AbpAuditingModule),
|
||||||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
|
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
|
||||||
typeof(YiFrameworkAspNetCoreModule),
|
typeof(YiFrameworkAspNetCoreModule),
|
||||||
typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule)
|
typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule)
|
||||||
@@ -63,59 +63,29 @@ namespace Yi.Abp.Web
|
|||||||
var configuration = context.Services.GetConfiguration();
|
var configuration = context.Services.GetConfiguration();
|
||||||
var host = context.Services.GetHostingEnvironment();
|
var host = context.Services.GetHostingEnvironment();
|
||||||
var service = context.Services;
|
var service = context.Services;
|
||||||
//请求日志
|
|
||||||
Configure<AbpAuditingOptions>(optios =>
|
|
||||||
{
|
|
||||||
//默认关闭,开启会有大量的审计日志
|
|
||||||
optios.IsEnabled = false;
|
|
||||||
//审计日志过滤器
|
|
||||||
optios.AlwaysLogSelectors.Add(x => Task.FromResult(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
//采用furion格式的规范化api,默认不开启,使用abp优雅的方式
|
|
||||||
//你没看错。。。
|
|
||||||
//service.AddFurionUnifyResultApi();
|
|
||||||
|
|
||||||
//配置错误处理显示详情
|
|
||||||
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
|
|
||||||
|
|
||||||
//动态Api
|
//动态Api
|
||||||
Configure<AbpAspNetCoreMvcOptions>(options =>
|
Configure<AbpAspNetCoreMvcOptions>(options =>
|
||||||
{
|
{
|
||||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
|
options.ConventionalControllers.Create(typeof(YiAbpWebModule).Assembly,
|
||||||
options => options.RemoteServiceName = "default");
|
options => options.RemoteServiceName = "default");
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "rbac");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "bbs");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "chat-hub");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "tenant-management");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "code-gen");
|
|
||||||
|
|
||||||
//统一前缀
|
//统一前缀
|
||||||
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
||||||
});
|
});
|
||||||
|
|
||||||
//设置api格式
|
//设置api格式
|
||||||
service.AddControllers().AddNewtonsoftJson(options =>
|
// service.AddControllers().AddNewtonsoftJson(options =>
|
||||||
{
|
// {
|
||||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
// options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
options.SerializerSettings.Converters.Add(new StringEnumConverter());
|
// });
|
||||||
});
|
|
||||||
|
|
||||||
//设置缓存不要过期,默认滑动20分钟
|
|
||||||
Configure<AbpDistributedCacheOptions>(cacheOptions =>
|
|
||||||
{
|
|
||||||
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
|
|
||||||
//缓存key前缀
|
|
||||||
cacheOptions.KeyPrefix = "Yi:";
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
|
|
||||||
|
// Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
|
||||||
|
|
||||||
//Swagger
|
//Swagger
|
||||||
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
|
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
|
||||||
@@ -124,142 +94,8 @@ namespace Yi.Abp.Web
|
|||||||
new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
|
new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
|
||||||
});
|
});
|
||||||
|
|
||||||
//跨域
|
|
||||||
context.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy(DefaultCorsPolicyName, builder =>
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
.WithOrigins(
|
|
||||||
configuration["App:CorsOrigins"]!
|
|
||||||
.Split(";", StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(o => o.RemovePostFix("/"))
|
|
||||||
.ToArray()
|
|
||||||
)
|
|
||||||
.WithAbpExposedHeaders()
|
|
||||||
.SetIsOriginAllowedToAllowWildcardSubdomains()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowCredentials();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//配置多租户
|
|
||||||
Configure<AbpTenantResolveOptions>(options =>
|
|
||||||
{
|
|
||||||
//基于cookie jwt不好用,有坑
|
|
||||||
options.TenantResolvers.Clear();
|
|
||||||
options.TenantResolvers.Add(new HeaderTenantResolveContributor());
|
|
||||||
//options.TenantResolvers.Add(new HeaderTenantResolveContributor());
|
|
||||||
//options.TenantResolvers.Add(new CookieTenantResolveContributor());
|
|
||||||
|
|
||||||
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
|
|
||||||
});
|
|
||||||
|
|
||||||
//速率限制
|
|
||||||
//每60秒限制100个请求,滑块添加,分6段
|
|
||||||
service.AddRateLimiter(_ =>
|
|
||||||
{
|
|
||||||
_.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
|
||||||
_.OnRejected = (context, _) =>
|
|
||||||
{
|
|
||||||
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
|
|
||||||
{
|
|
||||||
context.HttpContext.Response.Headers.RetryAfter =
|
|
||||||
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
|
|
||||||
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
|
|
||||||
|
|
||||||
return new ValueTask();
|
|
||||||
};
|
|
||||||
|
|
||||||
//全局使用,链式表达式
|
|
||||||
_.GlobalLimiter = PartitionedRateLimiter.CreateChained(
|
|
||||||
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
|
||||||
{
|
|
||||||
var userAgent = httpContext.Request.Headers.UserAgent.ToString();
|
|
||||||
|
|
||||||
return RateLimitPartition.GetSlidingWindowLimiter
|
|
||||||
(userAgent, _ =>
|
|
||||||
new SlidingWindowRateLimiterOptions
|
|
||||||
{
|
|
||||||
PermitLimit = 1000,
|
|
||||||
Window = TimeSpan.FromSeconds(60),
|
|
||||||
SegmentsPerWindow = 6,
|
|
||||||
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//jwt鉴权
|
|
||||||
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
|
|
||||||
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
|
|
||||||
|
|
||||||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ClockSkew = TimeSpan.Zero,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
ValidIssuer = jwtOptions.Issuer,
|
|
||||||
ValidAudience = jwtOptions.Audience,
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
|
||||||
};
|
|
||||||
options.Events = new JwtBearerEvents
|
|
||||||
{
|
|
||||||
OnMessageReceived = context =>
|
|
||||||
{
|
|
||||||
var accessToken = context.Request.Query["access_token"];
|
|
||||||
if (!string.IsNullOrEmpty(accessToken))
|
|
||||||
{
|
|
||||||
context.Token = accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.AddJwtBearer(TokenTypeConst.Refresh, options =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ClockSkew = TimeSpan.Zero,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
ValidIssuer = refreshJwtOptions.Issuer,
|
|
||||||
ValidAudience = refreshJwtOptions.Audience,
|
|
||||||
IssuerSigningKey =
|
|
||||||
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
|
|
||||||
};
|
|
||||||
options.Events = new JwtBearerEvents
|
|
||||||
{
|
|
||||||
OnMessageReceived = context =>
|
|
||||||
{
|
|
||||||
var refresh_token = context.Request.Headers["refresh_token"];
|
|
||||||
if (!string.IsNullOrEmpty(refresh_token))
|
|
||||||
{
|
|
||||||
context.Token = refresh_token;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var refreshToken = context.Request.Query["refresh_token"];
|
|
||||||
if (!string.IsNullOrEmpty(refreshToken))
|
|
||||||
{
|
|
||||||
context.Token = refreshToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); })
|
|
||||||
.AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); });
|
|
||||||
|
|
||||||
//授权
|
|
||||||
context.Services.AddAuthorization();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -277,30 +113,17 @@ namespace Yi.Abp.Web
|
|||||||
//跨域
|
//跨域
|
||||||
app.UseCors(DefaultCorsPolicyName);
|
app.UseCors(DefaultCorsPolicyName);
|
||||||
|
|
||||||
if (!env.IsDevelopment())
|
|
||||||
{
|
|
||||||
//速率限制
|
|
||||||
app.UseRateLimiter();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//无感token,先刷新再鉴权
|
|
||||||
app.UseRefreshToken();
|
|
||||||
|
|
||||||
//鉴权
|
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
|
|
||||||
//多租户
|
|
||||||
app.UseMultiTenancy();
|
|
||||||
|
|
||||||
//swagger
|
//swagger
|
||||||
app.UseYiSwagger();
|
app.UseYiSwagger();
|
||||||
|
|
||||||
//流量访问统计,需redis支持,否则不生效
|
|
||||||
app.UseAccessLog();
|
|
||||||
|
|
||||||
//请求处理
|
|
||||||
app.UseYiApiHandlinge();
|
|
||||||
|
|
||||||
//静态资源
|
//静态资源
|
||||||
app.UseStaticFiles("/api/app/wwwroot");
|
app.UseStaticFiles("/api/app/wwwroot");
|
||||||
@@ -308,15 +131,12 @@ namespace Yi.Abp.Web
|
|||||||
app.UseDirectoryBrowser("/api/app/wwwroot");
|
app.UseDirectoryBrowser("/api/app/wwwroot");
|
||||||
|
|
||||||
|
|
||||||
// app.Properties.Add("_AbpExceptionHandlingMiddleware_Added",false);
|
|
||||||
//工作单元
|
//工作单元
|
||||||
app.UseUnitOfWork();
|
app.UseUnitOfWork();
|
||||||
|
|
||||||
//授权
|
//授权
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
//审计日志
|
|
||||||
app.UseAuditing();
|
|
||||||
|
|
||||||
//日志记录
|
//日志记录
|
||||||
app.UseAbpSerilogEnrichers();
|
app.UseAbpSerilogEnrichers();
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export function getCodeImg() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 获取短信验证码
|
// 获取短信验证码
|
||||||
export function getCodePhone(phone) {
|
export function getCodePhone(phoneForm) {
|
||||||
return request({
|
return request({
|
||||||
url: "/account/captcha-phone",
|
url: "/account/captcha-phone",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -91,11 +91,11 @@ export function getCodePhone(phone) {
|
|||||||
},
|
},
|
||||||
method: "post",
|
method: "post",
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
data: { phone },
|
data: phoneForm,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 获取短信验证码-为了重置密码
|
// 获取短信验证码-为了重置密码
|
||||||
export function getCodePhoneForRetrievePassword(phone) {
|
export function getCodePhoneForRetrievePassword(form) {
|
||||||
return request({
|
return request({
|
||||||
url: "/account/captcha-phone/repassword",
|
url: "/account/captcha-phone/repassword",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -103,6 +103,6 @@ export function getCodePhoneForRetrievePassword(phone) {
|
|||||||
},
|
},
|
||||||
method: "post",
|
method: "post",
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
data: { phone },
|
data: form,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
// 注册逻辑
|
// 注册逻辑
|
||||||
import {reactive, ref} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
import {getCodePhoneForRetrievePassword} from "@/apis/accountApi";
|
import {getCodePhoneForRetrievePassword} from "@/apis/accountApi";
|
||||||
import useAuths from "@/hooks/useAuths";
|
import useAuths from "@/hooks/useAuths";
|
||||||
import { useRouter} from "vue-router";
|
import { useRouter} from "vue-router";
|
||||||
const { retrievePasswordFun } = useAuths();
|
const { retrievePasswordFun } = useAuths();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
import useUserStore from "@/stores/user";
|
||||||
const retrievePasswordFormRef = ref();
|
const retrievePasswordFormRef = ref();
|
||||||
|
//验证码弹窗
|
||||||
|
const codeDialogVisible=ref(false);
|
||||||
|
|
||||||
|
// 获取图片验证码
|
||||||
|
const codeImageURL = computed(() => useUserStore().codeImageURL);
|
||||||
|
const codeUUid = computed(() => useUserStore().codeUUid);
|
||||||
// 确认密码
|
// 确认密码
|
||||||
const passwordConfirm = ref("");
|
const passwordConfirm = ref("");
|
||||||
const registerForm = reactive({
|
const registerForm = reactive({
|
||||||
@@ -18,6 +23,11 @@ const registerForm = reactive({
|
|||||||
uuid: "",
|
uuid: "",
|
||||||
code: ""
|
code: ""
|
||||||
});
|
});
|
||||||
|
const phoneForm=reactive({
|
||||||
|
code:"",
|
||||||
|
phone:"",
|
||||||
|
uuid:codeUUid
|
||||||
|
});
|
||||||
const registerRules = reactive({
|
const registerRules = reactive({
|
||||||
phone: [{ required: true, message: "请输入手机号", trigger: "blur" }],
|
phone: [{ required: true, message: "请输入手机号", trigger: "blur" }],
|
||||||
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
|
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
|
||||||
@@ -56,14 +66,38 @@ const retrievePassword = async (formEl) => {
|
|||||||
const codeInfo = ref("发送短信");
|
const codeInfo = ref("发送短信");
|
||||||
const isDisabledCode = ref(false);
|
const isDisabledCode = ref(false);
|
||||||
|
|
||||||
|
//点击验证码
|
||||||
|
const handleGetCodeImage=()=>{
|
||||||
|
useUserStore().updateCodeImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击手机发送短信
|
||||||
|
const clickPhoneCaptcha=()=>{
|
||||||
|
if (registerForm.phone !== "")
|
||||||
|
{
|
||||||
|
handleGetCodeImage();
|
||||||
|
codeDialogVisible.value=true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ElMessage({
|
||||||
|
message: `请先输入手机号`,
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//前往登录
|
//前往登录
|
||||||
const handleSignInNow=()=>{
|
const handleSignInNow=()=>{
|
||||||
router.push("/login");
|
router.push("/login");
|
||||||
}
|
}
|
||||||
const captcha = async () => {
|
const captcha = async () => {
|
||||||
if (registerForm.phone !== "") {
|
if (registerForm.phone!==""&&phoneForm.code!=="")
|
||||||
const { data } = await getCodePhoneForRetrievePassword(registerForm.phone);
|
{
|
||||||
|
phoneForm.phone=registerForm.phone;
|
||||||
|
const { data } = await getCodePhoneForRetrievePassword(phoneForm);
|
||||||
registerForm.uuid = data.uuid;
|
registerForm.uuid = data.uuid;
|
||||||
|
codeDialogVisible.value=false;
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已向${registerForm.phone}发送验证码,请注意查收`,
|
message: `已向${registerForm.phone}发送验证码,请注意查收`,
|
||||||
type: "success",
|
type: "success",
|
||||||
@@ -113,7 +147,7 @@ const captcha = async () => {
|
|||||||
<el-form-item prop="phone">
|
<el-form-item prop="phone">
|
||||||
<div class="phone-code">
|
<div class="phone-code">
|
||||||
<input class="phone-code-input" type="text" v-model.trim="registerForm.phone">
|
<input class="phone-code-input" type="text" v-model.trim="registerForm.phone">
|
||||||
<button type="button" class="phone-code-btn" @click="captcha()">{{codeInfo}}</button>
|
<button type="button" class="phone-code-btn" @click="clickPhoneCaptcha()">{{codeInfo}}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -146,8 +180,41 @@ const captcha = async () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<el-dialog
|
||||||
|
v-model="codeDialogVisible"
|
||||||
|
title="发送短信"
|
||||||
|
width="500"
|
||||||
|
center
|
||||||
|
>
|
||||||
|
<div class="dialog-body">
|
||||||
|
<img class="code-img" alt="加载中" @click="handleGetCodeImage" :src="codeImageURL">
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<p>*图片验证码</p>
|
||||||
|
<el-form-item prop="code" >
|
||||||
|
<input type="text" v-model.trim="phoneForm.code">
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<button @click="captcha" style="width:80% " type="button" class="phone-code-btn">确认发送</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style src="@/assets/styles/login.css" scoped>
|
<style src="@/assets/styles/login.css" scoped>
|
||||||
</style>
|
</style>
|
||||||
|
<style scoped>
|
||||||
|
.dialog-body
|
||||||
|
{
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.code-img{
|
||||||
|
margin: 25px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
// 注册逻辑
|
// 注册逻辑
|
||||||
import {reactive, ref} from "vue";
|
import {computed, reactive, ref} from "vue";
|
||||||
import {getCodePhone} from "@/apis/accountApi";
|
import {getCodePhone} from "@/apis/accountApi";
|
||||||
import useAuths from "@/hooks/useAuths";
|
import useAuths from "@/hooks/useAuths";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
import useUserStore from "@/stores/user";
|
||||||
const { registerFun } = useAuths();
|
const { registerFun } = useAuths();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const registerFormRef = ref();
|
const registerFormRef = ref();
|
||||||
|
//验证码弹窗
|
||||||
|
const codeDialogVisible=ref(false);
|
||||||
|
|
||||||
|
// 获取图片验证码
|
||||||
|
const codeImageURL = computed(() => useUserStore().codeImageURL);
|
||||||
|
const codeUUid = computed(() => useUserStore().codeUUid);
|
||||||
// 确认密码
|
// 确认密码
|
||||||
const passwordConfirm = ref("");
|
const passwordConfirm = ref("");
|
||||||
const registerForm = reactive({
|
const registerForm = reactive({
|
||||||
@@ -21,6 +26,11 @@ const registerForm = reactive({
|
|||||||
code: "",
|
code: "",
|
||||||
nick:""
|
nick:""
|
||||||
});
|
});
|
||||||
|
const phoneForm=reactive({
|
||||||
|
code:"",
|
||||||
|
phone:"",
|
||||||
|
uuid:codeUUid
|
||||||
|
});
|
||||||
const registerRules = reactive({
|
const registerRules = reactive({
|
||||||
nick: [
|
nick: [
|
||||||
{ min: 2, message: "昵称需大于两位", trigger: "blur" },
|
{ min: 2, message: "昵称需大于两位", trigger: "blur" },
|
||||||
@@ -65,14 +75,37 @@ const register = async (formEl) => {
|
|||||||
const codeInfo = ref("发送短信");
|
const codeInfo = ref("发送短信");
|
||||||
const isDisabledCode = ref(false);
|
const isDisabledCode = ref(false);
|
||||||
|
|
||||||
|
//点击验证码
|
||||||
|
const handleGetCodeImage=()=>{
|
||||||
|
useUserStore().updateCodeImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击手机发送短信
|
||||||
|
const clickPhoneCaptcha=()=>{
|
||||||
|
if (registerForm.phone !== "")
|
||||||
|
{
|
||||||
|
handleGetCodeImage();
|
||||||
|
codeDialogVisible.value=true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ElMessage({
|
||||||
|
message: `请先输入手机号`,
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//前往登录
|
//前往登录
|
||||||
const handleSignInNow=()=>{
|
const handleSignInNow=()=>{
|
||||||
router.push("/login");
|
router.push("/login");
|
||||||
}
|
}
|
||||||
const captcha = async () => {
|
const captcha = async () => {
|
||||||
if (registerForm.phone !== "") {
|
if (registerForm.phone!==""&&phoneForm.code!=="")
|
||||||
const { data } = await getCodePhone(registerForm.phone);
|
{
|
||||||
|
phoneForm.phone=registerForm.phone;
|
||||||
|
const { data } = await getCodePhone(phoneForm);
|
||||||
registerForm.uuid = data.uuid;
|
registerForm.uuid = data.uuid;
|
||||||
|
codeDialogVisible.value=false;
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `已向${registerForm.phone}发送验证码,请注意查收`,
|
message: `已向${registerForm.phone}发送验证码,请注意查收`,
|
||||||
type: "success",
|
type: "success",
|
||||||
@@ -90,12 +123,15 @@ const captcha = async () => {
|
|||||||
time--;
|
time--;
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `请先输入手机号`,
|
message: `请先输入手机号`,
|
||||||
type: "warning",
|
type: "warning",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -138,7 +174,7 @@ const captcha = async () => {
|
|||||||
<el-form-item prop="phone">
|
<el-form-item prop="phone">
|
||||||
<div class="phone-code">
|
<div class="phone-code">
|
||||||
<input class="phone-code-input" type="text" v-model.trim="registerForm.phone">
|
<input class="phone-code-input" type="text" v-model.trim="registerForm.phone">
|
||||||
<button type="button" class="phone-code-btn" @click="captcha()">{{codeInfo}}</button>
|
<button type="button" class="phone-code-btn" @click="clickPhoneCaptcha()">{{codeInfo}}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -171,8 +207,43 @@ const captcha = async () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="codeDialogVisible"
|
||||||
|
title="发送短信"
|
||||||
|
width="500"
|
||||||
|
center
|
||||||
|
>
|
||||||
|
<div class="dialog-body">
|
||||||
|
<img class="code-img" alt="加载中" @click="handleGetCodeImage" :src="codeImageURL">
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
<p>*图片验证码</p>
|
||||||
|
<el-form-item prop="code" >
|
||||||
|
<input type="text" v-model.trim="phoneForm.code">
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<button @click="captcha" style="width:80% " type="button" class="phone-code-btn">确认发送</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style src="@/assets/styles/login.css" scoped>
|
<style src="@/assets/styles/login.css" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<style scoped>
|
||||||
|
.dialog-body
|
||||||
|
{
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.code-img{
|
||||||
|
margin: 25px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -91,13 +91,28 @@ defineExpose({ getRef });
|
|||||||
<re-col
|
<re-col
|
||||||
v-show="newFormInline.menuType !== 2"
|
v-show="newFormInline.menuType !== 2"
|
||||||
:value="24"
|
:value="24"
|
||||||
:xs="24"
|
:xs="12"
|
||||||
:sm="24"
|
:sm="12"
|
||||||
>
|
>
|
||||||
<el-form-item label="菜单图标">
|
<el-form-item label="菜单图标">
|
||||||
<IconSelect v-model="newFormInline.menuIcon" class="w-full" />
|
<IconSelect v-model="newFormInline.menuIcon" class="w-full" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</re-col>
|
</re-col>
|
||||||
|
<re-col
|
||||||
|
v-show="newFormInline.menuType !== 2"
|
||||||
|
:value="24"
|
||||||
|
:xs="12"
|
||||||
|
:sm="12"
|
||||||
|
>
|
||||||
|
<el-form-item label="路由名称">
|
||||||
|
<el-input
|
||||||
|
v-model="newFormInline.routerName"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入菜单名称"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</re-col>
|
||||||
<re-col :value="12" :xs="24" :sm="24">
|
<re-col :value="12" :xs="24" :sm="24">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
<el-input
|
<el-input
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export function useMenu() {
|
|||||||
{
|
{
|
||||||
label: "显示",
|
label: "显示",
|
||||||
prop: "isShow",
|
prop: "isShow",
|
||||||
formatter: ({ isShow }) => (isShow ? "否" : "是"),
|
formatter: ({ isShow }) => (isShow ? "是" : "否"),
|
||||||
width: 100
|
width: 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
"typeface-roboto": "^1.1.13",
|
"typeface-roboto": "^1.1.13",
|
||||||
"vue": "3.4.21",
|
"vue": "3.4.21",
|
||||||
"vue-cropper": "1.0.3",
|
"vue-cropper": "1.0.3",
|
||||||
"vue-router": "4.3.0"
|
"vue-router": "4.3.0",
|
||||||
|
"vform3-builds": "^3.0.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ aside {
|
|||||||
|
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
|
|
||||||
|
.el-pagination{
|
||||||
|
right:20px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import App from './App'
|
|||||||
import store from './store'
|
import store from './store'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import directive from './directive' // directive
|
import directive from './directive' // directive
|
||||||
|
import VForm3 from 'vform3-builds'
|
||||||
|
import 'vform3-builds/dist/designer.style.css' //引入VForm3样式
|
||||||
|
|
||||||
|
|
||||||
// 注册指令
|
// 注册指令
|
||||||
@@ -77,5 +79,6 @@ app.use(ElementPlus, {
|
|||||||
// 支持 large、default、small
|
// 支持 large、default、small
|
||||||
size: Cookies.get('size') || 'default'
|
size: Cookies.get('size') || 'default'
|
||||||
})
|
})
|
||||||
|
app.use(VForm3)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const loginRules = {
|
|||||||
const codeUrl = ref("");
|
const codeUrl = ref("");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
// 验证码开关
|
// 验证码开关
|
||||||
const captchaEnabled = ref(true);
|
const captchaEnabled = ref(false);
|
||||||
// 注册开关
|
// 注册开关
|
||||||
const register = ref(false);
|
const register = ref(false);
|
||||||
const redirect = ref(undefined);
|
const redirect = ref(undefined);
|
||||||
@@ -157,7 +157,7 @@ function handleLogin() {
|
|||||||
function getCode() {
|
function getCode() {
|
||||||
|
|
||||||
getCodeImg().then(res => {
|
getCodeImg().then(res => {
|
||||||
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
|
captchaEnabled.value = res.data.isEnableCaptcha === undefined ? true : res.data.isEnableCaptcha;
|
||||||
if (captchaEnabled.value) {
|
if (captchaEnabled.value) {
|
||||||
codeUrl.value = "data:image/gif;base64," + res.data.img;
|
codeUrl.value = "data:image/gif;base64," + res.data.img;
|
||||||
loginForm.value.uuid = res.data.uuid;
|
loginForm.value.uuid = res.data.uuid;
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ function handleRegister() {
|
|||||||
|
|
||||||
function getCode() {
|
function getCode() {
|
||||||
getCodeImg().then(res => {
|
getCodeImg().then(res => {
|
||||||
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
|
captchaEnabled.value = res.data.isEnableCaptcha === undefined ? true : res.data.isEnableCaptcha;
|
||||||
if (captchaEnabled.value) {
|
if (captchaEnabled.value) {
|
||||||
codeUrl.value = "data:image/gif;base64," + res.img;
|
codeUrl.value = "data:image/gif;base64," + res.img;
|
||||||
registerForm.value.uuid = res.uuid;
|
registerForm.value.uuid = res.uuid;
|
||||||
|
|||||||
@@ -9,6 +9,14 @@
|
|||||||
@keyup.enter="handleQuery"
|
@keyup.enter="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="部门编号" prop="deptCode">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.deptCode"
|
||||||
|
placeholder="请输入部门编号"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="state">
|
<el-form-item label="状态" prop="state">
|
||||||
<el-select v-model="queryParams.state" placeholder="部门状态" clearable>
|
<el-select v-model="queryParams.state" placeholder="部门状态" clearable>
|
||||||
<el-option
|
<el-option
|
||||||
@@ -55,6 +63,7 @@
|
|||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
>
|
>
|
||||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||||
|
<el-table-column prop="deptCode" label="部门编号" width="200"></el-table-column>
|
||||||
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
|
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
|
||||||
<el-table-column prop="state" label="状态" width="100">
|
<el-table-column prop="state" label="状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -112,6 +121,11 @@
|
|||||||
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
|
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="部门编号" prop="deptCode">
|
||||||
|
<el-input v-model="form.deptCode" placeholder="部门编号" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="显示排序" prop="orderNum">
|
<el-form-item label="显示排序" prop="orderNum">
|
||||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||||
@@ -173,11 +187,13 @@ const refreshTable = ref(true);
|
|||||||
const data = reactive({
|
const data = reactive({
|
||||||
form: {},
|
form: {},
|
||||||
queryParams: {
|
queryParams: {
|
||||||
|
deptCode:undefined,
|
||||||
deptName: undefined,
|
deptName: undefined,
|
||||||
state: undefined
|
state: undefined
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
|
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
|
||||||
|
deptCode: [{ required: true, message: "部门编号不能为空", trigger: "blur" }],
|
||||||
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
|
deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
|
||||||
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
|
orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
|
||||||
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
<el-form
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryRef"
|
||||||
|
:inline="true"
|
||||||
|
v-show="showSearch"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
<el-form-item label="字典名称" prop="dictType">
|
<el-form-item label="字典名称" prop="dictType">
|
||||||
<el-select v-model="queryParams.dictType">
|
<el-select v-model="queryParams.dictType" style="width: 200px">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in typeOptions"
|
v-for="item in typeOptions"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@@ -20,7 +26,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="state">
|
<el-form-item label="状态" prop="state">
|
||||||
<el-select v-model="queryParams.state" placeholder="数据状态" clearable>
|
<el-select
|
||||||
|
v-model="queryParams.state"
|
||||||
|
placeholder="数据状态"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in sys_normal_disable"
|
v-for="dict in sys_normal_disable"
|
||||||
:key="JSON.parse(dict.value)"
|
:key="JSON.parse(dict.value)"
|
||||||
@@ -30,11 +41,196 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery"
|
||||||
|
>搜索</el-button
|
||||||
|
>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="Plus"
|
||||||
|
@click="handleAdd"
|
||||||
|
v-hasPermi="['system:dict:add']"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
icon="Edit"
|
||||||
|
:disabled="single"
|
||||||
|
@click="handleUpdate"
|
||||||
|
v-hasPermi="['system:dict:edit']"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
icon="Delete"
|
||||||
|
:disabled="multiple"
|
||||||
|
@click="handleDelete"
|
||||||
|
v-hasPermi="['system:dict:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
icon="Download"
|
||||||
|
@click="handleExport"
|
||||||
|
v-hasPermi="['system:dict:export']"
|
||||||
|
>导出</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="warning" plain icon="Close" @click="handleClose"
|
||||||
|
>关闭</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
@queryTable="getList"
|
||||||
|
></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
v-loading="loading"
|
||||||
|
:data="dataList"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<!-- <el-table-column label="字典编码" align="center" prop="id" /> -->
|
||||||
|
<el-table-column label="字典标签" align="center" prop="dictLabel">
|
||||||
|
<template #default="scope">
|
||||||
|
<span
|
||||||
|
v-if="scope.row.listClass == '' || scope.row.listClass == 'default'"
|
||||||
|
>{{ scope.row.dictLabel }}</span
|
||||||
|
>
|
||||||
|
<el-tag
|
||||||
|
v-else
|
||||||
|
:type="scope.row.listClass == 'primary' ? '' : scope.row.listClass"
|
||||||
|
>{{ scope.row.dictLabel }}</el-tag
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="字典键值" align="center" prop="dictValue" />
|
||||||
|
<el-table-column label="字典排序" align="center" prop="orderNum" />
|
||||||
|
<el-table-column label="状态" align="center" prop="state">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :options="sys_normal_disable" :value="scope.row.state" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="备注"
|
||||||
|
align="center"
|
||||||
|
prop="remark"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="创建时间"
|
||||||
|
align="center"
|
||||||
|
prop="creationTime"
|
||||||
|
width="180"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ parseTime(scope.row.creationTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="操作"
|
||||||
|
align="center"
|
||||||
|
width="150"
|
||||||
|
class-name="small-padding fixed-width"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
icon="Edit"
|
||||||
|
@click="handleUpdate(scope.row)"
|
||||||
|
v-hasPermi="['system:dict:edit']"
|
||||||
|
type="success"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
icon="Delete"
|
||||||
|
@click="handleDelete(scope.row)"
|
||||||
|
v-hasPermi="['system:dict:remove']"
|
||||||
|
type="danger"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total > 0"
|
||||||
|
:total="Number(total)"
|
||||||
|
v-model:page="queryParams.skipCount"
|
||||||
|
v-model:limit="queryParams.maxResultCount"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 添加或修改参数配置对话框 -->
|
||||||
|
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||||
|
<el-form ref="dataRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="字典类型">
|
||||||
|
<el-input v-model="form.dictType" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据标签" prop="dictLabel">
|
||||||
|
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="数据键值" prop="dictValue">
|
||||||
|
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="样式属性" prop="cssClass">
|
||||||
|
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="显示排序" prop="dictSort">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.orderNum"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="回显样式" prop="listClass">
|
||||||
|
<el-select v-model="form.listClass">
|
||||||
|
<el-option
|
||||||
|
v-for="item in listClassOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label + '(' + item.value + ')'"
|
||||||
|
:value="item.value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="state">
|
||||||
|
<el-radio-group v-model="form.state">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in sys_normal_disable"
|
||||||
|
:key="dict.value"
|
||||||
|
:value="JSON.parse(dict.value)"
|
||||||
|
>{{ dict.label }}</el-radio
|
||||||
|
>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input
|
||||||
|
v-model="form.remark"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
|
|||||||
@@ -1,3 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div> 表单构建 <svg-icon icon-class="build" /> </div>
|
<div ref="box">
|
||||||
|
<v-form-designer ></v-form-designer>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref,onMounted} from "vue";
|
||||||
|
|
||||||
|
const box = ref<Element>()
|
||||||
|
onMounted(() =>
|
||||||
|
{
|
||||||
|
box.value?.firstChild?.classList.add("not-margin")
|
||||||
|
box.value?.firstChild?.children[0].remove()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div {
|
||||||
|
margin: 0; /* 如果页面出现垂直滚动条,则加入此行CSS以消除之 */
|
||||||
|
}
|
||||||
|
.not-margin{
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user