committed by
GitHub
158 changed files with 14513 additions and 927 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp |
||||
|
{ |
||||
|
public class AbpCommonModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace LINGYUN.Abp |
||||
|
{ |
||||
|
public class DynamicOptionsProvider<TValue> : IOptionsProvider<TValue>, ITransientDependency |
||||
|
where TValue : class, new() |
||||
|
{ |
||||
|
public TValue Value => _lazyValueFactory.Value; |
||||
|
|
||||
|
private readonly Lazy<TValue> _lazyValueFactory; |
||||
|
private readonly OneTimeRunner _oneTimeRunner; |
||||
|
|
||||
|
public DynamicOptionsProvider(IOptions<TValue> options) |
||||
|
{ |
||||
|
_oneTimeRunner = new OneTimeRunner(); |
||||
|
_lazyValueFactory = new Lazy<TValue>(() => CreateOptions(options)); |
||||
|
} |
||||
|
|
||||
|
protected virtual TValue CreateOptions(IOptions<TValue> options) |
||||
|
{ |
||||
|
// 用于简化需要在使用配置前自行调用此接口的繁复步骤
|
||||
|
// await options.SetAsync();
|
||||
|
// _onTimeRunner.Run(async () => await options.SetAsync());
|
||||
|
return options.Value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace LINGYUN.Abp |
||||
|
{ |
||||
|
public interface IOptionsProvider<TValue> |
||||
|
where TValue: class, new() |
||||
|
{ |
||||
|
TValue Value { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace>LINGYUN.Abp</RootNamespace> |
||||
|
<Description>Abp扩展基础库</Description> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="3.3.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataCreateDto : DataCreateOrUpdateDto |
||||
|
{ |
||||
|
public Guid? ParentId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataCreateOrUpdateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(DataConsts), nameof(DataConsts.MaxNameLength))] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(DataConsts), nameof(DataConsts.MaxDisplayNameLength))] |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(DataConsts), nameof(DataConsts.MaxDescriptionLength))] |
||||
|
public string Description { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataDto : EntityDto<Guid> |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public string Code { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public Guid? ParentId { get; set; } |
||||
|
|
||||
|
public List<DataItemDto> Items { get; set; } = new List<DataItemDto>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItemCreateDto : DataItemCreateOrUpdateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(DataItemConsts), nameof(DataItemConsts.MaxNameLength))] |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
using System; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using LINGYUN.Platform.Localization; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItemCreateOrUpdateDto : IValidatableObject |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(DataItemConsts), nameof(DataItemConsts.MaxDisplayNameLength))] |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(DataItemConsts), nameof(DataItemConsts.MaxValueLength))] |
||||
|
public string DefaultValue { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(DataItemConsts), nameof(DataItemConsts.MaxDescriptionLength))] |
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public bool AllowBeNull { get; set; } |
||||
|
|
||||
|
public ValueType ValueType { get; set; } |
||||
|
|
||||
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) |
||||
|
{ |
||||
|
if (!AllowBeNull && DefaultValue.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
var localizer = validationContext.GetRequiredService<IStringLocalizer<PlatformResource>>(); |
||||
|
yield return new ValidationResult( |
||||
|
localizer["The {0} field is required.", localizer["DisplayName:Value"]], |
||||
|
new string[] { nameof(DefaultValue) }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItemDto : EntityDto<Guid> |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
public string DefaultValue { get; set; } |
||||
|
|
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
public bool AllowBeNull { get; set; } |
||||
|
|
||||
|
public ValueType ValueType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItemUpdateDto : DataItemCreateOrUpdateDto |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataUpdateDto : DataCreateOrUpdateDto |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class GetDataByNameInput |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(DataConsts), nameof(DataConsts.MaxNameLength))] |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class GetDataListInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public string Filter { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public interface IDataAppService : |
||||
|
ICrudAppService< |
||||
|
DataDto, |
||||
|
Guid, |
||||
|
GetDataListInput, |
||||
|
DataCreateDto, |
||||
|
DataUpdateDto> |
||||
|
{ |
||||
|
Task<ListResultDto<DataDto>> GetAllAsync(); |
||||
|
|
||||
|
Task CreateItemAsync(Guid id, DataItemCreateDto input); |
||||
|
|
||||
|
Task UpdateItemAsync(Guid id, string name, DataItemUpdateDto input); |
||||
|
|
||||
|
Task DeleteItemAsync(Guid id, string name); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class GetLayoutListInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public string Filter { get; set; } |
||||
|
|
||||
|
public bool Reverse { get; set; } |
||||
|
|
||||
|
public PlatformType? PlatformType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class LayoutCreateDto : LayoutCreateOrUpdateDto |
||||
|
{ |
||||
|
public Guid DataId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class LayoutCreateOrUpdateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxNameLength))] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxDisplayNameLength))] |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxDescriptionLength))] |
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxPathLength))] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxRedirectLength))] |
||||
|
public string Redirect { get; set; } |
||||
|
|
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class LayoutDto : RouteDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所属平台
|
||||
|
/// </summary>
|
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 约定的Meta采用哪种数据字典,主要是约束路由必须字段的一致性
|
||||
|
/// </summary>
|
||||
|
public Guid DataId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class LayoutUpdateDto : LayoutCreateOrUpdateDto |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public interface ILayoutAppService : |
||||
|
ICrudAppService< |
||||
|
LayoutDto, |
||||
|
Guid, |
||||
|
GetLayoutListInput, |
||||
|
LayoutCreateDto, |
||||
|
LayoutUpdateDto> |
||||
|
{ |
||||
|
Task<ListResultDto<LayoutDto>> GetAllListAsync(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class GetMenuInput |
||||
|
{ |
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuCreateDto : MenuCreateOrUpdateDto |
||||
|
{ |
||||
|
public Guid? ParentId { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public Guid LayoutId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuCreateOrUpdateDto |
||||
|
{ |
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxNameLength))] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxDisplayNameLength))] |
||||
|
public string DisplayName { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxDescriptionLength))] |
||||
|
public string Description { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxPathLength))] |
||||
|
public string Path { get; set; } |
||||
|
|
||||
|
[DynamicStringLength(typeof(RouteConsts), nameof(RouteConsts.MaxRedirectLength))] |
||||
|
public string Redirect { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DynamicStringLength(typeof(MenuConsts), nameof(MenuConsts.MaxComponentLength))] |
||||
|
public string Component { get; set; } |
||||
|
|
||||
|
public bool IsPublic { get; set; } |
||||
|
|
||||
|
public Dictionary<string, object> Meta { get; set; } = new Dictionary<string, object>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuDto : RouteDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 菜单编号
|
||||
|
/// </summary>
|
||||
|
public string Code { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 菜单布局页
|
||||
|
/// </summary>
|
||||
|
public string Component { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属平台
|
||||
|
/// </summary>
|
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 父节点
|
||||
|
/// </summary>
|
||||
|
public Guid? ParentId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属布局标识
|
||||
|
/// </summary>
|
||||
|
public Guid LayoutId { get; set; } |
||||
|
|
||||
|
public bool IsPublic { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuGetAllInput : ISortedResultRequest |
||||
|
{ |
||||
|
public PlatformType? PlatformType { get; set; } |
||||
|
|
||||
|
public string Filter { get; set; } |
||||
|
|
||||
|
public bool Reverse { get; set; } |
||||
|
|
||||
|
public Guid? ParentId { get; set; } |
||||
|
|
||||
|
public string Sorting { get; set; } |
||||
|
|
||||
|
public Guid? LayoutId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuGetByRoleInput |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(80)] |
||||
|
public string Role { get; set; } |
||||
|
|
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuGetByUserInput |
||||
|
{ |
||||
|
[Required] |
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
public string[] Roles { get; set; } = new string[0]; |
||||
|
|
||||
|
public PlatformType PlatformType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuGetListInput : PagedAndSortedResultRequestDto |
||||
|
{ |
||||
|
public PlatformType? PlatformType { get; set; } |
||||
|
|
||||
|
public string Filter { get; set; } |
||||
|
|
||||
|
public bool Reverse { get; set; } |
||||
|
|
||||
|
public Guid? ParentId { get; set; } |
||||
|
|
||||
|
public Guid? LayoutId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuItemDto : RouteDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 菜单编号
|
||||
|
/// </summary>
|
||||
|
public string Code { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 菜单组件
|
||||
|
/// </summary>
|
||||
|
public string Component { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 子菜单列表
|
||||
|
/// </summary>
|
||||
|
public List<MenuItemDto> Children { get; set; } = new List<MenuItemDto>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuUpdateDto : MenuCreateOrUpdateDto |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class RoleMenuInput |
||||
|
{ |
||||
|
[Required] |
||||
|
[StringLength(80)] |
||||
|
public string RoleName { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public List<Guid> MenuIds { get; set; } = new List<Guid>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class UserMenuInput |
||||
|
{ |
||||
|
[Required] |
||||
|
public Guid UserId { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
public List<Guid> MenuIds { get; set; } = new List<Guid>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public interface IMenuAppService : |
||||
|
ICrudAppService< |
||||
|
MenuDto, |
||||
|
Guid, |
||||
|
MenuGetListInput, |
||||
|
MenuCreateDto, |
||||
|
MenuUpdateDto> |
||||
|
{ |
||||
|
Task<ListResultDto<MenuDto>> GetAllAsync(MenuGetAllInput input); |
||||
|
|
||||
|
Task<ListResultDto<MenuDto>> GetUserMenuListAsync(MenuGetByUserInput input); |
||||
|
|
||||
|
Task<ListResultDto<MenuDto>> GetRoleMenuListAsync(MenuGetByRoleInput input); |
||||
|
|
||||
|
Task SetUserMenusAsync(UserMenuInput input); |
||||
|
|
||||
|
Task SetRoleMenusAsync(RoleMenuInput input); |
||||
|
|
||||
|
Task<ListResultDto<MenuDto>> GetCurrentUserMenuListAsync(GetMenuInput input); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public static class PlatformRemoteServiceConsts |
||||
|
{ |
||||
|
public const string RemoteServiceName = "Platform"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Routes |
||||
|
{ |
||||
|
public class RouteDto : EntityDto<Guid> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 路径
|
||||
|
/// </summary>
|
||||
|
public string Path { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 名称
|
||||
|
/// </summary>
|
||||
|
public string Name { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 显示名称
|
||||
|
/// </summary>
|
||||
|
public string DisplayName { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 说明
|
||||
|
/// </summary>
|
||||
|
public string Description { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 重定向路径
|
||||
|
/// </summary>
|
||||
|
public string Redirect { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 路由的一些辅助元素,取决于数据字典的设计
|
||||
|
/// </summary>
|
||||
|
public Dictionary<string, object> Meta { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,14 +0,0 @@ |
|||||
using AutoMapper; |
|
||||
using LINGYUN.Platform.Versions; |
|
||||
|
|
||||
namespace LINGYUN.Platform |
|
||||
{ |
|
||||
public class AppPlatformApplicationMappingProfile : Profile |
|
||||
{ |
|
||||
public AppPlatformApplicationMappingProfile() |
|
||||
{ |
|
||||
CreateMap<VersionFile, VersionFileDto>(); |
|
||||
CreateMap<AppVersion, VersionDto>(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,191 @@ |
|||||
|
using LINGYUN.Platform.Permissions; |
||||
|
using LINGYUN.Platform.Utils; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
[Authorize(PlatformPermissions.DataDictionary.Default)] |
||||
|
public class DataAppService : PlatformApplicationServiceBase, IDataAppService |
||||
|
{ |
||||
|
protected IDataRepository DataRepository { get; } |
||||
|
|
||||
|
public DataAppService( |
||||
|
IDataRepository dataRepository) |
||||
|
{ |
||||
|
DataRepository = dataRepository; |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.Create)] |
||||
|
public virtual async Task<DataDto> CreateAsync(DataCreateDto input) |
||||
|
{ |
||||
|
var data = await DataRepository.FindByNameAsync(input.Name); |
||||
|
if (data != null) |
||||
|
{ |
||||
|
throw new UserFriendlyException("指定名称的数据字典已经存在!"); |
||||
|
} |
||||
|
|
||||
|
string code = string.Empty; |
||||
|
var children = await DataRepository.GetChildrenAsync(input.ParentId); |
||||
|
if (children.Any()) |
||||
|
{ |
||||
|
var lastChildren = children.OrderBy(x => x.Code).FirstOrDefault(); |
||||
|
code = CodeNumberGenerator.CalculateNextCode(lastChildren.Code); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var parentData = input.ParentId != null |
||||
|
? await DataRepository.GetAsync(input.ParentId.Value) |
||||
|
: null; |
||||
|
|
||||
|
code = CodeNumberGenerator.AppendCode(parentData?.Code, CodeNumberGenerator.CreateCode(1)); |
||||
|
} |
||||
|
|
||||
|
data = new Data( |
||||
|
GuidGenerator.Create(), |
||||
|
input.Name, |
||||
|
code, |
||||
|
input.DisplayName, |
||||
|
input.Description, |
||||
|
input.ParentId, |
||||
|
CurrentTenant.Id |
||||
|
); |
||||
|
|
||||
|
data = await DataRepository.InsertAsync(data); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Data, DataDto>(data); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.Delete)] |
||||
|
public virtual async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
|
||||
|
var children = await DataRepository.GetChildrenAsync(data.Id); |
||||
|
if (children.Any()) |
||||
|
{ |
||||
|
throw new UserFriendlyException("当前数据字典存在子节点,无法删除!"); |
||||
|
} |
||||
|
|
||||
|
await DataRepository.DeleteAsync(data); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<DataDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
|
||||
|
return ObjectMapper.Map<Data, DataDto>(data); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ListResultDto<DataDto>> GetAllAsync() |
||||
|
{ |
||||
|
var datas = await DataRepository.GetListAsync(includeDetails: false); |
||||
|
|
||||
|
return new ListResultDto<DataDto>( |
||||
|
ObjectMapper.Map<List<Data>, List<DataDto>>(datas)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PagedResultDto<DataDto>> GetListAsync(GetDataListInput input) |
||||
|
{ |
||||
|
var count = await DataRepository.GetCountAsync(input.Filter); |
||||
|
|
||||
|
var datas = await DataRepository.GetPagedListAsync( |
||||
|
input.Filter, input.Sorting, |
||||
|
false, input.SkipCount, input.MaxResultCount); |
||||
|
|
||||
|
return new PagedResultDto<DataDto>(count, |
||||
|
ObjectMapper.Map<List<Data>, List<DataDto>>(datas)); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.Update)] |
||||
|
public virtual async Task<DataDto> UpdateAsync(Guid id, DataUpdateDto input) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
|
||||
|
if (!string.Equals(data.Name, input.Name, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
data.Name = input.Name; |
||||
|
} |
||||
|
if (!string.Equals(data.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
data.DisplayName = input.DisplayName; |
||||
|
} |
||||
|
if (!string.Equals(data.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
data.Description = input.Description; |
||||
|
} |
||||
|
|
||||
|
data = await DataRepository.UpdateAsync(data); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Data, DataDto>(data); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.ManageItems)] |
||||
|
public virtual async Task UpdateItemAsync(Guid id, string name, DataItemUpdateDto input) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
var dataItem = data.FindItem(name); |
||||
|
if (dataItem == null) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"不存在名为 {name} 的数据字典项!"); |
||||
|
} |
||||
|
|
||||
|
if (!string.Equals(dataItem.DefaultValue, input.DefaultValue, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
dataItem.DefaultValue = input.DefaultValue; |
||||
|
} |
||||
|
if (!string.Equals(dataItem.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
dataItem.DisplayName = input.DisplayName; |
||||
|
} |
||||
|
if (!string.Equals(dataItem.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
dataItem.Description = input.Description; |
||||
|
} |
||||
|
dataItem.AllowBeNull = input.AllowBeNull; |
||||
|
|
||||
|
data = await DataRepository.UpdateAsync(data); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.ManageItems)] |
||||
|
public virtual async Task CreateItemAsync(Guid id, DataItemCreateDto input) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
var dataItem = data.FindItem(input.Name); |
||||
|
if (dataItem != null) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"已经存在名为 {input.Name} 的数据字典项!"); |
||||
|
} |
||||
|
|
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
input.Name, |
||||
|
input.DisplayName, |
||||
|
input.DefaultValue, |
||||
|
input.ValueType, |
||||
|
input.Description, |
||||
|
input.AllowBeNull); |
||||
|
|
||||
|
await DataRepository.UpdateAsync(data); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.DataDictionary.ManageItems)] |
||||
|
public virtual async Task DeleteItemAsync(Guid id, string name) |
||||
|
{ |
||||
|
var data = await DataRepository.GetAsync(id); |
||||
|
data.RemoveItem(name); |
||||
|
|
||||
|
await DataRepository.UpdateAsync(data); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,124 @@ |
|||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Permissions; |
||||
|
using LINGYUN.Platform.Routes; |
||||
|
using LINGYUN.Platform.Utils; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
[Authorize(PlatformPermissions.Layout.Default)] |
||||
|
public class LayoutAppService : PlatformApplicationServiceBase, ILayoutAppService |
||||
|
{ |
||||
|
protected ILayoutRepository LayoutRepository { get; } |
||||
|
|
||||
|
public LayoutAppService( |
||||
|
ILayoutRepository layoutRepository) |
||||
|
{ |
||||
|
LayoutRepository = layoutRepository; |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Layout.Create)] |
||||
|
public virtual async Task<LayoutDto> CreateAsync(LayoutCreateDto input) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.FindByNameAsync(input.Name); |
||||
|
if (layout != null) |
||||
|
{ |
||||
|
throw new UserFriendlyException($"已经存在名为 {input.Name} 的布局!"); |
||||
|
} |
||||
|
|
||||
|
layout = new Layout( |
||||
|
GuidGenerator.Create(), |
||||
|
input.Path, |
||||
|
input.Name, |
||||
|
input.DisplayName, |
||||
|
input.DataId, |
||||
|
input.PlatformType, |
||||
|
input.Redirect, |
||||
|
input.Description, |
||||
|
CurrentTenant.Id); |
||||
|
|
||||
|
layout = await LayoutRepository.InsertAsync(layout); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Layout, LayoutDto>(layout); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Layout.Delete)] |
||||
|
public virtual async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.GetAsync(id); |
||||
|
|
||||
|
//if (await LayoutRepository.AnyMenuAsync(layout.Id))
|
||||
|
//{
|
||||
|
// throw new UserFriendlyException($"不能删除存在菜单的布局!");
|
||||
|
//}
|
||||
|
|
||||
|
await LayoutRepository.DeleteAsync(layout); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<LayoutDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.GetAsync(id); |
||||
|
|
||||
|
return ObjectMapper.Map<Layout, LayoutDto>(layout); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ListResultDto<LayoutDto>> GetAllListAsync() |
||||
|
{ |
||||
|
var layouts = await LayoutRepository.GetListAsync(); |
||||
|
|
||||
|
return new ListResultDto<LayoutDto>( |
||||
|
ObjectMapper.Map<List<Layout>, List<LayoutDto>>(layouts)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PagedResultDto<LayoutDto>> GetListAsync(GetLayoutListInput input) |
||||
|
{ |
||||
|
var count = await LayoutRepository.GetCountAsync(input.PlatformType, input.Filter); |
||||
|
|
||||
|
var layouts = await LayoutRepository.GetPagedListAsync( |
||||
|
input.PlatformType, input.Filter, |
||||
|
input.Sorting, input.Reverse, false, |
||||
|
input.SkipCount, input.MaxResultCount); |
||||
|
|
||||
|
return new PagedResultDto<LayoutDto>(count, |
||||
|
ObjectMapper.Map<List<Layout>, List<LayoutDto>>(layouts)); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Layout.Update)] |
||||
|
public virtual async Task<LayoutDto> UpdateAsync(Guid id, LayoutUpdateDto input) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.GetAsync(id); |
||||
|
|
||||
|
if (!string.Equals(layout.Name, input.Name, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
layout.Name = input.Name; |
||||
|
} |
||||
|
if (!string.Equals(layout.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
layout.DisplayName = input.DisplayName; |
||||
|
} |
||||
|
if (!string.Equals(layout.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
layout.Description = input.Description; |
||||
|
} |
||||
|
if (!string.Equals(layout.Path, input.Path, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
layout.Path = input.Path; |
||||
|
} |
||||
|
if (!string.Equals(layout.Redirect, input.Redirect, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
layout.Redirect = input.Redirect; |
||||
|
} |
||||
|
layout = await LayoutRepository.UpdateAsync(layout); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Layout, LayoutDto>(layout); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,238 @@ |
|||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Permissions; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.Users; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
[Authorize(PlatformPermissions.Menu.Default)] |
||||
|
public class MenuAppService : PlatformApplicationServiceBase, IMenuAppService |
||||
|
{ |
||||
|
protected DataItemMappingOptions DataItemMapping { get; } |
||||
|
protected MenuManager MenuManager { get; } |
||||
|
protected IMenuRepository MenuRepository { get; } |
||||
|
protected IDataRepository DataRepository { get; } |
||||
|
protected ILayoutRepository LayoutRepository { get; } |
||||
|
|
||||
|
public MenuAppService( |
||||
|
MenuManager menuManager, |
||||
|
IMenuRepository menuRepository, |
||||
|
IDataRepository dataRepository, |
||||
|
ILayoutRepository layoutRepository, |
||||
|
IOptions<DataItemMappingOptions> options) |
||||
|
{ |
||||
|
MenuManager = menuManager; |
||||
|
MenuRepository = menuRepository; |
||||
|
DataRepository = dataRepository; |
||||
|
LayoutRepository = layoutRepository; |
||||
|
DataItemMapping = options.Value; |
||||
|
} |
||||
|
|
||||
|
[Authorize] |
||||
|
public virtual async Task<ListResultDto<MenuDto>> GetCurrentUserMenuListAsync(GetMenuInput input) |
||||
|
{ |
||||
|
var myMenus = await MenuRepository.GetUserMenusAsync( |
||||
|
CurrentUser.GetId(), |
||||
|
CurrentUser.Roles, |
||||
|
input.PlatformType); |
||||
|
|
||||
|
return new ListResultDto<MenuDto>( |
||||
|
ObjectMapper.Map<List<Menu>, List<MenuDto>>(myMenus)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<MenuDto> GetAsync(Guid id) |
||||
|
{ |
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
|
||||
|
return ObjectMapper.Map<Menu, MenuDto>(menu); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<ListResultDto<MenuDto>> GetAllAsync(MenuGetAllInput input) |
||||
|
{ |
||||
|
var menus = await MenuRepository.GetAllAsync( |
||||
|
input.Filter, input.Sorting, input.Reverse, |
||||
|
input.PlatformType, input.ParentId, input.LayoutId); |
||||
|
|
||||
|
return new ListResultDto<MenuDto>( |
||||
|
ObjectMapper.Map<List<Menu>, List<MenuDto>>(menus)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<PagedResultDto<MenuDto>> GetListAsync(MenuGetListInput input) |
||||
|
{ |
||||
|
var count = await MenuRepository.GetCountAsync(input.Filter, input.PlatformType, input.ParentId, input.LayoutId); |
||||
|
|
||||
|
var menus = await MenuRepository.GetListAsync( |
||||
|
input.Filter, input.Sorting, input.Reverse, |
||||
|
input.PlatformType, input.ParentId, input.LayoutId, |
||||
|
input.SkipCount, input.MaxResultCount); |
||||
|
|
||||
|
return new PagedResultDto<MenuDto>(count, |
||||
|
ObjectMapper.Map<List<Menu>, List<MenuDto>>(menus)); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.Create)] |
||||
|
public virtual async Task<MenuDto> CreateAsync(MenuCreateDto input) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.GetAsync(input.LayoutId); |
||||
|
var data = await DataRepository.GetAsync(layout.DataId); |
||||
|
|
||||
|
var menu = await MenuManager.CreateAsync( |
||||
|
GuidGenerator.Create(), |
||||
|
layout.Id, |
||||
|
input.Path, |
||||
|
input.Name, |
||||
|
input.Component, |
||||
|
input.DisplayName, |
||||
|
input.Redirect, |
||||
|
input.Description, |
||||
|
layout.PlatformType, |
||||
|
input.ParentId, |
||||
|
CurrentTenant.Id, |
||||
|
input.IsPublic); |
||||
|
|
||||
|
// 利用布局约定的数据字典来校验必须的路由元数据,元数据的加入是为了适配多端路由
|
||||
|
foreach (var dataItem in data.Items) |
||||
|
{ |
||||
|
if (!input.Meta.TryGetValue(dataItem.Name, out object meta)) |
||||
|
{ |
||||
|
if (!dataItem.AllowBeNull) |
||||
|
{ |
||||
|
throw new BusinessException(PlatformErrorCodes.MenuMissingMetadata) |
||||
|
.WithData("Name", dataItem.DisplayName) |
||||
|
.WithData("DataName", data.DisplayName); |
||||
|
} |
||||
|
// 是否需要设定默认值
|
||||
|
menu.SetProperty(dataItem.Name, dataItem.DefaultValue); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// 需要检查参数是否有效
|
||||
|
menu.SetProperty(dataItem.Name, DataItemMapping.MapToString(dataItem.ValueType, meta)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Menu, MenuDto>(menu); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.Update)] |
||||
|
public virtual async Task<MenuDto> UpdateAsync(Guid id, MenuUpdateDto input) |
||||
|
{ |
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
|
||||
|
// 利用布局约定的数据字典来校验必须的路由元数据,元数据的加入是为了适配多端路由
|
||||
|
var layout = await LayoutRepository.GetAsync(menu.LayoutId); |
||||
|
var data = await DataRepository.GetAsync(layout.DataId); |
||||
|
foreach (var dataItem in data.Items) |
||||
|
{ |
||||
|
if (!input.Meta.TryGetValue(dataItem.Name, out object meta)) |
||||
|
{ |
||||
|
if (!dataItem.AllowBeNull) |
||||
|
{ |
||||
|
throw new BusinessException(PlatformErrorCodes.MenuMissingMetadata) |
||||
|
.WithData("Name", dataItem.DisplayName) |
||||
|
.WithData("DataName", data.DisplayName); |
||||
|
} |
||||
|
// 是否需要设定默认值?
|
||||
|
menu.SetProperty(dataItem.Name, dataItem.DefaultValue); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// 与现有的数据做对比
|
||||
|
var menuMeta = menu.GetProperty(dataItem.Name); |
||||
|
if (menuMeta != null && menuMeta.Equals(meta)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
// 需要检查参数是否有效
|
||||
|
menu.SetProperty(dataItem.Name, DataItemMapping.MapToString(dataItem.ValueType, meta)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!string.Equals(menu.Name, input.Name, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.Name = input.Name; |
||||
|
} |
||||
|
if (!string.Equals(menu.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.DisplayName = input.DisplayName; |
||||
|
} |
||||
|
if (!string.Equals(menu.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.Description = input.Description; |
||||
|
} |
||||
|
if (!string.Equals(menu.Path, input.Path, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.Path = input.Path; |
||||
|
} |
||||
|
if (!string.Equals(menu.Redirect, input.Redirect, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.Redirect = input.Redirect; |
||||
|
} |
||||
|
if (!string.Equals(menu.Component, input.Component, StringComparison.InvariantCultureIgnoreCase)) |
||||
|
{ |
||||
|
menu.Component = input.Component; |
||||
|
} |
||||
|
|
||||
|
menu.IsPublic = input.IsPublic; |
||||
|
|
||||
|
await MenuManager.UpdateAsync(menu); |
||||
|
await CurrentUnitOfWork.SaveChangesAsync(); |
||||
|
|
||||
|
return ObjectMapper.Map<Menu, MenuDto>(menu); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.Delete)] |
||||
|
public virtual async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var childrens = await MenuRepository.GetChildrenAsync(id); |
||||
|
if (childrens.Any()) |
||||
|
{ |
||||
|
throw new BusinessException(PlatformErrorCodes.DeleteMenuHaveChildren); |
||||
|
} |
||||
|
|
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
await MenuRepository.DeleteAsync(menu); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.ManageUsers)] |
||||
|
public virtual async Task<ListResultDto<MenuDto>> GetUserMenuListAsync(MenuGetByUserInput input) |
||||
|
{ |
||||
|
var menus = await MenuRepository.GetUserMenusAsync(input.UserId, input.Roles, input.PlatformType); |
||||
|
|
||||
|
return new ListResultDto<MenuDto>( |
||||
|
ObjectMapper.Map<List<Menu>, List<MenuDto>>(menus)); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.ManageUsers)] |
||||
|
public virtual async Task SetUserMenusAsync(UserMenuInput input) |
||||
|
{ |
||||
|
await MenuManager.SetUserMenusAsync(input.UserId, input.MenuIds); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.ManageRoles)] |
||||
|
public virtual async Task SetRoleMenusAsync(RoleMenuInput input) |
||||
|
{ |
||||
|
await MenuManager.SetRoleMenusAsync(input.RoleName, input.MenuIds); |
||||
|
} |
||||
|
|
||||
|
[Authorize(PlatformPermissions.Menu.ManageRoles)] |
||||
|
public virtual async Task<ListResultDto<MenuDto>> GetRoleMenuListAsync(MenuGetByRoleInput input) |
||||
|
{ |
||||
|
var menus = await MenuRepository.GetRoleMenusAsync(new string[] { input.Role }, input.PlatformType); |
||||
|
|
||||
|
return new ListResultDto<MenuDto>( |
||||
|
ObjectMapper.Map<List<Menu>, List<MenuDto>>(menus)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using AutoMapper; |
||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using LINGYUN.Platform.Versions; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public class PlatformApplicationMappingProfile : Profile |
||||
|
{ |
||||
|
public PlatformApplicationMappingProfile() |
||||
|
{ |
||||
|
CreateMap<VersionFile, VersionFileDto>(); |
||||
|
CreateMap<AppVersion, VersionDto>(); |
||||
|
|
||||
|
CreateMap<DataItem, DataItemDto>(); |
||||
|
CreateMap<Data, DataDto>(); |
||||
|
CreateMap<Menu, MenuDto>() |
||||
|
.ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties)); |
||||
|
CreateMap<Layout, LayoutDto>() |
||||
|
.ForMember(dto => dto.Meta, map => map.MapFrom(src => src.ExtraProperties)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public static class DataConsts |
||||
|
{ |
||||
|
public static int MaxNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 30; |
||||
|
|
||||
|
public static int MaxCodeLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 1024; |
||||
|
|
||||
|
public static int MaxDisplayNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 128; |
||||
|
|
||||
|
public static int MaxDescriptionLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 1024; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public static class DataItemConsts |
||||
|
{ |
||||
|
public static int MaxNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 30; |
||||
|
|
||||
|
public static int MaxValueLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 128; |
||||
|
|
||||
|
public static int MaxDisplayNameLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 128; |
||||
|
|
||||
|
public static int MaxDescriptionLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 1024; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public enum ValueType |
||||
|
{ |
||||
|
String = 0, |
||||
|
Numeic = 1, |
||||
|
Boolean = 2, |
||||
|
Date = 3, |
||||
|
DateTime = 4, |
||||
|
Array = 5 |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -1,12 +1,55 @@ |
|||||
{ |
{ |
||||
"culture": "en", |
"culture": "en", |
||||
"texts": { |
"texts": { |
||||
"Platform.VersionFile:404": "File not found, name: {FileName}, version:{FileVersion}!", |
"Platform:01404": "File not found, name: {FileName}, version:{FileVersion}!", |
||||
|
"Platform:02001": "The same menu exists in the sibling directory: {Name}!", |
||||
|
"Platform:02002": "You are not allowed to delete menu nodes when there are other submenus!", |
||||
|
"Platform:02003": "The menu level has reached the specified maximum: {Depth}!", |
||||
|
"Platform:02101": "The menu metadata is missing the necessary element :{Name}, which is defined in the data dictionary :{DataName}!", |
||||
|
"Platform:03001": "The metadata format does not match!", |
||||
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", |
"UploadFileSizeBeyondLimit": "Upload file size cannot exceed {0} MB!", |
||||
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", |
"NotAllowedFileExtensionName": "Not allowed file extension: {0}!", |
||||
"DisplayName:VersionFileLimitLength": "File limit size", |
"DisplayName:VersionFileLimitLength": "File limit size", |
||||
"Description:VersionFileLimitLength": "Limit size of uploaded file in MB", |
"Description:VersionFileLimitLength": "Limit size of uploaded file in MB", |
||||
"DisplayName:AllowVersionFileExtensions": "File extension", |
"DisplayName:AllowVersionFileExtensions": "File extension", |
||||
"Description:AllowVersionFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation" |
"Description:AllowVersionFileExtensions": "List of allowed extensions to upload files, with multiple extensions separated by, don't need a notation", |
||||
|
"DisplayName:Menus": "Menus", |
||||
|
"DisplayName:Name": "Name", |
||||
|
"DisplayName:Code": "Code", |
||||
|
"DisplayName:IsPublic": "Is Public", |
||||
|
"DisplayName:DisplayName": "Display Name", |
||||
|
"DisplayName:Description": "Description", |
||||
|
"DisplayName:AllowBeNull": "Allow Be Null", |
||||
|
"DisplayName:DefaultValue": "Default Value", |
||||
|
"DisplayName:ValueType": "Value Type", |
||||
|
"DisplayName:Path": "Path", |
||||
|
"DisplayName:Redirect": "Redirect", |
||||
|
"DisplayName:Meta": "Meta", |
||||
|
"DisplayName:Component": "Component", |
||||
|
"DisplayName:Filter": "Filter", |
||||
|
"DisplayName:PlatformType": "Platform Type", |
||||
|
"DisplayName:SecrchMenu": "Secrch Menu", |
||||
|
"DisplayName:SecrchLayout": "Secrch Layout", |
||||
|
"DisplayName:Layout": "Layout", |
||||
|
"DisplayName:Basic": "Basic", |
||||
|
"DisplayName:DataDictionary": "Data Dictionary", |
||||
|
"Layout:AddNew": "Add New", |
||||
|
"Layout:Edit": "Edit", |
||||
|
"Layout:EditByName": "Edit Layout - {0}", |
||||
|
"Layout:Delete": "Delete Layout", |
||||
|
"Menu:AddNew": "Add New", |
||||
|
"Menu:AddChildren": "Add Children", |
||||
|
"Menu:Edit": "Edit", |
||||
|
"Menu:EditByName": "Edit Menu - {0}", |
||||
|
"Menu:Delete": "Delete Menu", |
||||
|
"Menu:Manage": "Manage Menus", |
||||
|
"Data:AddNew": "Add New", |
||||
|
"Data:AddChildren": "Add Children", |
||||
|
"Data:Edit": "Edit", |
||||
|
"Data:Delete": "Delete Data", |
||||
|
"Data:AppendItem": "Append Item", |
||||
|
"Data:EditItem": "Edit Item", |
||||
|
"Data:RemoveItem": "Remove Item", |
||||
|
"Data:Items": "Data Items" |
||||
} |
} |
||||
} |
} |
||||
@ -1,12 +1,55 @@ |
|||||
{ |
{ |
||||
"culture": "zh-Hans", |
"culture": "zh-Hans", |
||||
"texts": { |
"texts": { |
||||
"Platform.VersionFile:404": "文件: {FileName}, 版本号:{FileVersion} 不存在!", |
"Platform:01404": "文件: {FileName}, 版本号: {FileVersion} 不存在!", |
||||
|
"Platform:02001": "同级目录下存在相同的菜单: {Name}!", |
||||
|
"Platform:02002": "在有其他子菜单的情况下,不允许删除菜单节点!", |
||||
|
"Platform:02003": "菜单层级已达到规定最大值: {Depth}!", |
||||
|
"Platform:02101": "菜单元数据缺少必要的元素: {Name},此选项在数据字典:{DataName} 中定义!", |
||||
|
"Platform:03001": "元数据格式不匹配!", |
||||
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", |
"UploadFileSizeBeyondLimit": "上传文件大小不能超过 {0} MB!", |
||||
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", |
"NotAllowedFileExtensionName": "不被允许的文件扩展名: {0}!", |
||||
"DisplayName:VersionFileLimitLength": "文件限制大小", |
"DisplayName:VersionFileLimitLength": "文件限制大小", |
||||
"Description:VersionFileLimitLength": "上传文件的限制大小,单位(MB)", |
"Description:VersionFileLimitLength": "上传文件的限制大小,单位(MB)", |
||||
"DisplayName:AllowVersionFileExtensions": "文件扩展名", |
"DisplayName:AllowVersionFileExtensions": "文件扩展名", |
||||
"Description:AllowVersionFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号" |
"Description:AllowVersionFileExtensions": "允许的上传文件扩展名列表,多个扩展名以,分隔,无需输入.符号", |
||||
|
"DisplayName:Menus": "菜单列表", |
||||
|
"DisplayName:Name": "名称", |
||||
|
"DisplayName:Code": "编号", |
||||
|
"DisplayName:IsPublic": "是否公用的", |
||||
|
"DisplayName:DisplayName": "显示名称", |
||||
|
"DisplayName:Description": "说明", |
||||
|
"DisplayName:AllowBeNull": "允许空值", |
||||
|
"DisplayName:DefaultValue": "默认值", |
||||
|
"DisplayName:ValueType": "值类型", |
||||
|
"DisplayName:Path": "路径", |
||||
|
"DisplayName:Redirect": "重定向路径", |
||||
|
"DisplayName:Meta": "元数据", |
||||
|
"DisplayName:Component": "组件", |
||||
|
"DisplayName:Filter": "筛选", |
||||
|
"DisplayName:PlatformType": "平台类型", |
||||
|
"DisplayName:SecrchMenu": "查询菜单", |
||||
|
"DisplayName:SecrchLayout": "查询布局", |
||||
|
"DisplayName:Layout": "布局", |
||||
|
"DisplayName:Basic": "基础信息", |
||||
|
"DisplayName:DataDictionary": "数据字典", |
||||
|
"Layout:AddNew": "添加新布局", |
||||
|
"Layout:Edit": "编辑布局", |
||||
|
"Layout:EditByName": "编辑布局 - {0}", |
||||
|
"Layout:Delete": "删除布局", |
||||
|
"Menu:AddNew": "添加新菜单", |
||||
|
"Menu:AddChildren": "添加子菜单", |
||||
|
"Menu:Edit": "编辑菜单", |
||||
|
"Menu:EditByName": "编辑菜单 - {0}", |
||||
|
"Menu:Delete": "删除菜单", |
||||
|
"Menu:Manage": "管理菜单", |
||||
|
"Data:AddNew": "添加新字典", |
||||
|
"Data:AddChildren": "添加下级字典", |
||||
|
"Data:Edit": "编辑字典", |
||||
|
"Data:Delete": "删除字典", |
||||
|
"Data:AppendItem": "添加项目", |
||||
|
"Data:EditItem": "编辑项目", |
||||
|
"Data:RemoveItem": "删除项目", |
||||
|
"Data:Items": "字典项目" |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public static class MenuConsts |
||||
|
{ |
||||
|
public static int MaxComponentLength |
||||
|
{ |
||||
|
get; |
||||
|
set; |
||||
|
} = 255; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 最大深度
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 默认为4,仅支持四级子菜单
|
||||
|
/// </remarks>
|
||||
|
public const int MaxDepth = 4; |
||||
|
|
||||
|
public const int MaxCodeLength = MaxDepth * (PlatformConsts.CodeUnitLength + 1) - 1; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public static class PlatformConsts |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 编号不足位补足字符,如编号为 3,长度5位,补足字符为 0,则编号为00003
|
||||
|
/// </summary>
|
||||
|
public static char CodePrefix { get; set; } = '0'; |
||||
|
/// <summary>
|
||||
|
/// 编号长度
|
||||
|
/// </summary>
|
||||
|
public const int CodeUnitLength = 5; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.Guids; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 数据字典
|
||||
|
/// </summary>
|
||||
|
public class Data : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual string Name { get; set; } |
||||
|
|
||||
|
public virtual string Code { get; set; } |
||||
|
|
||||
|
public virtual string DisplayName { get; set; } |
||||
|
|
||||
|
public virtual string Description { get; set; } |
||||
|
|
||||
|
public virtual Guid? ParentId { get; set; } |
||||
|
|
||||
|
public virtual ICollection<DataItem> Items { get; protected set; } |
||||
|
|
||||
|
protected Data() |
||||
|
{ |
||||
|
Items = new Collection<DataItem>(); |
||||
|
} |
||||
|
|
||||
|
public Data( |
||||
|
[NotNull] Guid id, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string code, |
||||
|
[NotNull] string displayName, |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
Check.NotNull(id, nameof(id)); |
||||
|
Check.NotNullOrWhiteSpace(name, nameof(name)); |
||||
|
Check.NotNullOrWhiteSpace(code, nameof(code)); |
||||
|
Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); |
||||
|
|
||||
|
Id = id; |
||||
|
Name = name; |
||||
|
Code = code; |
||||
|
DisplayName = displayName; |
||||
|
Description = description; |
||||
|
ParentId = parentId; |
||||
|
TenantId = tenantId; |
||||
|
|
||||
|
CreationTime = DateTime.Now; |
||||
|
|
||||
|
Items = new Collection<DataItem>(); |
||||
|
} |
||||
|
|
||||
|
public Data AddItem( |
||||
|
[NotNull] IGuidGenerator guidGenerator, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string displayName, |
||||
|
[CanBeNull] string defaultValue, |
||||
|
ValueType valueType = ValueType.String, |
||||
|
string description = "", |
||||
|
bool allowBeNull = true) |
||||
|
{ |
||||
|
Check.NotNull(guidGenerator, nameof(guidGenerator)); |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
Check.NotNull(displayName, nameof(displayName)); |
||||
|
|
||||
|
if (!IsInItem(name)) |
||||
|
{ |
||||
|
var dataItem = new DataItem( |
||||
|
guidGenerator.Create(), |
||||
|
Id, |
||||
|
name, |
||||
|
displayName, |
||||
|
defaultValue, |
||||
|
valueType, |
||||
|
description, |
||||
|
allowBeNull, |
||||
|
TenantId |
||||
|
); |
||||
|
Items.Add(dataItem); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public DataItem FindItem(string name) |
||||
|
{ |
||||
|
return Items.FirstOrDefault(item => item.Name == name); |
||||
|
} |
||||
|
|
||||
|
public DataItem FindItem(Guid id) |
||||
|
{ |
||||
|
return Items.FirstOrDefault(item => item.Id == id); |
||||
|
} |
||||
|
|
||||
|
public bool RemoveItem(string name) |
||||
|
{ |
||||
|
if (IsInItem(name)) |
||||
|
{ |
||||
|
Items.RemoveAll(item => item.Name == name); |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public bool IsInItem(string name) |
||||
|
{ |
||||
|
return Items.Any(item => item.Name == name); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataDictionaryDataSeeder : IDataDictionaryDataSeeder, ITransientDependency |
||||
|
{ |
||||
|
protected IGuidGenerator GuidGenerator { get; } |
||||
|
protected IDataRepository DataRepository { get; } |
||||
|
|
||||
|
public DataDictionaryDataSeeder( |
||||
|
IGuidGenerator guidGenerator, |
||||
|
IDataRepository dataRepository) |
||||
|
{ |
||||
|
GuidGenerator = guidGenerator; |
||||
|
DataRepository = dataRepository; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Data> SeedAsync( |
||||
|
string name, |
||||
|
string code, |
||||
|
string displayName, |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var data = await DataRepository.FindByNameAsync(name, cancellationToken: cancellationToken); |
||||
|
|
||||
|
if (data == null) |
||||
|
{ |
||||
|
data = new Data( |
||||
|
GuidGenerator.Create(), |
||||
|
name, |
||||
|
code, |
||||
|
displayName, |
||||
|
description, |
||||
|
parentId, |
||||
|
tenantId); |
||||
|
|
||||
|
data = await DataRepository.InsertAsync(data); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,90 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItem : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual string Name { get; protected set; } |
||||
|
|
||||
|
public virtual string DisplayName { get; set; } |
||||
|
|
||||
|
public virtual string DefaultValue { get; set; } |
||||
|
|
||||
|
public virtual string Description { get; set; } |
||||
|
|
||||
|
public virtual bool AllowBeNull { get; set; } |
||||
|
|
||||
|
public virtual ValueType ValueType { get; protected set; } |
||||
|
|
||||
|
public virtual Guid DataId { get; protected set; } |
||||
|
|
||||
|
protected DataItem() { } |
||||
|
|
||||
|
public DataItem( |
||||
|
[NotNull] Guid id, |
||||
|
[NotNull] Guid dataId, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string displayName, |
||||
|
[CanBeNull] string defaultValue = null, |
||||
|
ValueType valueType = ValueType.String, |
||||
|
string description = "", |
||||
|
bool allowBeNull = true, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
Check.NotNull(id, nameof(id)); |
||||
|
Check.NotNull(dataId, nameof(dataId)); |
||||
|
Check.NotNullOrWhiteSpace(name, nameof(name)); |
||||
|
Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); |
||||
|
|
||||
|
Id = id; |
||||
|
Name = name; |
||||
|
DefaultValue = defaultValue ?? SetDefaultValue(); |
||||
|
ValueType = valueType; |
||||
|
DisplayName = displayName; |
||||
|
AllowBeNull = allowBeNull; |
||||
|
|
||||
|
DataId = dataId; |
||||
|
TenantId = tenantId; |
||||
|
Description = description; |
||||
|
} |
||||
|
|
||||
|
public string SetDefaultValue() |
||||
|
{ |
||||
|
switch (ValueType) |
||||
|
{ |
||||
|
case ValueType.Array: |
||||
|
DefaultValue = "";// 当数据类型为数组对象时,需要前端来做转换了,约定的分隔符为英文逗号
|
||||
|
break; |
||||
|
case ValueType.Boolean: |
||||
|
DefaultValue = "false"; |
||||
|
break; |
||||
|
case ValueType.Date: |
||||
|
DefaultValue = !AllowBeNull ? DateTime.Now.ToString("yyyy-MM-dd") : ""; |
||||
|
break; |
||||
|
case ValueType.DateTime: |
||||
|
if (!AllowBeNull) |
||||
|
{ |
||||
|
DefaultValue = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // TODO: 以当前时间作为默认值?
|
||||
|
} |
||||
|
DefaultValue = !AllowBeNull ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : ""; |
||||
|
break; |
||||
|
case ValueType.Numeic: |
||||
|
DefaultValue = "0"; |
||||
|
break; |
||||
|
default: |
||||
|
case ValueType.String: |
||||
|
DefaultValue = ""; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return DefaultValue; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
using Newtonsoft.Json.Linq; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class DataItemMappingOptions |
||||
|
{ |
||||
|
public Dictionary<ValueType, Func<object, string>> DataItemMaps { get; } |
||||
|
|
||||
|
public DataItemMappingOptions() |
||||
|
{ |
||||
|
DataItemMaps = new Dictionary<ValueType, Func<object, string>>(); |
||||
|
} |
||||
|
|
||||
|
internal void SetDefaultMapping() |
||||
|
{ |
||||
|
SetMapping(ValueType.Array, value => |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
if (value is JArray array) |
||||
|
{ |
||||
|
var joinString = string.Empty; |
||||
|
foreach (var obj in array.Children()) |
||||
|
{ |
||||
|
joinString += obj.ToString() + ","; |
||||
|
} |
||||
|
return joinString.EndsWith(",") ? joinString.Substring(0, joinString.Length - 1) : joinString; |
||||
|
} |
||||
|
throw new BusinessException(PlatformErrorCodes.MetaFormatMissMatch); |
||||
|
}); |
||||
|
SetMapping(ValueType.Boolean, value => |
||||
|
{ |
||||
|
if (value != null) |
||||
|
{ |
||||
|
if (value is bool bo) |
||||
|
{ |
||||
|
return bo.ToString().ToLower(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var boInput = value.ToString().ToLower(); |
||||
|
if (boInput == "true" || |
||||
|
boInput == "false") |
||||
|
{ |
||||
|
return boInput; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
throw new BusinessException(PlatformErrorCodes.MetaFormatMissMatch); |
||||
|
}); |
||||
|
SetMapping(ValueType.Date, value => |
||||
|
{ |
||||
|
if (value != null && value is DateTime date) |
||||
|
{ |
||||
|
return date.ToString("yyyy-MM-dd"); |
||||
|
} |
||||
|
throw new BusinessException(PlatformErrorCodes.MetaFormatMissMatch); |
||||
|
}); |
||||
|
SetMapping(ValueType.DateTime, value => |
||||
|
{ |
||||
|
if (value != null && value is DateTime date) |
||||
|
{ |
||||
|
return date.ToString("yyyy-MM-dd HH:mm:ss"); |
||||
|
} |
||||
|
throw new BusinessException(PlatformErrorCodes.MetaFormatMissMatch); |
||||
|
}); |
||||
|
SetMapping(ValueType.Numeic, value => |
||||
|
{ |
||||
|
if (value != null) |
||||
|
{ |
||||
|
var valueType = value.GetType(); |
||||
|
if (!valueType.IsClass && !valueType.IsInterface && typeof(IFormattable).IsAssignableFrom(valueType)) |
||||
|
{ |
||||
|
return value.ToString(); |
||||
|
} |
||||
|
} |
||||
|
throw new BusinessException(PlatformErrorCodes.MetaFormatMissMatch); |
||||
|
}); |
||||
|
SetMapping(ValueType.String, value => |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return ""; |
||||
|
} |
||||
|
return value.ToString(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void SetMapping(ValueType valueType, Func<object, string> func) |
||||
|
{ |
||||
|
DataItemMaps[valueType] = func; |
||||
|
} |
||||
|
|
||||
|
public string MapToString(ValueType valueType, object inputValue) |
||||
|
{ |
||||
|
return DataItemMaps[valueType](inputValue); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public interface IDataDictionaryDataSeeder |
||||
|
{ |
||||
|
Task<Data> SeedAsync( |
||||
|
string name, |
||||
|
string code, |
||||
|
string displayName, |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public interface IDataRepository : IBasicRepository<Data, Guid> |
||||
|
{ |
||||
|
Task<Data> FindByNameAsync( |
||||
|
string name, |
||||
|
bool includeDetails = true, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Data>> GetChildrenAsync( |
||||
|
Guid? parentId, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
|
||||
|
Task<int> GetCountAsync( |
||||
|
string filter = "", |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Data>> GetPagedListAsync( |
||||
|
string filter = "", |
||||
|
string sotring = nameof(Data.Code), |
||||
|
bool includeDetails = false, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public interface ILayoutRepository : IBasicRepository<Layout, Guid> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 根据名称查询布局
|
||||
|
/// </summary>
|
||||
|
/// <param name="name"></param>
|
||||
|
/// <param name="includeDetails"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<Layout> FindByNameAsync( |
||||
|
string name, |
||||
|
bool includeDetails = true, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<int> GetCountAsync( |
||||
|
PlatformType? platformType = null, |
||||
|
string filter = "", |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Layout>> GetPagedListAsync( |
||||
|
PlatformType? platformType = null, |
||||
|
string filter = "", |
||||
|
string sorting = nameof(Layout.Name), |
||||
|
bool reverse = false, |
||||
|
bool includeDetails = false, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 布局视图实体
|
||||
|
/// </summary>
|
||||
|
public class Layout : Route |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所属平台
|
||||
|
/// </summary>
|
||||
|
public virtual PlatformType PlatformType { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 约定的Meta采用哪种数据字典,主要是约束路由必须字段的一致性
|
||||
|
/// </summary>
|
||||
|
public virtual Guid DataId { get; protected set; } |
||||
|
|
||||
|
protected Layout() { } |
||||
|
|
||||
|
public Layout( |
||||
|
[NotNull] Guid id, |
||||
|
[NotNull] string path, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string displayName, |
||||
|
[NotNull] Guid dataId, |
||||
|
[NotNull] PlatformType platformType = PlatformType.None, |
||||
|
[CanBeNull] string redirect = "", |
||||
|
[CanBeNull] string description = "", |
||||
|
[CanBeNull] Guid? tenantId = null) |
||||
|
: base(id, path, name, displayName, redirect, description, tenantId) |
||||
|
{ |
||||
|
DataId = dataId; |
||||
|
PlatformType = platformType; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public interface IMenuRepository : IBasicRepository<Menu, Guid> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 根据名称查询菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="menuName"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<Menu> FindByNameAsync( |
||||
|
string menuName, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 查询主菜单,每一个布局页创建的时候都要创建路径为 / 的主菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="platformType"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<Menu> FindMainAsync( |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 获取子节点
|
||||
|
/// </summary>
|
||||
|
/// <param name="parentId"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<Menu>> GetChildrenAsync( |
||||
|
Guid? parentId, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
/// <summary>
|
||||
|
/// 通过父菜单编码查询子菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="code"></param>
|
||||
|
/// <param name="parentId"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<Menu>> GetAllChildrenWithParentCodeAsync( |
||||
|
string code, |
||||
|
Guid? parentId, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
/// <summary>
|
||||
|
/// 查找用户可访问菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="userId">用户标识</param>
|
||||
|
/// <param name="roles">角色列表</param>
|
||||
|
/// <param name="platformType">平台类型</param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<Menu>> GetUserMenusAsync( |
||||
|
Guid userId, |
||||
|
string[] roles, |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
/// <summary>
|
||||
|
/// 查找角色可访问菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="roles">角色列表</param>
|
||||
|
/// <param name="platformType">平台类型</param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<Menu>> GetRoleMenusAsync( |
||||
|
string[] roles, |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<int> GetCountAsync( |
||||
|
string filter = "", |
||||
|
PlatformType? platformType = null, |
||||
|
Guid? parentId = null, |
||||
|
Guid? layoutId = null, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Menu>> GetListAsync( |
||||
|
string filter = "", |
||||
|
string sorting = nameof(Menu.Code), |
||||
|
bool reverse = false, |
||||
|
PlatformType? platformType = null, |
||||
|
Guid? parentId = null, |
||||
|
Guid? layoutId = null, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<Menu>> GetAllAsync( |
||||
|
string filter = "", |
||||
|
string sorting = nameof(Menu.Code), |
||||
|
bool reverse = false, |
||||
|
PlatformType? platformType = null, |
||||
|
Guid? parentId = null, |
||||
|
Guid? layoutId = null, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task RemoveAllRolesAsync( |
||||
|
Menu menu, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
|
||||
|
Task RemoveAllMembersAsync( |
||||
|
Menu menu, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public interface IRoleMenuRepository : IBasicRepository<RoleMenu, Guid> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 角色是否拥有菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="roleName"></param>
|
||||
|
/// <param name="menuName"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<bool> RoleHasInMenuAsync( |
||||
|
string roleName, |
||||
|
string menuName, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task SetRoleMenusAsync( |
||||
|
string roleName, |
||||
|
IEnumerable<Guid> menuIds, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public interface IUserMenuRepository : IBasicRepository<UserMenu, Guid> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 用户是否拥有菜单
|
||||
|
/// </summary>
|
||||
|
/// <param name="userId"></param>
|
||||
|
/// <param name="menuName"></param>
|
||||
|
/// <param name="cancellationToken"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<bool> UserHasInMenuAsync( |
||||
|
Guid userId, |
||||
|
string menuName, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task SetMemberMenusAsync( |
||||
|
Guid userId, |
||||
|
IEnumerable<Guid> menuIds, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Platform.Routes; |
||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 菜单
|
||||
|
/// </summary>
|
||||
|
public class Menu : Route |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所属平台
|
||||
|
/// </summary>
|
||||
|
public virtual PlatformType PlatformType { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 菜单编号
|
||||
|
/// </summary>
|
||||
|
public virtual string Code { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 菜单布局页,Layout的路径
|
||||
|
/// </summary>
|
||||
|
public virtual string Component { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属的父菜单
|
||||
|
/// </summary>
|
||||
|
public virtual Guid? ParentId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 所属布局标识
|
||||
|
/// </summary>
|
||||
|
public virtual Guid LayoutId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 公共菜单
|
||||
|
/// </summary>
|
||||
|
public virtual bool IsPublic { get; set; } |
||||
|
protected Menu() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public Menu( |
||||
|
[NotNull] Guid id, |
||||
|
[NotNull] Guid layoutId, |
||||
|
[NotNull] string path, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string code, |
||||
|
[NotNull] string component, |
||||
|
[NotNull] string displayName, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null) |
||||
|
: base(id, path, name, displayName, redirect, description, tenantId) |
||||
|
{ |
||||
|
Check.NotNullOrWhiteSpace(code, nameof(code)); |
||||
|
|
||||
|
LayoutId = layoutId; |
||||
|
Code = code; |
||||
|
Component = component;// 下属的一级菜单的Component应该是布局页, 例如vue-admin中的 component: Layout, 其他前端框架雷同, 此处应传递布局页的路径让前端import
|
||||
|
PlatformType = platformType; |
||||
|
ParentId = parentId; |
||||
|
|
||||
|
IsPublic = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,191 @@ |
|||||
|
using LINGYUN.Platform.Utils; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Domain.Services; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
public class MenuManager : DomainService |
||||
|
{ |
||||
|
protected IMenuRepository MenuRepository { get; } |
||||
|
protected IUserMenuRepository UserMenuRepository { get; } |
||||
|
protected IRoleMenuRepository RoleMenuRepository { get; } |
||||
|
|
||||
|
public MenuManager( |
||||
|
IMenuRepository menuRepository, |
||||
|
IUserMenuRepository userMenuRepository, |
||||
|
IRoleMenuRepository roleMenuRepository) |
||||
|
{ |
||||
|
MenuRepository = menuRepository; |
||||
|
UserMenuRepository = userMenuRepository; |
||||
|
RoleMenuRepository = roleMenuRepository; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task<Menu> CreateAsync( |
||||
|
Guid id, |
||||
|
Guid layoutId, |
||||
|
string path, |
||||
|
string name, |
||||
|
string component, |
||||
|
string displayName, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
bool isPublic = false) |
||||
|
{ |
||||
|
var code = await GetNextChildCodeAsync(parentId); |
||||
|
if (code.Length > MenuConsts.MaxCodeLength) |
||||
|
{ |
||||
|
throw new BusinessException(PlatformErrorCodes.MenuAchieveMaxDepth) |
||||
|
.WithData("Depth", MenuConsts.MaxDepth); |
||||
|
} |
||||
|
var menu = new Menu( |
||||
|
id, |
||||
|
layoutId, |
||||
|
path, |
||||
|
name, |
||||
|
code, |
||||
|
component, |
||||
|
displayName, |
||||
|
redirect, |
||||
|
description, |
||||
|
platformType, |
||||
|
parentId, |
||||
|
tenantId) |
||||
|
{ |
||||
|
IsPublic = isPublic |
||||
|
}; |
||||
|
await ValidateMenuAsync(menu); |
||||
|
await MenuRepository.InsertAsync(menu); |
||||
|
|
||||
|
return menu; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task UpdateAsync(Menu menu) |
||||
|
{ |
||||
|
await ValidateMenuAsync(menu); |
||||
|
await MenuRepository.UpdateAsync(menu); |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
var children = await FindChildrenAsync(id, true); |
||||
|
|
||||
|
foreach (var child in children) |
||||
|
{ |
||||
|
await MenuRepository.RemoveAllMembersAsync(child); |
||||
|
await MenuRepository.RemoveAllRolesAsync(child); |
||||
|
await MenuRepository.DeleteAsync(child); |
||||
|
} |
||||
|
|
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
await MenuRepository.RemoveAllMembersAsync(menu); |
||||
|
await MenuRepository.RemoveAllRolesAsync(menu); |
||||
|
|
||||
|
await MenuRepository.DeleteAsync(id); |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task MoveAsync(Guid id, Guid? parentId) |
||||
|
{ |
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
if (menu.ParentId == parentId) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var children = await FindChildrenAsync(id, true); |
||||
|
|
||||
|
var oldCode = menu.Code; |
||||
|
|
||||
|
menu.Code = await GetNextChildCodeAsync(parentId); |
||||
|
menu.ParentId = parentId; |
||||
|
|
||||
|
await ValidateMenuAsync(menu); |
||||
|
|
||||
|
foreach (var child in children) |
||||
|
{ |
||||
|
child.Code = CodeNumberGenerator.AppendCode(menu.Code, CodeNumberGenerator.GetRelativeCode(child.Code, oldCode)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SetUserMenusAsync(Guid userId, IEnumerable<Guid> menuIds) |
||||
|
{ |
||||
|
await UserMenuRepository.SetMemberMenusAsync(userId, menuIds); |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public virtual async Task SetRoleMenusAsync(string roleName, IEnumerable<Guid> menuIds) |
||||
|
{ |
||||
|
await RoleMenuRepository.SetRoleMenusAsync(roleName, menuIds); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task ValidateMenuAsync(Menu menu) |
||||
|
{ |
||||
|
var siblings = (await FindChildrenAsync(menu.ParentId)) |
||||
|
.Where(x => x.Id != menu.Id) |
||||
|
.ToList(); |
||||
|
|
||||
|
if (siblings.Any(ou => ou.Name == menu.Name)) |
||||
|
{ |
||||
|
throw new BusinessException(PlatformErrorCodes.DuplicateMenu) |
||||
|
.WithData("Name", menu.Name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<string> GetNextChildCodeAsync(Guid? parentId) |
||||
|
{ |
||||
|
var lastChild = await GetLastChildOrNullAsync(parentId); |
||||
|
if (lastChild != null) |
||||
|
{ |
||||
|
return CodeNumberGenerator.CalculateNextCode(lastChild.Code); |
||||
|
} |
||||
|
|
||||
|
var parentCode = parentId != null |
||||
|
? await GetCodeOrDefaultAsync(parentId.Value) |
||||
|
: null; |
||||
|
|
||||
|
return CodeNumberGenerator.AppendCode( |
||||
|
parentCode, |
||||
|
CodeNumberGenerator.CreateCode(1) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Menu> GetLastChildOrNullAsync(Guid? parentId) |
||||
|
{ |
||||
|
var children = await MenuRepository.GetChildrenAsync(parentId); |
||||
|
return children.OrderBy(c => c.Code).LastOrDefault(); |
||||
|
} |
||||
|
|
||||
|
public async Task<List<Menu>> FindChildrenAsync(Guid? parentId, bool recursive = false) |
||||
|
{ |
||||
|
if (!recursive) |
||||
|
{ |
||||
|
return await MenuRepository.GetChildrenAsync(parentId); |
||||
|
} |
||||
|
|
||||
|
if (!parentId.HasValue) |
||||
|
{ |
||||
|
return await MenuRepository.GetListAsync(includeDetails: true); |
||||
|
} |
||||
|
|
||||
|
var code = await GetCodeOrDefaultAsync(parentId.Value); |
||||
|
|
||||
|
return await MenuRepository.GetAllChildrenWithParentCodeAsync(code, parentId); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<string> GetCodeOrDefaultAsync(Guid id) |
||||
|
{ |
||||
|
var menu = await MenuRepository.GetAsync(id); |
||||
|
return menu?.Code; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 角色菜单
|
||||
|
/// </summary>
|
||||
|
public class RoleMenu : AuditedEntity<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid MenuId { get; protected set; } |
||||
|
|
||||
|
public virtual string RoleName { get; protected set; } |
||||
|
|
||||
|
protected RoleMenu() { } |
||||
|
|
||||
|
public RoleMenu( |
||||
|
Guid menuId, |
||||
|
string roleName, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
MenuId = menuId; |
||||
|
RoleName = roleName; |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
public override object[] GetKeys() |
||||
|
{ |
||||
|
return new object[] { MenuId, RoleName }; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Menus |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 用户菜单
|
||||
|
/// </summary>
|
||||
|
public class UserMenu : AuditedEntity<Guid>, IMultiTenant |
||||
|
{ |
||||
|
public virtual Guid? TenantId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid MenuId { get; protected set; } |
||||
|
|
||||
|
public virtual Guid UserId { get; protected set; } |
||||
|
|
||||
|
protected UserMenu() { } |
||||
|
|
||||
|
public UserMenu( |
||||
|
Guid menuId, |
||||
|
Guid userId, |
||||
|
Guid? tenantId = null) |
||||
|
{ |
||||
|
MenuId = menuId; |
||||
|
UserId = userId; |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
|
|
||||
|
public override object[] GetKeys() |
||||
|
{ |
||||
|
return new object[] { MenuId, UserId }; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,768 @@ |
|||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using LINGYUN.Platform.Routes; |
||||
|
using LINGYUN.Platform.Utils; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Data; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace LINGYUN.Platform |
||||
|
{ |
||||
|
public class PlatformDataSeedContributor : IDataSeedContributor, ITransientDependency |
||||
|
{ |
||||
|
protected IGuidGenerator GuidGenerator { get; } |
||||
|
protected IRouteDataSeeder RouteDataSeeder { get; } |
||||
|
protected IDataDictionaryDataSeeder DataDictionaryDataSeeder { get; } |
||||
|
protected IMenuRepository MenuRepository { get; } |
||||
|
protected ILayoutRepository LayoutRepository { get; } |
||||
|
|
||||
|
public PlatformDataSeedContributor( |
||||
|
IRouteDataSeeder routeDataSeeder, |
||||
|
IMenuRepository menuRepository, |
||||
|
ILayoutRepository layoutRepository, |
||||
|
IGuidGenerator guidGenerator, |
||||
|
IDataDictionaryDataSeeder dataDictionaryDataSeeder) |
||||
|
{ |
||||
|
GuidGenerator = guidGenerator; |
||||
|
RouteDataSeeder = routeDataSeeder; |
||||
|
MenuRepository = menuRepository; |
||||
|
LayoutRepository = layoutRepository; |
||||
|
DataDictionaryDataSeeder = dataDictionaryDataSeeder; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SeedAsync(DataSeedContext context) |
||||
|
{ |
||||
|
var data = await SeedDefaultDataDictionaryAsync(context.TenantId); |
||||
|
// 预置
|
||||
|
var layout = await SeedDefaultLayoutAsync(data); |
||||
|
// 首页
|
||||
|
await SeedHomeMenuAsync(layout, data); |
||||
|
// 管理菜单预置菜单数据
|
||||
|
await SeedAdminMenuAsync(layout, data); |
||||
|
// saas菜单数据
|
||||
|
await SeedSaasMenuAsync(layout, data); |
||||
|
// 身份资源菜单数据
|
||||
|
await SeedIdentityServerMenuAsync(layout, data); |
||||
|
// 审计日志菜单数据
|
||||
|
await SeedAuditingMenuAsync(layout, data); |
||||
|
// 布局容器预置菜单数据
|
||||
|
await SeedContainerMenuAsync(layout, data); |
||||
|
// 网关管理菜单数据
|
||||
|
await SeedApiGatewayMenuAsync(layout, data); |
||||
|
} |
||||
|
|
||||
|
private async Task<Data> SeedDefaultDataDictionaryAsync(Guid? tenantId) |
||||
|
{ |
||||
|
var data = await DataDictionaryDataSeeder |
||||
|
.SeedAsync( |
||||
|
"Layout", |
||||
|
CodeNumberGenerator.CreateCode(1), |
||||
|
"Vue Admin Layout Meta Dictionary", |
||||
|
"Vue Admin Layout Meta Dictionary", |
||||
|
null, |
||||
|
tenantId); |
||||
|
|
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"roles", // TODO: 是否需要把这一项写入到预置数据?
|
||||
|
"roles", |
||||
|
"", |
||||
|
Datas.ValueType.Array, |
||||
|
"will control the page roles (allow setting multiple roles)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"title", |
||||
|
"title", |
||||
|
"component", |
||||
|
Datas.ValueType.String, |
||||
|
"the name showed in subMenu and breadcrumb (recommend set)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"icon", |
||||
|
"icon", |
||||
|
"icon", |
||||
|
Datas.ValueType.String, |
||||
|
"the icon showed in the sidebar"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"hidden", |
||||
|
"hidden", |
||||
|
"false", |
||||
|
Datas.ValueType.Boolean, |
||||
|
"if true, this route will not show in the sidebar (default is false)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"alwaysShow", |
||||
|
"alwaysShow", |
||||
|
"false", |
||||
|
Datas.ValueType.Boolean, |
||||
|
"if true, will always show the root menu (default is false)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"breadcrumb", |
||||
|
"breadcrumb", |
||||
|
"true", |
||||
|
Datas.ValueType.Boolean, |
||||
|
"if false, the item will be hidden in breadcrumb (default is true)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"noCache", |
||||
|
"noCache", |
||||
|
"false", |
||||
|
Datas.ValueType.Boolean, |
||||
|
"if true, the page will not be cached (default is false)"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"affix", |
||||
|
"affix", |
||||
|
"false", |
||||
|
Datas.ValueType.Boolean, |
||||
|
"if true, the tag will affix in the tags-view"); |
||||
|
data.AddItem( |
||||
|
GuidGenerator, |
||||
|
"activeMenu", |
||||
|
"activeMenu", |
||||
|
"", |
||||
|
Datas.ValueType.String, |
||||
|
"if set path, the sidebar will highlight the path you set"); |
||||
|
|
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
private async Task<Layout> SeedDefaultLayoutAsync(Data data) |
||||
|
{ |
||||
|
var layout = await RouteDataSeeder.SeedLayoutAsync( |
||||
|
"Layout", |
||||
|
"layout/index.vue", |
||||
|
"Vue Admin Layout", |
||||
|
data.Id, |
||||
|
PlatformType.WebMvvm, // 针对当前的vue管理页
|
||||
|
"", |
||||
|
"Vue Admin Layout", |
||||
|
data.TenantId |
||||
|
); |
||||
|
|
||||
|
return layout; |
||||
|
} |
||||
|
|
||||
|
private async Task SeedHomeMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var adminMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"home", |
||||
|
"/", |
||||
|
CodeNumberGenerator.CreateCode(1), |
||||
|
layout.Path, |
||||
|
"Home", |
||||
|
"/dashboard", |
||||
|
"Home", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "home" }, |
||||
|
{ "icon", "home" }, |
||||
|
{ "alwaysShow", true } |
||||
|
}, |
||||
|
// isPublic: true,
|
||||
|
isPublic: false); // 首页应该是共有的页面
|
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"dashboard", |
||||
|
"dashboard", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/dashboard/index.vue", |
||||
|
"Dashboard", |
||||
|
"", |
||||
|
"Dashboard", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "dashboard" }, |
||||
|
{ "icon", "dashboard" } |
||||
|
}, |
||||
|
isPublic: false); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedAdminMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var adminMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"admin", |
||||
|
"/admin", |
||||
|
CodeNumberGenerator.CreateCode(2), |
||||
|
layout.Path, |
||||
|
"Admin", |
||||
|
"", |
||||
|
"Admin", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "admin" }, |
||||
|
{ "icon", "admin" }, |
||||
|
{ "alwaysShow", true } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"roles", |
||||
|
"roles", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/roles/index.vue", |
||||
|
"Manage Roles", |
||||
|
"", |
||||
|
"Manage Roles", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "roles" }, |
||||
|
{ "icon", "role" }, |
||||
|
{ "roles", new string[] { "AbpIdentity.Roles" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"users", |
||||
|
"users", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/admin/users/index.vue", |
||||
|
"Manage Users", |
||||
|
"", |
||||
|
"Manage Users", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "users" }, |
||||
|
{ "icon", "users" }, |
||||
|
{ "roles", new string[] { "AbpIdentity.Users" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"organization-unit", |
||||
|
"organization-unit", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(3)), |
||||
|
"views/admin/organization-unit/index.vue", |
||||
|
"Manage Organization Units", |
||||
|
"", |
||||
|
"Manage Organization Units", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "organization-unit" }, |
||||
|
{ "icon", "organization-unit" }, |
||||
|
{ "roles", new string[] { "AbpIdentity.OrganizationUnits" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"claim-type", |
||||
|
"claim-type", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(4)), |
||||
|
"views/admin/claim-type/index.vue", |
||||
|
"Manage Organization Units", |
||||
|
"", |
||||
|
"Manage Organization Units", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "claim-type" }, |
||||
|
{ "icon", "claim-type" }, |
||||
|
{ "roles", new string[] { "AbpIdentity.IdentityClaimTypes" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"data-dictionary", |
||||
|
"data-dictionary", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(5)), |
||||
|
"views/admin/data-dictionary/index.vue", |
||||
|
"Manage Data Dictionarys", |
||||
|
"", |
||||
|
"Manage Data Dictionarys", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "data-dictionary" }, |
||||
|
{ "icon", "data-dictionary" }, |
||||
|
{ "roles", new string[] { "Platform.DataDictionary" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"settings", |
||||
|
"settings", |
||||
|
CodeNumberGenerator.AppendCode(adminMenu.Code, CodeNumberGenerator.CreateCode(6)), |
||||
|
"views/admin/settings/index.vue", |
||||
|
"Manage Settings", |
||||
|
"", |
||||
|
"Manage Settings", |
||||
|
adminMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "settings" }, |
||||
|
{ "icon", "settings" }, |
||||
|
{ "roles", new string[] { "AbpSettingManagement.Settings" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedSaasMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var saasMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"saas", |
||||
|
"/saas", |
||||
|
CodeNumberGenerator.CreateCode(3), |
||||
|
layout.Path, |
||||
|
"Saas", |
||||
|
"", |
||||
|
"Saas", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "saas" }, |
||||
|
{ "icon", "saas" }, |
||||
|
{ "alwaysShow", true } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"editions", |
||||
|
"editions", |
||||
|
CodeNumberGenerator.AppendCode(saasMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/edition/index.vue", |
||||
|
"Manage Editions", |
||||
|
"", |
||||
|
"Manage Editions", |
||||
|
saasMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "editions" }, |
||||
|
{ "icon", "editions" } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"tenants", |
||||
|
"tenants", |
||||
|
CodeNumberGenerator.AppendCode(saasMenu.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/admin/tenants/index.vue", |
||||
|
"Manage Tenants", |
||||
|
"", |
||||
|
"Manage Tenants", |
||||
|
saasMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "tenants" }, |
||||
|
{ "icon", "tenants" } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedIdentityServerMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var identityServerMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"identity-server", |
||||
|
"/identity-server", |
||||
|
CodeNumberGenerator.CreateCode(4), |
||||
|
layout.Path, |
||||
|
"Identity Server", |
||||
|
"", |
||||
|
"Identity Server", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "identity-server" }, |
||||
|
{ "icon", "identity-server" }, |
||||
|
{ "alwaysShow", true }, |
||||
|
{ "roles", new string[]{ "AbpIdentityServer.Clients", "AbpIdentityServer.ApiResources", "AbpIdentityServer.IdentityResources" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"clients", |
||||
|
"clients", |
||||
|
CodeNumberGenerator.AppendCode(identityServerMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/identityServer/client/index.vue", |
||||
|
"Manage Clients", |
||||
|
"", |
||||
|
"Manage Clients", |
||||
|
identityServerMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "clients" }, |
||||
|
{ "icon", "clients" }, |
||||
|
{ "roles", new string[]{ "AbpIdentityServer.Clients" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"api-resources", |
||||
|
"api-resources", |
||||
|
CodeNumberGenerator.AppendCode(identityServerMenu.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/admin/identityServer/api-resources/index.vue", |
||||
|
"Manage Api Resources", |
||||
|
"", |
||||
|
"Manage Api Resources", |
||||
|
identityServerMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "api-resources" }, |
||||
|
{ "icon", "api" }, |
||||
|
{ "roles", new string[]{ "AbpIdentityServer.ApiResources" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"identity-resources", |
||||
|
"identity-resources", |
||||
|
CodeNumberGenerator.AppendCode(identityServerMenu.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/admin/identityServer/identity-resources/index.vue", |
||||
|
"Manage Identity Resources", |
||||
|
"", |
||||
|
"Manage Identity Resources", |
||||
|
identityServerMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "identity-resources" }, |
||||
|
{ "icon", "identity" }, |
||||
|
{ "roles", new string[]{ "AbpIdentityServer.IdentityResources" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedAuditingMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var auditingMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"auditing", |
||||
|
"/auditing", |
||||
|
CodeNumberGenerator.CreateCode(5), |
||||
|
layout.Path, |
||||
|
"Auditing", |
||||
|
"", |
||||
|
"Auditing", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "auditing" }, |
||||
|
{ "icon", "auditing" }, |
||||
|
{ "alwaysShow", true }, |
||||
|
{ "roles", new string[]{ "AbpAuditing.AuditLog", "AbpAuditing.SecurityLog" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"audit-log", |
||||
|
"audit-log", |
||||
|
CodeNumberGenerator.AppendCode(auditingMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/auditing/audit-log/index.vue", |
||||
|
"Manage AuditLog", |
||||
|
"", |
||||
|
"Manage AuditLog", |
||||
|
auditingMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "audit-log" }, |
||||
|
{ "icon", "audit-log" }, |
||||
|
{ "roles", new string[]{ "AbpAuditing.AuditLog" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"security-log", |
||||
|
"security-log", |
||||
|
CodeNumberGenerator.AppendCode(auditingMenu.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/admin/auditing/security-log/index.vue", |
||||
|
"Manage SecurityLog", |
||||
|
"", |
||||
|
"Manage SecurityLog", |
||||
|
auditingMenu.Id, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "security-log" }, |
||||
|
{ "icon", "security-log" }, |
||||
|
{ "roles", new string[]{ "AbpAuditing.SecurityLog" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedContainerMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var containerRoot = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"container", |
||||
|
"/container", |
||||
|
CodeNumberGenerator.CreateCode(6), |
||||
|
layout.Path, |
||||
|
"Container", |
||||
|
"", |
||||
|
"Manage Container", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "container" }, |
||||
|
{ "icon", "container" }, |
||||
|
{ "alwaysShow", true } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"layouts", |
||||
|
"layouts", |
||||
|
CodeNumberGenerator.AppendCode(containerRoot.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/container/layouts/index.vue", |
||||
|
"Manage Layouts", |
||||
|
"", |
||||
|
"Manage Layouts", |
||||
|
containerRoot.Id, |
||||
|
containerRoot.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "layouts" }, |
||||
|
{ "icon", "layout" } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"menus", |
||||
|
"menus", |
||||
|
CodeNumberGenerator.AppendCode(containerRoot.Code, CodeNumberGenerator.CreateCode(2)), |
||||
|
"views/container/menus/index.vue", |
||||
|
"Manage Menus", |
||||
|
"", |
||||
|
"Manage Menus", |
||||
|
containerRoot.Id, |
||||
|
containerRoot.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "menus" }, |
||||
|
{ "icon", "menu" } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task SeedApiGatewayMenuAsync(Layout layout, Data data) |
||||
|
{ |
||||
|
var apiGatewayMenu = await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"apigateway", |
||||
|
"/apigateway", |
||||
|
CodeNumberGenerator.CreateCode(7), |
||||
|
layout.Path, |
||||
|
"Manage Api Gateway", |
||||
|
"/group", |
||||
|
"Manage Api Gateway", |
||||
|
null, |
||||
|
layout.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "api-gateway" }, |
||||
|
{ "icon", "api-gateway" }, |
||||
|
{ "alwaysShow", true }, |
||||
|
{ "roles", new string[] { "ApiGateway.RouteGroup", "ApiGateway.Global", "ApiGateway.Route", "ApiGateway.DynamicRoute", "ApiGateway.AggregateRoute" } }, |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
|
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"group", |
||||
|
"group", |
||||
|
CodeNumberGenerator.AppendCode(apiGatewayMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/apigateway/group.vue", |
||||
|
"Manage Groups", |
||||
|
"", |
||||
|
"Manage Groups", |
||||
|
apiGatewayMenu.Id, |
||||
|
apiGatewayMenu.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "group" }, |
||||
|
{ "icon", "group" }, |
||||
|
{ "roles", new string[] { "ApiGateway.RouteGroup" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"global", |
||||
|
"global", |
||||
|
CodeNumberGenerator.AppendCode(apiGatewayMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/apigateway/global.vue", |
||||
|
"Manage Globals", |
||||
|
"", |
||||
|
"Manage Globals", |
||||
|
apiGatewayMenu.Id, |
||||
|
apiGatewayMenu.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "global" }, |
||||
|
{ "icon", "global-setting" }, |
||||
|
{ "roles", new string[] { "ApiGateway.Global" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"route", |
||||
|
"route", |
||||
|
CodeNumberGenerator.AppendCode(apiGatewayMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/apigateway/route.vue", |
||||
|
"Manage Routes", |
||||
|
"", |
||||
|
"Manage Routes", |
||||
|
apiGatewayMenu.Id, |
||||
|
apiGatewayMenu.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "route" }, |
||||
|
{ "icon", "route" }, |
||||
|
{ "roles", new string[] { "ApiGateway.Route" } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
await SeedMenuAsync( |
||||
|
layout, |
||||
|
data, |
||||
|
"aggregate-route", |
||||
|
"aggregate-route", |
||||
|
CodeNumberGenerator.AppendCode(apiGatewayMenu.Code, CodeNumberGenerator.CreateCode(1)), |
||||
|
"views/admin/apigateway/aggregateRoute.vue", |
||||
|
"Manage Aggregate Routes", |
||||
|
"", |
||||
|
"Manage Aggregate Routes", |
||||
|
apiGatewayMenu.Id, |
||||
|
apiGatewayMenu.TenantId, |
||||
|
new Dictionary<string, object>() |
||||
|
{ |
||||
|
{ "title", "aggregate-route" }, |
||||
|
{ "icon", "aggregate" }, |
||||
|
{ "roles", new string[] { "ApiGateway.AggregateRoute " } } |
||||
|
}, |
||||
|
new string[] { "admin" }); |
||||
|
} |
||||
|
|
||||
|
private async Task<Menu> SeedMenuAsync( |
||||
|
Layout layout, |
||||
|
Data data, |
||||
|
string name, |
||||
|
string path, |
||||
|
string code, |
||||
|
string component, |
||||
|
string displayName, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
Dictionary<string, object> meta = null, |
||||
|
string[] roles = null, |
||||
|
Guid[] users = null, |
||||
|
bool isPublic = false |
||||
|
) |
||||
|
{ |
||||
|
var menu = await RouteDataSeeder.SeedMenuAsync( |
||||
|
layout, |
||||
|
name, |
||||
|
path, |
||||
|
code, |
||||
|
component, |
||||
|
displayName, |
||||
|
redirect, |
||||
|
description, |
||||
|
parentId, |
||||
|
tenantId, |
||||
|
isPublic |
||||
|
); |
||||
|
foreach (var item in data.Items) |
||||
|
{ |
||||
|
menu.SetProperty(item.Name, item.DefaultValue); |
||||
|
} |
||||
|
if (meta != null) |
||||
|
{ |
||||
|
foreach (var item in meta) |
||||
|
{ |
||||
|
menu.SetProperty(item.Key, item.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (roles != null) |
||||
|
{ |
||||
|
foreach (var role in roles) |
||||
|
{ |
||||
|
await RouteDataSeeder.SeedRoleMenuAsync(role, menu, tenantId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (users != null) |
||||
|
{ |
||||
|
foreach (var user in users) |
||||
|
{ |
||||
|
await RouteDataSeeder.SeedUserMenuAsync(user, menu, tenantId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return menu; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,6 @@ |
|||||
namespace LINGYUN.Platform |
namespace LINGYUN.Platform |
||||
{ |
{ |
||||
public static class AppPlatformDbProperties |
public static class PlatformDbProperties |
||||
{ |
{ |
||||
public static string DbTablePrefix { get; set; } = "AppPlatform"; |
public static string DbTablePrefix { get; set; } = "AppPlatform"; |
||||
|
|
||||
@ -0,0 +1,50 @@ |
|||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Routes |
||||
|
{ |
||||
|
public interface IRouteDataSeeder |
||||
|
{ |
||||
|
Task<Layout> SeedLayoutAsync( |
||||
|
string name, |
||||
|
string path, |
||||
|
string displayName, |
||||
|
Guid dataId, |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<Menu> SeedMenuAsync( |
||||
|
Layout layout, |
||||
|
string name, |
||||
|
string path, |
||||
|
string code, |
||||
|
string component, |
||||
|
string displayName, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
bool isPublic = false, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task SeedUserMenuAsync( |
||||
|
Guid userId, |
||||
|
Menu menu, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
|
||||
|
Task SeedRoleMenuAsync( |
||||
|
string roleName, |
||||
|
Menu menu, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -1,78 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.Domain.Repositories; |
|
||||
|
|
||||
namespace LINGYUN.Platform.Routes |
|
||||
{ |
|
||||
public interface IRouteRepository : IBasicRepository<Route, Guid> |
|
||||
{ |
|
||||
Task<List<Route>> GetChildrenAsync( |
|
||||
Guid? parentId, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<List<Route>> GetAllChildrenWithParentCodeAsync( |
|
||||
string code, |
|
||||
Guid? parentId, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<Route> GetAsync( |
|
||||
string displayName, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<List<Route>> GetPagedListAsync( |
|
||||
string sorting = null, |
|
||||
int maxResultCount = int.MaxValue, |
|
||||
int skipCount = 0, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<List<Route>> GetRolesRouteAsync( |
|
||||
string roleName, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<List<Route>> GetUsersRouteAsync( |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task RemoveAllUsersRouteAsync( |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task RemoveUserRouteAsync( |
|
||||
Guid userId, |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task RemoveAllRolesRouteAsync( |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task RemoveRoleRouteAsync( |
|
||||
string roleName, |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<bool> IsInRouteAsync( |
|
||||
string roleName, |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
|
|
||||
Task<bool> IsInRouteAsync( |
|
||||
Guid userId, |
|
||||
Route route, |
|
||||
CancellationToken cancellationToken = default |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
@ -1,31 +0,0 @@ |
|||||
using JetBrains.Annotations; |
|
||||
using System; |
|
||||
using Volo.Abp; |
|
||||
using Volo.Abp.Domain.Entities.Auditing; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Platform.Routes |
|
||||
{ |
|
||||
public class RoleRoute : FullAuditedEntity<int>, IMultiTenant |
|
||||
{ |
|
||||
public virtual Guid? TenantId { get; protected set; } |
|
||||
public virtual string RoleName { get; protected set; } |
|
||||
public virtual Guid RouteId { get; protected set; } |
|
||||
protected RoleRoute() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public RoleRoute(int id) |
|
||||
{ |
|
||||
Id = id; |
|
||||
} |
|
||||
|
|
||||
public RoleRoute(Guid routeId, [NotNull] string roleName, Guid? tenantId = null) |
|
||||
{ |
|
||||
RouteId = routeId; |
|
||||
TenantId = tenantId; |
|
||||
RoleName = Check.NotNullOrWhiteSpace(roleName, nameof(roleName)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,193 +1,79 @@ |
|||||
using JetBrains.Annotations; |
using JetBrains.Annotations; |
||||
using System; |
using System; |
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Domain.Entities.Auditing; |
using Volo.Abp.Domain.Entities.Auditing; |
||||
using Volo.Abp.MultiTenancy; |
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
namespace LINGYUN.Platform.Routes |
namespace LINGYUN.Platform.Routes |
||||
{ |
|
||||
// TODO: 因为abp的菜单设计模式是按照权限分配的,是否可以去掉路由的后台配置?
|
|
||||
// 按钮、菜单权限可以在子权限中定义
|
|
||||
// 数据权限需要DbContext拦截器或者创建一个数据过滤仓储的抽象类,需要过滤数据权限的继承自此仓储
|
|
||||
public class Route : FullAuditedAggregateRoot<Guid>, IMultiTenant |
|
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// 租户标识
|
/// 不管是布局还是视图或者页面,都作为路由的实现,因此抽象一个路由实体<br/>
|
||||
|
/// 注意:这是基于 Vue Router 的路由规则设计的实体,详情:https://router.vuejs.org/zh/api/#routes
|
||||
/// </summary>
|
/// </summary>
|
||||
|
public abstract class Route : FullAuditedAggregateRoot<Guid>, IMultiTenant |
||||
|
{ |
||||
public virtual Guid? TenantId { get; protected set; } |
public virtual Guid? TenantId { get; protected set; } |
||||
/// <summary>
|
/// <summary>
|
||||
/// 编号
|
/// 路径
|
||||
/// </summary>
|
/// </summary>
|
||||
public virtual string Code { get; set; } |
public virtual string Path { get; set; } |
||||
/// <summary>
|
/// <summary>
|
||||
/// 名称
|
/// 名称
|
||||
/// </summary>
|
/// </summary>
|
||||
public virtual string Name { get; protected set; } |
public virtual string Name { get; set; } |
||||
/// <summary>
|
|
||||
/// 全名
|
|
||||
/// </summary>
|
|
||||
public virtual string FullName { get; set; } |
|
||||
/// <summary>
|
/// <summary>
|
||||
/// 显示名称
|
/// 显示名称
|
||||
/// </summary>
|
/// </summary>
|
||||
public virtual string DisplayName { get; protected set; } |
public virtual string DisplayName { get; set; } |
||||
/// <summary>
|
|
||||
/// 平台标识
|
|
||||
/// </summary>
|
|
||||
public virtual PlatformType PlatformType { get; set; } |
|
||||
/// <summary>
|
/// <summary>
|
||||
/// 说明
|
/// 说明
|
||||
/// </summary>
|
/// </summary>
|
||||
public virtual string Description { get; set; } |
public virtual string Description { get; set; } |
||||
/// <summary>
|
/// <summary>
|
||||
/// 图标
|
/// 重定向路径
|
||||
/// </summary>
|
|
||||
public virtual string Icon { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 路由地址
|
|
||||
/// </summary>
|
|
||||
public virtual string LinkUrl { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 是否菜单
|
|
||||
/// </summary>
|
|
||||
public virtual bool IsMenu { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 是否工具栏
|
|
||||
/// </summary>
|
|
||||
public virtual bool IsToolBar { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 是否侧边栏
|
|
||||
/// </summary>
|
|
||||
public virtual bool IsSideBar { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 是否公共路由
|
|
||||
/// </summary>
|
|
||||
public virtual bool IsPublic { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 是否内置
|
|
||||
/// </summary>
|
/// </summary>
|
||||
public virtual bool IsStatic { get; set; } |
public virtual string Redirect { get; set; } |
||||
/// <summary>
|
|
||||
/// 总是显示根菜单
|
|
||||
/// </summary>
|
|
||||
public virtual bool AlwaysShow { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 父级标识
|
|
||||
/// </summary>
|
|
||||
public virtual Guid? ParentId { get; set; } |
|
||||
protected Route() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public Route(Guid id, string name, string displayName, string url) |
|
||||
{ |
|
||||
Id = id; |
|
||||
LinkToUrl(url); |
|
||||
ChangeName(name, displayName); |
|
||||
} |
|
||||
|
|
||||
public void LinkToUrl([NotNull] string linkUrl) |
protected Route() { } |
||||
{ |
|
||||
LinkUrl = Check.NotNullOrWhiteSpace(linkUrl, nameof(linkUrl)); |
|
||||
} |
|
||||
|
|
||||
public void ChangeIcon(string icon) |
protected Route( |
||||
|
[NotNull] Guid id, |
||||
|
[NotNull] string path, |
||||
|
[NotNull] string name, |
||||
|
[NotNull] string displayName, |
||||
|
[CanBeNull] string redirect = "", |
||||
|
[CanBeNull] string description = "", |
||||
|
[CanBeNull] Guid? tenantId = null) |
||||
|
: base(id) |
||||
{ |
{ |
||||
Icon = icon; |
Check.NotNullOrWhiteSpace(path, nameof(path)); |
||||
} |
Check.NotNullOrWhiteSpace(name, nameof(name)); |
||||
|
Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); |
||||
|
|
||||
public void ChangeName([NotNull] string name, [CanBeNull] string displayName) |
Path = path; |
||||
{ |
Name = name; |
||||
Name = Check.NotNullOrWhiteSpace(name, nameof(name)); |
|
||||
DisplayName = displayName; |
DisplayName = displayName; |
||||
|
Redirect = redirect; |
||||
|
Description = description; |
||||
|
TenantId = tenantId; |
||||
} |
} |
||||
|
|
||||
public static string CreateCode(params int[] numbers) |
public override int GetHashCode() |
||||
{ |
{ |
||||
if (numbers.IsNullOrEmpty()) |
return Name.GetHashCode(); |
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return numbers.Select(number => number.ToString(new string('0', RouteConsts.CodeUnitLength))).JoinAsString("."); |
|
||||
} |
} |
||||
|
|
||||
public static string AppendCode(string parentCode, string childCode) |
public override bool Equals(object obj) |
||||
{ |
{ |
||||
if (childCode.IsNullOrEmpty()) |
if (obj == null) |
||||
{ |
{ |
||||
throw new ArgumentNullException(nameof(childCode), "childCode can not be null or empty."); |
return false; |
||||
} |
} |
||||
|
if (obj is Route route) |
||||
if (parentCode.IsNullOrEmpty()) |
|
||||
{ |
{ |
||||
return childCode; |
return route.Name.Equals(Name, StringComparison.InvariantCultureIgnoreCase); |
||||
} |
} |
||||
|
return base.Equals(obj); |
||||
return parentCode + "." + childCode; |
|
||||
} |
|
||||
|
|
||||
public static string GetRelativeCode(string code, string parentCode) |
|
||||
{ |
|
||||
if (code.IsNullOrEmpty()) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
|
||||
} |
|
||||
|
|
||||
if (parentCode.IsNullOrEmpty()) |
|
||||
{ |
|
||||
return code; |
|
||||
} |
|
||||
|
|
||||
if (code.Length == parentCode.Length) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return code.Substring(parentCode.Length + 1); |
|
||||
} |
|
||||
|
|
||||
public static string CalculateNextCode(string code) |
|
||||
{ |
|
||||
if (code.IsNullOrEmpty()) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
|
||||
} |
|
||||
|
|
||||
var parentCode = GetParentCode(code); |
|
||||
var lastUnitCode = GetLastUnitCode(code); |
|
||||
|
|
||||
return AppendCode(parentCode, CreateCode(Convert.ToInt32(lastUnitCode) + 1)); |
|
||||
} |
|
||||
|
|
||||
public static string GetLastUnitCode(string code) |
|
||||
{ |
|
||||
if (code.IsNullOrEmpty()) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
|
||||
} |
|
||||
|
|
||||
var splittedCode = code.Split('.'); |
|
||||
return splittedCode[splittedCode.Length - 1]; |
|
||||
} |
|
||||
|
|
||||
public static string GetParentCode(string code) |
|
||||
{ |
|
||||
if (code.IsNullOrEmpty()) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
|
||||
} |
|
||||
|
|
||||
var splittedCode = code.Split('.'); |
|
||||
if (splittedCode.Length == 1) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return splittedCode.Take(splittedCode.Length - 1).JoinAsString("."); |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,150 @@ |
|||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Guids; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Routes |
||||
|
{ |
||||
|
public class RouteDataSeeder : IRouteDataSeeder, ITransientDependency |
||||
|
{ |
||||
|
protected IGuidGenerator GuidGenerator { get; } |
||||
|
protected ILayoutRepository LayoutRepository { get; } |
||||
|
protected IMenuRepository MenuRepository { get; } |
||||
|
protected IUserMenuRepository UserMenuRepository { get; } |
||||
|
protected IRoleMenuRepository RoleMenuRepository { get; } |
||||
|
|
||||
|
public RouteDataSeeder( |
||||
|
IGuidGenerator guidGenerator, |
||||
|
IMenuRepository menuRepository, |
||||
|
ILayoutRepository layoutRepository, |
||||
|
IUserMenuRepository userMenuRepository, |
||||
|
IRoleMenuRepository roleMenuRepository) |
||||
|
{ |
||||
|
GuidGenerator = guidGenerator; |
||||
|
MenuRepository = menuRepository; |
||||
|
LayoutRepository = layoutRepository; |
||||
|
UserMenuRepository = userMenuRepository; |
||||
|
RoleMenuRepository = roleMenuRepository; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Layout> SeedLayoutAsync( |
||||
|
string name, |
||||
|
string path, |
||||
|
string displayName, |
||||
|
Guid dataId, |
||||
|
PlatformType platformType = PlatformType.None, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var layout = await LayoutRepository.FindByNameAsync(name, cancellationToken: cancellationToken); |
||||
|
if (layout == null) |
||||
|
{ |
||||
|
layout = new Layout( |
||||
|
GuidGenerator.Create(), |
||||
|
path, |
||||
|
name, |
||||
|
displayName, |
||||
|
dataId, |
||||
|
platformType, |
||||
|
redirect, |
||||
|
description, |
||||
|
tenantId); |
||||
|
layout = await LayoutRepository.InsertAsync(layout, cancellationToken: cancellationToken); |
||||
|
} |
||||
|
return layout; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Menu> SeedMenuAsync( |
||||
|
Layout layout, |
||||
|
string name, |
||||
|
string path, |
||||
|
string code, |
||||
|
string component, |
||||
|
string displayName, |
||||
|
string redirect = "", |
||||
|
string description = "", |
||||
|
Guid? parentId = null, |
||||
|
Guid? tenantId = null, |
||||
|
bool isPublic = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
if (parentId.HasValue) |
||||
|
{ |
||||
|
var children = await MenuRepository.GetChildrenAsync(parentId); |
||||
|
var childMenu = children.FirstOrDefault(x => x.Name == name); |
||||
|
if (childMenu != null) |
||||
|
{ |
||||
|
return childMenu; |
||||
|
} |
||||
|
} |
||||
|
var menu = await MenuRepository.FindByNameAsync(name, cancellationToken: cancellationToken); |
||||
|
if (menu == null) |
||||
|
{ |
||||
|
menu = new Menu( |
||||
|
GuidGenerator.Create(), |
||||
|
layout.Id, |
||||
|
path, |
||||
|
name, |
||||
|
code, |
||||
|
component, |
||||
|
displayName, |
||||
|
redirect, |
||||
|
description, |
||||
|
layout.PlatformType, |
||||
|
parentId, |
||||
|
tenantId) |
||||
|
{ |
||||
|
IsPublic = isPublic |
||||
|
}; |
||||
|
|
||||
|
menu = await MenuRepository.InsertAsync(menu, cancellationToken: cancellationToken); |
||||
|
} |
||||
|
|
||||
|
return menu; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SeedRoleMenuAsync( |
||||
|
string roleName, |
||||
|
Menu menu, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
if (! await RoleMenuRepository.RoleHasInMenuAsync(roleName, menu.Name, cancellationToken)) |
||||
|
{ |
||||
|
var roleMenu = new RoleMenu(menu.Id, roleName, tenantId); |
||||
|
await RoleMenuRepository.InsertAsync(roleMenu); |
||||
|
|
||||
|
var childrens = await MenuRepository.GetChildrenAsync(menu.Id); |
||||
|
foreach (var children in childrens) |
||||
|
{ |
||||
|
await SeedRoleMenuAsync(roleName, children, tenantId, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SeedUserMenuAsync( |
||||
|
Guid userId, |
||||
|
Menu menu, |
||||
|
Guid? tenantId = null, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
if (!await UserMenuRepository.UserHasInMenuAsync(userId, menu.Name, cancellationToken)) |
||||
|
{ |
||||
|
var userMenu = new UserMenu(menu.Id, userId, tenantId); |
||||
|
await UserMenuRepository.InsertAsync(userMenu); |
||||
|
|
||||
|
var childrens = await MenuRepository.GetChildrenAsync(menu.Id); |
||||
|
foreach (var children in childrens) |
||||
|
{ |
||||
|
await SeedUserMenuAsync(userId, children, tenantId, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,139 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.Domain.Services; |
|
||||
using Volo.Abp.Uow; |
|
||||
|
|
||||
namespace LINGYUN.Platform.Routes |
|
||||
{ |
|
||||
public class RouteManager : DomainService |
|
||||
{ |
|
||||
protected IRouteRepository RouteRepository { get; } |
|
||||
public RouteManager( |
|
||||
IRouteRepository routeRepository) |
|
||||
{ |
|
||||
RouteRepository = routeRepository; |
|
||||
} |
|
||||
|
|
||||
[UnitOfWork] |
|
||||
public virtual async Task CreateAsync(Route route) |
|
||||
{ |
|
||||
route.Code = await GetNextChildCodeAsync(route.ParentId); |
|
||||
await RouteRepository.InsertAsync(route); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task UpdateAsync(Route route) |
|
||||
{ |
|
||||
await RouteRepository.UpdateAsync(route); |
|
||||
} |
|
||||
|
|
||||
[UnitOfWork] |
|
||||
public virtual async Task DeleteAsync(Guid id) |
|
||||
{ |
|
||||
var children = await FindChildrenAsync(id, true); |
|
||||
|
|
||||
foreach (var child in children) |
|
||||
{ |
|
||||
await RouteRepository.RemoveAllUsersRouteAsync(child); |
|
||||
await RouteRepository.RemoveAllRolesRouteAsync(child); |
|
||||
await RouteRepository.DeleteAsync(child); |
|
||||
} |
|
||||
|
|
||||
var organizationUnit = await RouteRepository.GetAsync(id); |
|
||||
|
|
||||
await RouteRepository.RemoveAllUsersRouteAsync(organizationUnit); |
|
||||
await RouteRepository.RemoveAllRolesRouteAsync(organizationUnit); |
|
||||
await RouteRepository.DeleteAsync(id); |
|
||||
} |
|
||||
|
|
||||
[UnitOfWork] |
|
||||
public virtual async Task MoveAsync(Guid id, Guid? parentId) |
|
||||
{ |
|
||||
var route = await RouteRepository.GetAsync(id); |
|
||||
if (route.ParentId == parentId) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var children = await FindChildrenAsync(id, true); |
|
||||
|
|
||||
var oldCode = route.Code; |
|
||||
|
|
||||
route.Code = await GetNextChildCodeAsync(parentId); |
|
||||
route.ParentId = parentId; |
|
||||
|
|
||||
foreach (var child in children) |
|
||||
{ |
|
||||
child.Code = Route.AppendCode(route.Code, Route.GetRelativeCode(child.Code, oldCode)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public virtual async Task RemoveRoleFromRouteAsync(string roleName, Route route) |
|
||||
{ |
|
||||
await RouteRepository.RemoveRoleRouteAsync(roleName, route); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task RemoveUserFromRouteAsync(Guid userId, Route route) |
|
||||
{ |
|
||||
await RouteRepository.RemoveUserRouteAsync(userId, route); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<string> GetNextChildCodeAsync(Guid? parentId) |
|
||||
{ |
|
||||
var lastChild = await GetLastChildOrNullAsync(parentId); |
|
||||
if (lastChild != null) |
|
||||
{ |
|
||||
return Route.CalculateNextCode(lastChild.Code); |
|
||||
} |
|
||||
|
|
||||
var parentCode = parentId != null |
|
||||
? await GetCodeOrDefaultAsync(parentId.Value) |
|
||||
: null; |
|
||||
|
|
||||
return Route.AppendCode( |
|
||||
parentCode, |
|
||||
Route.CreateCode(1) |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<Route> GetLastChildOrNullAsync(Guid? parentId) |
|
||||
{ |
|
||||
var children = await RouteRepository.GetChildrenAsync(parentId); |
|
||||
return children.OrderBy(c => c.Code).LastOrDefault(); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<string> GetCodeOrDefaultAsync(Guid id) |
|
||||
{ |
|
||||
var ou = await RouteRepository.GetAsync(id); |
|
||||
return ou?.Code; |
|
||||
} |
|
||||
|
|
||||
public async Task<List<Route>> FindChildrenAsync(Guid? parentId, bool recursive = false) |
|
||||
{ |
|
||||
if (!recursive) |
|
||||
{ |
|
||||
return await RouteRepository.GetChildrenAsync(parentId); |
|
||||
} |
|
||||
|
|
||||
if (!parentId.HasValue) |
|
||||
{ |
|
||||
return await RouteRepository.GetListAsync(); |
|
||||
} |
|
||||
|
|
||||
var code = await GetCodeOrDefaultAsync(parentId.Value); |
|
||||
|
|
||||
return await RouteRepository.GetAllChildrenWithParentCodeAsync(code, parentId); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<bool> IsInRouteAsync(Guid userId, Route route) |
|
||||
{ |
|
||||
return await RouteRepository.IsInRouteAsync(userId, route); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<bool> IsInRouteAsync(string roleName, Route route) |
|
||||
{ |
|
||||
return await RouteRepository.IsInRouteAsync(roleName, route); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
using System; |
|
||||
using Volo.Abp.Domain.Entities.Auditing; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Platform.Routes |
|
||||
{ |
|
||||
public class UserRoute : FullAuditedEntity<int>, IMultiTenant |
|
||||
{ |
|
||||
public virtual Guid? TenantId { get; protected set; } |
|
||||
public virtual Guid UserId { get; protected set; } |
|
||||
public virtual Guid RouteId { get; protected set; } |
|
||||
protected UserRoute() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public UserRoute(int id) |
|
||||
{ |
|
||||
Id = id; |
|
||||
} |
|
||||
|
|
||||
public UserRoute(Guid routeId, Guid userId, Guid? tenantId = null) |
|
||||
{ |
|
||||
UserId = userId; |
|
||||
RouteId = routeId; |
|
||||
TenantId = tenantId; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,94 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Utils |
||||
|
{ |
||||
|
public static class CodeNumberGenerator |
||||
|
{ |
||||
|
public static string CreateCode(params int[] numbers) |
||||
|
{ |
||||
|
if (numbers.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return numbers.Select(number => number.ToString(new string(PlatformConsts.CodePrefix, PlatformConsts.CodeUnitLength))).JoinAsString("."); |
||||
|
} |
||||
|
|
||||
|
public static string AppendCode(string parentCode, string childCode) |
||||
|
{ |
||||
|
if (childCode.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(childCode), "childCode can not be null or empty."); |
||||
|
} |
||||
|
|
||||
|
if (parentCode.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return childCode; |
||||
|
} |
||||
|
|
||||
|
return parentCode + "." + childCode; |
||||
|
} |
||||
|
|
||||
|
public static string GetRelativeCode(string code, string parentCode) |
||||
|
{ |
||||
|
if (code.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
||||
|
} |
||||
|
|
||||
|
if (parentCode.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
if (code.Length == parentCode.Length) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return code.Substring(parentCode.Length + 1); |
||||
|
} |
||||
|
|
||||
|
public static string CalculateNextCode(string code) |
||||
|
{ |
||||
|
if (code.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
||||
|
} |
||||
|
|
||||
|
var parentCode = GetParentCode(code); |
||||
|
var lastUnitCode = GetLastCode(code); |
||||
|
|
||||
|
return AppendCode(parentCode, CreateCode(Convert.ToInt32(lastUnitCode) + 1)); |
||||
|
} |
||||
|
|
||||
|
public static string GetLastCode(string code) |
||||
|
{ |
||||
|
if (code.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
||||
|
} |
||||
|
|
||||
|
var splittedCode = code.Split('.'); |
||||
|
return splittedCode[splittedCode.Length - 1]; |
||||
|
} |
||||
|
|
||||
|
public static string GetParentCode(string code) |
||||
|
{ |
||||
|
if (code.IsNullOrEmpty()) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(code), "code can not be null or empty."); |
||||
|
} |
||||
|
|
||||
|
var splittedCode = code.Split('.'); |
||||
|
if (splittedCode.Length == 1) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return splittedCode.Take(splittedCode.Length - 1).JoinAsString("."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using LINGYUN.Platform.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Dynamic.Core; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Datas |
||||
|
{ |
||||
|
public class EfCoreDataRepository : EfCoreRepository<PlatformDbContext, Data, Guid>, IDataRepository |
||||
|
{ |
||||
|
public EfCoreDataRepository( |
||||
|
IDbContextProvider<PlatformDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Data> FindByNameAsync( |
||||
|
string name, |
||||
|
bool includeDetails = true, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.IncludeDetails(includeDetails) |
||||
|
.Where(x => x.Name == name) |
||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<Data>> GetChildrenAsync( |
||||
|
Guid? parentId, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.IncludeDetails(includeDetails) |
||||
|
.Where(x => x.ParentId == parentId) |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<int> GetCountAsync( |
||||
|
string filter = "", |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.WhereIf(!filter.IsNullOrWhiteSpace(), x => |
||||
|
x.Code.Contains(filter) || x.Description.Contains(filter) || |
||||
|
x.DisplayName.Contains(filter) || x.Name.Contains(filter)) |
||||
|
.CountAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<Data>> GetPagedListAsync( |
||||
|
string filter = "", |
||||
|
string sotring = "Code", |
||||
|
bool includeDetails = false, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
sotring ??= nameof(Data.Code); |
||||
|
|
||||
|
return await DbSet |
||||
|
.IncludeDetails(includeDetails) |
||||
|
.WhereIf(!filter.IsNullOrWhiteSpace(), x => |
||||
|
x.Code.Contains(filter) || x.Description.Contains(filter) || |
||||
|
x.DisplayName.Contains(filter) || x.Name.Contains(filter)) |
||||
|
.OrderBy(sotring) |
||||
|
.PageBy(skipCount, maxResultCount) |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public override IQueryable<Data> WithDetails() |
||||
|
{ |
||||
|
return GetQueryable().IncludeDetails(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,143 +0,0 @@ |
|||||
using LINGYUN.Platform.Routes; |
|
||||
using LINGYUN.Platform.Versions; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
using System; |
|
||||
using Volo.Abp; |
|
||||
using Volo.Abp.EntityFrameworkCore.Modeling; |
|
||||
|
|
||||
namespace LINGYUN.Platform.EntityFrameworkCore |
|
||||
{ |
|
||||
public static class AppPlatformDbContextModelBuilderExtensions |
|
||||
{ |
|
||||
public static void ConfigurePlatform( |
|
||||
this ModelBuilder builder, |
|
||||
Action<AppPlatformModelBuilderConfigurationOptions> optionsAction = null) |
|
||||
{ |
|
||||
Check.NotNull(builder, nameof(builder)); |
|
||||
|
|
||||
var options = new AppPlatformModelBuilderConfigurationOptions( |
|
||||
AppPlatformDbProperties.DbTablePrefix, |
|
||||
AppPlatformDbProperties.DbSchema |
|
||||
); |
|
||||
|
|
||||
optionsAction?.Invoke(options); |
|
||||
|
|
||||
builder.Entity<Route>(x => |
|
||||
{ |
|
||||
x.ToTable(options.TablePrefix + "Route"); |
|
||||
|
|
||||
x.Property(p => p.Code) |
|
||||
.IsRequired() |
|
||||
.HasMaxLength(RouteConsts.MaxCodeLength) |
|
||||
.HasColumnName(nameof(Route.Code)); |
|
||||
x.Property(p => p.DisplayName) |
|
||||
.IsRequired() |
|
||||
.HasMaxLength(RouteConsts.MaxDisplayNameLength) |
|
||||
.HasColumnName(nameof(Route.DisplayName)); |
|
||||
x.Property(p => p.LinkUrl) |
|
||||
.IsRequired() |
|
||||
.HasMaxLength(RouteConsts.MaxLinkUrlLength) |
|
||||
.HasColumnName(nameof(Route.LinkUrl)); |
|
||||
x.Property(p => p.Name) |
|
||||
.IsRequired() |
|
||||
.HasMaxLength(RouteConsts.MaxNameLength) |
|
||||
.HasColumnName(nameof(Route.Name)); |
|
||||
|
|
||||
x.Property(p => p.Icon) |
|
||||
.HasMaxLength(RouteConsts.MaxIconLength) |
|
||||
.HasColumnName(nameof(Route.Icon)); |
|
||||
x.Property(p => p.FullName) |
|
||||
.HasMaxLength(RouteConsts.MaxFullNameLength) |
|
||||
.HasColumnName(nameof(Route.FullName)); |
|
||||
x.Property(p => p.Description) |
|
||||
.HasMaxLength(RouteConsts.MaxDescriptionLength) |
|
||||
.HasColumnName(nameof(Route.Description)); |
|
||||
|
|
||||
x.ConfigureByConvention(); |
|
||||
|
|
||||
x.HasMany<Route>().WithOne().HasForeignKey(p => p.ParentId); |
|
||||
|
|
||||
x.HasIndex(i => i.Code); |
|
||||
}); |
|
||||
|
|
||||
builder.Entity<RoleRoute>(x => |
|
||||
{ |
|
||||
x.ToTable(options.TablePrefix + "RoleRoute"); |
|
||||
|
|
||||
x.Property(p => p.RoleName) |
|
||||
.IsRequired() |
|
||||
.HasMaxLength(RoleRouteConsts.MaxRoleNameLength) |
|
||||
.HasColumnName(nameof(RoleRoute.RoleName)); |
|
||||
|
|
||||
x.ConfigureMultiTenant(); |
|
||||
|
|
||||
x.HasIndex(i => new { i.RoleName, i.RouteId }); |
|
||||
}); |
|
||||
|
|
||||
builder.Entity<UserRoute>(x => |
|
||||
{ |
|
||||
x.ToTable(options.TablePrefix + "UserRoute"); |
|
||||
|
|
||||
x.ConfigureMultiTenant(); |
|
||||
|
|
||||
x.HasIndex(i => new { i.UserId, i.RouteId }); |
|
||||
}); |
|
||||
|
|
||||
builder.Entity<AppVersion>(x => |
|
||||
{ |
|
||||
x.ToTable(options.TablePrefix + "Version", options.Schema); |
|
||||
|
|
||||
x.Property(p => p.Title) |
|
||||
.IsRequired() |
|
||||
.HasColumnName(nameof(AppVersion.Title)) |
|
||||
.HasMaxLength(AppVersionConsts.MaxTitleLength); |
|
||||
x.Property(p => p.Version) |
|
||||
.IsRequired() |
|
||||
.HasColumnName(nameof(AppVersion.Version)) |
|
||||
.HasMaxLength(AppVersionConsts.MaxVersionLength); |
|
||||
|
|
||||
x.Property(p => p.Description) |
|
||||
.HasColumnName(nameof(AppVersion.Description)) |
|
||||
.HasMaxLength(AppVersionConsts.MaxDescriptionLength); |
|
||||
|
|
||||
x.ConfigureByConvention(); |
|
||||
|
|
||||
x.HasIndex(i => i.Version); |
|
||||
|
|
||||
x.HasMany(p => p.Files) |
|
||||
.WithOne(q => q.AppVersion) |
|
||||
.HasPrincipalKey(pk => pk.Id) |
|
||||
.HasForeignKey(fk => fk.AppVersionId) |
|
||||
.OnDelete(DeleteBehavior.Cascade); |
|
||||
}); |
|
||||
|
|
||||
builder.Entity<VersionFile>(x => |
|
||||
{ |
|
||||
x.ToTable(options.TablePrefix + "VersionFile", options.Schema); |
|
||||
|
|
||||
x.Property(p => p.Name) |
|
||||
.IsRequired() |
|
||||
.HasColumnName(nameof(VersionFile.Name)) |
|
||||
.HasMaxLength(VersionFileConsts.MaxNameLength); |
|
||||
x.Property(p => p.SHA256) |
|
||||
.IsRequired() |
|
||||
.HasColumnName(nameof(VersionFile.SHA256)) |
|
||||
.HasMaxLength(VersionFileConsts.MaxSHA256Length); |
|
||||
x.Property(p => p.Version) |
|
||||
.IsRequired() |
|
||||
.HasColumnName(nameof(VersionFile.Version)) |
|
||||
.HasMaxLength(VersionFileConsts.MaxVersionLength); |
|
||||
|
|
||||
x.Property(p => p.Path) |
|
||||
.HasColumnName(nameof(VersionFile.Path)) |
|
||||
.HasMaxLength(VersionFileConsts.MaxPathLength); |
|
||||
|
|
||||
x.ConfigureAudited(); |
|
||||
x.ConfigureMultiTenant(); |
|
||||
|
|
||||
x.HasIndex(i => new { i.Path, i.Name, i.Version }).IsUnique(); |
|
||||
|
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,249 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using LINGYUN.Platform.Routes; |
||||
|
using LINGYUN.Platform.Versions; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
|
|
||||
|
namespace LINGYUN.Platform.EntityFrameworkCore |
||||
|
{ |
||||
|
public static class PlatformDbContextModelBuilderExtensions |
||||
|
{ |
||||
|
public static void ConfigurePlatform( |
||||
|
this ModelBuilder builder, |
||||
|
Action<PlatformModelBuilderConfigurationOptions> optionsAction = null) |
||||
|
{ |
||||
|
Check.NotNull(builder, nameof(builder)); |
||||
|
|
||||
|
var options = new PlatformModelBuilderConfigurationOptions( |
||||
|
PlatformDbProperties.DbTablePrefix, |
||||
|
PlatformDbProperties.DbSchema |
||||
|
); |
||||
|
|
||||
|
optionsAction?.Invoke(options); |
||||
|
|
||||
|
builder.Entity<Layout>(b => |
||||
|
{ |
||||
|
b.ToTable(options.TablePrefix + "Layouts", options.Schema); |
||||
|
|
||||
|
b.ConfigureRoute(); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<Menu>(b => |
||||
|
{ |
||||
|
b.ToTable(options.TablePrefix + "Menus", options.Schema); |
||||
|
|
||||
|
b.ConfigureRoute(); |
||||
|
|
||||
|
b.Property(p => p.Component) |
||||
|
.HasMaxLength(MenuConsts.MaxComponentLength) |
||||
|
.HasColumnName(nameof(Menu.Component)) |
||||
|
.IsRequired(); |
||||
|
b.Property(p => p.Code) |
||||
|
.HasMaxLength(MenuConsts.MaxCodeLength) |
||||
|
.HasColumnName(nameof(Menu.Code)) |
||||
|
.IsRequired(); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<RoleMenu>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "RoleMenus"); |
||||
|
|
||||
|
x.Property(p => p.RoleName) |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(RoleRouteConsts.MaxRoleNameLength) |
||||
|
.HasColumnName(nameof(RoleMenu.RoleName)); |
||||
|
|
||||
|
x.ConfigureByConvention(); |
||||
|
|
||||
|
x.HasIndex(i => new { i.RoleName, i.MenuId }); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<UserMenu>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "UserMenus"); |
||||
|
|
||||
|
x.ConfigureByConvention(); |
||||
|
|
||||
|
x.HasIndex(i => new { i.UserId, i.MenuId }); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<Data>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "Datas"); |
||||
|
|
||||
|
x.Property(p => p.Code) |
||||
|
.HasMaxLength(DataConsts.MaxCodeLength) |
||||
|
.HasColumnName(nameof(Data.Code)) |
||||
|
.IsRequired(); |
||||
|
x.Property(p => p.Name) |
||||
|
.HasMaxLength(DataConsts.MaxNameLength) |
||||
|
.HasColumnName(nameof(Data.Name)) |
||||
|
.IsRequired(); |
||||
|
x.Property(p => p.DisplayName) |
||||
|
.HasMaxLength(DataConsts.MaxDisplayNameLength) |
||||
|
.HasColumnName(nameof(Data.DisplayName)) |
||||
|
.IsRequired(); |
||||
|
x.Property(p => p.Description) |
||||
|
.HasMaxLength(DataConsts.MaxDescriptionLength) |
||||
|
.HasColumnName(nameof(Data.Description)); |
||||
|
|
||||
|
x.ConfigureByConvention(); |
||||
|
|
||||
|
x.HasMany(p => p.Items) |
||||
|
.WithOne() |
||||
|
.HasForeignKey(fk => fk.DataId) |
||||
|
.IsRequired(); |
||||
|
|
||||
|
x.HasIndex(i => new { i.Name }); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<DataItem>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "DataItems"); |
||||
|
|
||||
|
x.Property(p => p.DefaultValue) |
||||
|
.HasMaxLength(DataItemConsts.MaxValueLength) |
||||
|
.HasColumnName(nameof(DataItem.DefaultValue)); |
||||
|
x.Property(p => p.Name) |
||||
|
.HasMaxLength(DataItemConsts.MaxNameLength) |
||||
|
.HasColumnName(nameof(DataItem.Name)) |
||||
|
.IsRequired(); |
||||
|
x.Property(p => p.DisplayName) |
||||
|
.HasMaxLength(DataItemConsts.MaxDisplayNameLength) |
||||
|
.HasColumnName(nameof(DataItem.DisplayName)) |
||||
|
.IsRequired(); |
||||
|
x.Property(p => p.Description) |
||||
|
.HasMaxLength(DataItemConsts.MaxDescriptionLength) |
||||
|
.HasColumnName(nameof(DataItem.Description)); |
||||
|
|
||||
|
x.Property(p => p.AllowBeNull).HasDefaultValue(true); |
||||
|
|
||||
|
x.ConfigureByConvention(); |
||||
|
|
||||
|
x.HasIndex(i => new { i.Name }); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
builder.Entity<AppVersion>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "Version", options.Schema); |
||||
|
|
||||
|
x.Property(p => p.Title) |
||||
|
.IsRequired() |
||||
|
.HasColumnName(nameof(AppVersion.Title)) |
||||
|
.HasMaxLength(AppVersionConsts.MaxTitleLength); |
||||
|
x.Property(p => p.Version) |
||||
|
.IsRequired() |
||||
|
.HasColumnName(nameof(AppVersion.Version)) |
||||
|
.HasMaxLength(AppVersionConsts.MaxVersionLength); |
||||
|
|
||||
|
x.Property(p => p.Description) |
||||
|
.HasColumnName(nameof(AppVersion.Description)) |
||||
|
.HasMaxLength(AppVersionConsts.MaxDescriptionLength); |
||||
|
|
||||
|
x.ConfigureByConvention(); |
||||
|
|
||||
|
x.HasIndex(i => i.Version); |
||||
|
|
||||
|
x.HasMany(p => p.Files) |
||||
|
.WithOne(q => q.AppVersion) |
||||
|
.HasPrincipalKey(pk => pk.Id) |
||||
|
.HasForeignKey(fk => fk.AppVersionId) |
||||
|
.OnDelete(DeleteBehavior.Cascade); |
||||
|
}); |
||||
|
|
||||
|
builder.Entity<VersionFile>(x => |
||||
|
{ |
||||
|
x.ToTable(options.TablePrefix + "VersionFile", options.Schema); |
||||
|
|
||||
|
x.Property(p => p.Name) |
||||
|
.IsRequired() |
||||
|
.HasColumnName(nameof(VersionFile.Name)) |
||||
|
.HasMaxLength(VersionFileConsts.MaxNameLength); |
||||
|
x.Property(p => p.SHA256) |
||||
|
.IsRequired() |
||||
|
.HasColumnName(nameof(VersionFile.SHA256)) |
||||
|
.HasMaxLength(VersionFileConsts.MaxSHA256Length); |
||||
|
x.Property(p => p.Version) |
||||
|
.IsRequired() |
||||
|
.HasColumnName(nameof(VersionFile.Version)) |
||||
|
.HasMaxLength(VersionFileConsts.MaxVersionLength); |
||||
|
|
||||
|
x.Property(p => p.Path) |
||||
|
.HasColumnName(nameof(VersionFile.Path)) |
||||
|
.HasMaxLength(VersionFileConsts.MaxPathLength); |
||||
|
|
||||
|
x.ConfigureAudited(); |
||||
|
x.ConfigureMultiTenant(); |
||||
|
|
||||
|
x.HasIndex(i => new { i.Path, i.Name, i.Version }).IsUnique(); |
||||
|
|
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static EntityTypeBuilder<TRoute> ConfigureRoute<TRoute>( |
||||
|
this EntityTypeBuilder<TRoute> builder) |
||||
|
where TRoute : Route |
||||
|
{ |
||||
|
builder |
||||
|
.Property(p => p.DisplayName) |
||||
|
.HasMaxLength(RouteConsts.MaxDisplayNameLength) |
||||
|
.HasColumnName(nameof(Route.DisplayName)) |
||||
|
.IsRequired(); |
||||
|
builder |
||||
|
.Property(p => p.Name) |
||||
|
.HasMaxLength(RouteConsts.MaxNameLength) |
||||
|
.HasColumnName(nameof(Route.Name)) |
||||
|
.IsRequired(); |
||||
|
builder |
||||
|
.Property(p => p.Path) |
||||
|
.HasMaxLength(RouteConsts.MaxPathLength) |
||||
|
.HasColumnName(nameof(Route.Path)); |
||||
|
builder |
||||
|
.Property(p => p.Redirect) |
||||
|
.HasMaxLength(RouteConsts.MaxRedirectLength) |
||||
|
.HasColumnName(nameof(Route.Redirect)); |
||||
|
|
||||
|
builder.ConfigureByConvention(); |
||||
|
|
||||
|
return builder; |
||||
|
} |
||||
|
|
||||
|
public static OwnedNavigationBuilder<TEntity, TRoute> ConfigureRoute<TEntity, TRoute>( |
||||
|
[NotNull] this OwnedNavigationBuilder<TEntity, TRoute> builder, |
||||
|
[CanBeNull] string tablePrefix = "", |
||||
|
[CanBeNull] string schema = null) |
||||
|
where TEntity : class |
||||
|
where TRoute : Route |
||||
|
{ |
||||
|
builder.ToTable(tablePrefix + "Routes", schema); |
||||
|
|
||||
|
builder |
||||
|
.Property(p => p.DisplayName) |
||||
|
.HasMaxLength(RouteConsts.MaxDisplayNameLength) |
||||
|
.HasColumnName(nameof(Route.DisplayName)) |
||||
|
.IsRequired(); |
||||
|
builder |
||||
|
.Property(p => p.Name) |
||||
|
.HasMaxLength(RouteConsts.MaxNameLength) |
||||
|
.HasColumnName(nameof(Route.Name)) |
||||
|
.IsRequired(); |
||||
|
builder |
||||
|
.Property(p => p.Path) |
||||
|
.HasMaxLength(RouteConsts.MaxPathLength) |
||||
|
.HasColumnName(nameof(Route.Path)); |
||||
|
builder |
||||
|
.Property(p => p.Redirect) |
||||
|
.HasMaxLength(RouteConsts.MaxRedirectLength) |
||||
|
.HasColumnName(nameof(Route.Redirect)); |
||||
|
|
||||
|
return builder; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using LINGYUN.Platform.Datas; |
||||
|
using LINGYUN.Platform.Layouts; |
||||
|
using LINGYUN.Platform.Menus; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace LINGYUN.Platform.EntityFrameworkCore |
||||
|
{ |
||||
|
public static class PlatformEfCoreQueryableExtensions |
||||
|
{ |
||||
|
|
||||
|
public static IQueryable<Layout> IncludeDetails(this IQueryable<Layout> queryable, bool include = true) |
||||
|
{ |
||||
|
if (!include) |
||||
|
{ |
||||
|
return queryable; |
||||
|
} |
||||
|
|
||||
|
return queryable; |
||||
|
} |
||||
|
|
||||
|
public static IQueryable<Data> IncludeDetails(this IQueryable<Data> queryable, bool include = true) |
||||
|
{ |
||||
|
if (!include) |
||||
|
{ |
||||
|
return queryable; |
||||
|
} |
||||
|
|
||||
|
return queryable |
||||
|
//.AsSplitQuery()
|
||||
|
.Include(x => x.Items); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs
4
aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/AppPlatformModelBuilderConfigurationOptions.cs → aspnet-core/modules/platform/LINGYUN.Platform.EntityFrameworkCore/LINGYUN/Platform/EntityFrameworkCore/PlatformModelBuilderConfigurationOptions.cs
@ -0,0 +1,74 @@ |
|||||
|
using LINGYUN.Platform.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Dynamic.Core; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Platform.Layouts |
||||
|
{ |
||||
|
public class EfCoreLayoutRepository : EfCoreRepository<PlatformDbContext, Layout, Guid>, ILayoutRepository |
||||
|
{ |
||||
|
public EfCoreLayoutRepository(IDbContextProvider<PlatformDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<Layout> FindByNameAsync( |
||||
|
string name, |
||||
|
bool includeDetails = false, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.IncludeDetails(includeDetails) |
||||
|
.Where(x => x.Name == name) |
||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<int> GetCountAsync( |
||||
|
PlatformType? platformType = null, |
||||
|
string filter = "", |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbSet |
||||
|
.WhereIf(platformType.HasValue, x => x.PlatformType == platformType.Value) |
||||
|
.WhereIf(!filter.IsNullOrWhiteSpace(), x => |
||||
|
x.Name.Contains(filter) || x.DisplayName.Contains(filter) || |
||||
|
x.Description.Contains(filter) || x.Redirect.Contains(filter)) |
||||
|
.CountAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<Layout>> GetPagedListAsync( |
||||
|
PlatformType? platformType = null, |
||||
|
string filter = "", |
||||
|
string sorting = nameof(Layout.Name), |
||||
|
bool reverse = false, |
||||
|
bool includeDetails = false, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
sorting ??= nameof(Layout.Name); |
||||
|
sorting = reverse ? sorting + " DESC" : sorting; |
||||
|
|
||||
|
return await DbSet |
||||
|
.IncludeDetails(includeDetails) |
||||
|
.WhereIf(platformType.HasValue, x => x.PlatformType == platformType.Value) |
||||
|
.WhereIf(!filter.IsNullOrWhiteSpace(), x => |
||||
|
x.Name.Contains(filter) || x.DisplayName.Contains(filter) || |
||||
|
x.Description.Contains(filter) || x.Redirect.Contains(filter)) |
||||
|
.OrderBy(sorting) |
||||
|
.PageBy(skipCount, maxResultCount) |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public override IQueryable<Layout> WithDetails() |
||||
|
{ |
||||
|
return GetQueryable().IncludeDetails(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue