feat: 合并
This commit is contained in:
@@ -107,13 +107,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManageme
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{4FFE7212-21F2-476D-B628-3C65E6C5075E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.Codegen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.CodeGen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.Codegen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.CodeGen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.Codegen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.Codegen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.CodeGen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.FreeRedis", "framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj", "{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.CodeGen.SqlSugarCore", "module\code-gen\Yi.Framework.CodeGen.SqlSugarCore\Yi.Framework.CodeGen.SqlSugarCore.csproj", "{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -289,6 +293,14 @@ Global
|
||||
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -341,6 +353,8 @@ Global
|
||||
{882BC563-2F75-4B95-AC96-F4BF23F5E69D} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||
{85CB8517-2B80-42D8-B954-081079AC9BA0} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||
{EEFF0F05-2709-4151-A8CE-667935CEAE0B} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FreeRedis;
|
||||
|
||||
namespace Yi.Framework.Caching.FreeRedis
|
||||
{
|
||||
/// <summary>
|
||||
/// 便于转到定义
|
||||
/// </summary>
|
||||
public class FreeSqlOptions: ConnectionStringBuilder
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FreeRedis" Version="1.2.13" />
|
||||
<PackageReference Include="FreeRedis.DistributedCache" Version="1.2.5" />
|
||||
<PackageReference Include="Volo.Abp.Caching" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Yi.Framework.Caching.FreeRedis
|
||||
{
|
||||
[Dependency(ReplaceServices =true)]
|
||||
public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency
|
||||
{
|
||||
protected ICurrentTenant CurrentTenant { get; }
|
||||
|
||||
protected AbpDistributedCacheOptions DistributedCacheOptions { get; }
|
||||
|
||||
public YiDistributedCacheKeyNormalizer(
|
||||
ICurrentTenant currentTenant,
|
||||
IOptions<AbpDistributedCacheOptions> distributedCacheOptions)
|
||||
{
|
||||
CurrentTenant = currentTenant;
|
||||
DistributedCacheOptions = distributedCacheOptions.Value;
|
||||
}
|
||||
|
||||
public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args)
|
||||
{
|
||||
var normalizedKey = $"{DistributedCacheOptions.KeyPrefix}{args.Key}";
|
||||
|
||||
//if (!args.IgnoreMultiTenancy && CurrentTenant.Id.HasValue)
|
||||
//{
|
||||
// normalizedKey = $"t:{CurrentTenant.Id.Value},{normalizedKey}";
|
||||
//}
|
||||
|
||||
return normalizedKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using FreeRedis;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Volo.Abp.Caching;
|
||||
|
||||
namespace Yi.Framework.Caching.FreeRedis
|
||||
{
|
||||
/// <summary>
|
||||
/// 此模块得益于FreeRedis作者支持IDistributedCache,使用湿滑
|
||||
/// </summary>
|
||||
[DependsOn(typeof(AbpCachingModule))]
|
||||
public class YiFrameworkCachingFreeRedisModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
|
||||
var configuration = context.Services.GetConfiguration();
|
||||
|
||||
var redisEnabled = configuration["Redis:IsEnabled"];
|
||||
if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled))
|
||||
{
|
||||
var redisConfiguration = configuration["Redis:Configuration"];
|
||||
RedisClient redisClient = new RedisClient(redisConfiguration);
|
||||
|
||||
context.Services.AddSingleton<IRedisClient>(redisClient);
|
||||
context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache>(new
|
||||
DistributedCache(redisClient)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ namespace Yi.Framework.SqlSugarCore
|
||||
{
|
||||
options.ConnectionString = currentConnection;
|
||||
}));
|
||||
connectionCreator.SetDbAop(SqlSugarClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -242,6 +243,11 @@ namespace Yi.Framework.SqlSugarCore
|
||||
/// <param name="pars"></param>
|
||||
protected virtual void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||
{
|
||||
if (Options.EnabledSqlLog)
|
||||
{
|
||||
var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
|
||||
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -251,7 +257,14 @@ namespace Yi.Framework.SqlSugarCore
|
||||
/// <param name="column"></param>
|
||||
protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column)
|
||||
{
|
||||
|
||||
if (property.PropertyType == typeof(ExtraPropertyDictionary))
|
||||
{
|
||||
column.IsIgnore = true;
|
||||
}
|
||||
if (property.Name == nameof(Entity<object>.Id))
|
||||
{
|
||||
column.IsPrimarykey = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void BackupDataBase()
|
||||
|
||||
@@ -6,9 +6,11 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.EventBus.Local;
|
||||
using Volo.Abp.Users;
|
||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Integral;
|
||||
using Yi.Framework.Bbs.Domain.Managers;
|
||||
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||
using Yi.Framework.Rbac.Domain.Authorization;
|
||||
|
||||
namespace Yi.Framework.Bbs.Application.Services.Integral
|
||||
@@ -17,10 +19,12 @@ namespace Yi.Framework.Bbs.Application.Services.Integral
|
||||
{
|
||||
private IntegralManager _integralManager;
|
||||
private ICurrentUser _currentUser;
|
||||
public IntegralService(IntegralManager integralManager, ICurrentUser currentUser)
|
||||
private ILocalEventBus _localEventBus;
|
||||
public IntegralService(IntegralManager integralManager, ICurrentUser currentUser, ILocalEventBus localEventBus)
|
||||
{
|
||||
_integralManager = integralManager;
|
||||
_currentUser = currentUser;
|
||||
_localEventBus = localEventBus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Yi.Framework.Bbs.Domain.Shared.Consts
|
||||
{
|
||||
public class LevelConst
|
||||
{
|
||||
public const string LevelCacheKey=nameof(LevelCacheKey);
|
||||
public const string LevelCacheKey="Level:All";
|
||||
|
||||
public const string Level_Low_Zero = "经验提升等级低于或等于0";
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace Yi.Framework.CodeGen.Domain.Shared.Enums
|
||||
|
||||
[Display(Name = "DateTime", Description = "DateTime")]
|
||||
DateTime,
|
||||
|
||||
[Display(Name = "Guid", Description = "Guid")]
|
||||
Guid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Data;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
|
||||
namespace Yi.Framework.CodeGen.Domain.Entities
|
||||
@@ -24,5 +25,8 @@ namespace Yi.Framework.CodeGen.Domain.Entities
|
||||
/// </summary>
|
||||
[Navigate(NavigateType.OneToMany, nameof(FieldEntity.TableId))]
|
||||
public List<FieldEntity> Fields { get; set; }
|
||||
|
||||
[SugarColumn(IsIgnore =true)]
|
||||
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
using Volo.Abp.Data;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Guids;
|
||||
using Yi.Framework.CodeGen.Domain.Entities;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.CodeGen.SqlSugarCore
|
||||
{
|
||||
public class TemplateDataSeed : IDataSeedContributor, ITransientDependency
|
||||
{
|
||||
private ISqlSugarRepository<TemplateEntity> _repository;
|
||||
public TemplateDataSeed(ISqlSugarRepository<TemplateEntity> repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
public async Task SeedAsync(DataSeedContext context)
|
||||
{
|
||||
if (!await _repository.IsAnyAsync(x => true))
|
||||
{
|
||||
await _repository.InsertManyAsync(GetSeedData());
|
||||
}
|
||||
}
|
||||
public List<TemplateEntity> GetSeedData()
|
||||
{
|
||||
var entities = new List<TemplateEntity>();
|
||||
TemplateEntity entityTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "Entity",
|
||||
BuildPath = "D:\\code\\Entities\\@ModelEntity.cs",
|
||||
Remarks = "实体",
|
||||
TemplateStr = "using SqlSugar;\r\nusing lo.Abp;\r\nusing lo.Abp.Auditing;\r\nusing lo.Abp.Domain.Entities;\r\nusing Yi.Framework.Core.Data;\r\n\r\nnamespace Yi.Framework.Rbac.Domain.Entities\r\n{\r\n /// <summary>\r\n /// 实体\r\n /// </summary>\r\n [SugarTable(\"@Model\")]\r\n public class @ModelEntity : Entity<Guid>\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(entityTemplate);
|
||||
|
||||
|
||||
TemplateEntity getListInputTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "GetListInput",
|
||||
BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetListInput.cs",
|
||||
Remarks = "列表查询参数",
|
||||
TemplateStr = "using Yi.Framework.Ddd;\r\nusing Yi.Framework.Ddd.Application.Contracts;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n /// <summary>\r\n /// 查询参数\r\n /// </summary>\r\n public class @ModelGetListInput : PagedAllResultRequestDto\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(getListInputTemplate);
|
||||
|
||||
|
||||
TemplateEntity getListOutputDtoTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "GetListOutputDto",
|
||||
BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetListOutputDto.cs",
|
||||
Remarks = "列表返回dto",
|
||||
TemplateStr = "using lo.Abp.Application.Dtos;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelGetListOutputDto : EntityDto<Guid>\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(getListOutputDtoTemplate);
|
||||
|
||||
|
||||
TemplateEntity getOutputDtoTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "GetOutputDto",
|
||||
BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetOutputDto.cs",
|
||||
Remarks = "单返回dto",
|
||||
TemplateStr = "using lo.Abp.Application.Dtos;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelGetOutputDto : EntityDto<Guid>\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(getOutputDtoTemplate);
|
||||
|
||||
TemplateEntity updateInputTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "UpdateInput",
|
||||
BuildPath = "D:\\code\\Dtos\\@Model\\@ModelUpdateInput.cs",
|
||||
Remarks = "更新输入",
|
||||
TemplateStr = "namespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelUpdateInput\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(updateInputTemplate);
|
||||
|
||||
TemplateEntity createInputTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "CreateInput",
|
||||
BuildPath = "D:\\code\\Dtos\\@Model\\@ModelCreateInput.cs",
|
||||
Remarks = "创建dto",
|
||||
TemplateStr = "namespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n /// <summary>\r\n /// @Model输入创建对象\r\n /// </summary>\r\n public class @ModelCreateInput\r\n {\r\n@field\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(createInputTemplate);
|
||||
|
||||
|
||||
TemplateEntity iServicesTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "IServices",
|
||||
BuildPath = "D:\\code\\IServices\\I@ModelService.cs",
|
||||
Remarks = "应用服务抽象",
|
||||
TemplateStr = "using lo.Abp.Application.Services;\r\nusing Yi.Framework.Ddd.Application.Contracts;\r\nusing Yi.Framework.Rbac.Application.Contracts.Dtos.@Model;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.IServices\r\n{\r\n /// <summary>\r\n /// @Model服务抽象\r\n /// </summary>\r\n public interface I@ModelService : IYiCrudAppService<@ModelGetOutputDto, @ModelGetListOutputDto, Guid, @ModelGetListInput, @ModelCreateInput, @ModelUpdateInput>\r\n {\r\n\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(iServicesTemplate);
|
||||
|
||||
|
||||
|
||||
TemplateEntity servicesTemplate = new TemplateEntity()
|
||||
{
|
||||
Name = "Service",
|
||||
BuildPath = "D:\\code\\Services\\@ModelService.cs",
|
||||
Remarks = "应用服务",
|
||||
TemplateStr = "using SqlSugar;\r\nusing lo.Abp.Application.Dtos;\r\nusing lo.Abp.Application.Services;\r\nusing Yi.Framework.Ddd.Application;\r\nusing Yi.Framework.Rbac.Application.Contracts.Dtos.@Model;\r\nusing Yi.Framework.Rbac.Application.Contracts.IServices;\r\nusing Yi.Framework.Rbac.Domain.Entities;\r\nusing Yi.Framework.SqlSugarCore.Abstractions;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Services\r\n{\r\n /// <summary>\r\n /// @Model服务实现\r\n /// </summary>\r\n public class @ModelService : YiCrudAppService<@ModelEntity, @ModelGetOutputDto, @ModelGetListOutputDto, Guid, @ModelGetListInput, @ModelCreateInput, @ModelUpdateInput>,\r\n I@ModelService\r\n {\r\n private ISqlSugarRepository<@ModelEntity, Guid> _repository;\r\n public @ModelService(ISqlSugarRepository<@ModelEntity, Guid> repository) : base(repository)\r\n {\r\n _repository = repository;\r\n }\r\n\r\n /// <summary>\r\n /// 多查\r\n /// </summary>\r\n /// <param name=\"input\"></param>\r\n /// <returns></returns>\r\n public override async Task<PagedResultDto<@ModelGetListOutputDto>> GetListAsync(@ModelGetListInput input)\r\n {\r\n RefAsync<int> total = 0;\r\n\r\n var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.@ModelKey), x => x.@ModelKey.Contains(input.@ModelKey!))\r\n .WhereIF(!string.IsNullOrEmpty(input.@ModelName), x => x.@ModelName!.Contains(input.@ModelName!))\r\n .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)\r\n .ToPageListAsync(input.SkipCount, input.MaxResultCount, total);\r\n return new PagedResultDto<@ModelGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));\r\n }\r\n }\r\n}\r\n"
|
||||
};
|
||||
entities.Add(servicesTemplate);
|
||||
|
||||
TemplateEntity apiTemplate = new TemplateEntity()
|
||||
{
|
||||
TemplateStr = "import request from '@/utils/request'\r\n\r\n// 分页查询\r\nexport function listData(query) {\r\n return request({\r\n url: '/@model',\r\n method: 'get',\r\n params: query\r\n })\r\n}\r\n\r\n// id查询\r\nexport function getData(id) {\r\n return request({\r\n url: `/@model/${id}`,\r\n method: 'get'\r\n })\r\n}\r\n\r\n// 新增\r\nexport function addData(data) {\r\n return request({\r\n url: '/@model',\r\n method: 'post',\r\n data: data\r\n })\r\n}\r\n\r\n// 修改\r\nexport function updateData(id,data) {\r\n return request({\r\n url: `/@model/${id}`,\r\n method: 'put',\r\n data: data\r\n })\r\n}\r\n\r\n// 删除\r\nexport function delData(ids) {\r\n return request({\r\n url: `/@model`,\r\n method: 'delete',\r\n params:{id:ids}\r\n })\r\n}\r\n",
|
||||
Name = "api",
|
||||
BuildPath = "D:\\code\\Api\\@ModelApi.vue",
|
||||
Remarks = "前端api"
|
||||
};
|
||||
entities.Add(apiTemplate);
|
||||
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
using Yi.Framework.SqlSugarCore;
|
||||
|
||||
namespace Yi.Framework.CodeGen.SqlSugarCore
|
||||
{
|
||||
[DependsOn(typeof(YiFrameworkSqlSugarCoreModule))]
|
||||
public class YiFrameworkCodeGenSqlSugarCoreModule:AbpModule
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
|
||||
{
|
||||
/// <summary>
|
||||
/// Notice输入创建对象
|
||||
/// </summary>
|
||||
public class NoticeCreateInput
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public NoticeTypeEnum Type { get; set; }
|
||||
public string Content { get; set; }
|
||||
public int OrderNum { get; set; }
|
||||
public bool State { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Yi.Framework.Ddd.Application.Contracts;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
|
||||
{
|
||||
/// <summary>
|
||||
/// 查询参数
|
||||
/// </summary>
|
||||
public class NoticeGetListInput : PagedAllResultRequestDto
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public NoticeTypeEnum? Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
|
||||
{
|
||||
public class NoticeGetListOutputDto : EntityDto<Guid>
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public NoticeTypeEnum Type { get; set; }
|
||||
public string Content { get; set; }
|
||||
public bool IsDeleted { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public Guid? CreatorId { get; set; }
|
||||
public Guid? LastModifierId { get; set; }
|
||||
public DateTime? LastModificationTime { get; set; }
|
||||
public int OrderNum { get; set; }
|
||||
public bool State { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
|
||||
{
|
||||
public class NoticeGetOutputDto : EntityDto<Guid>
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public NoticeTypeEnum Type { get; set; }
|
||||
public string Content { get; set; }
|
||||
public bool IsDeleted { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public Guid? CreatorId { get; set; }
|
||||
public Guid? LastModifierId { get; set; }
|
||||
public DateTime? LastModificationTime { get; set; }
|
||||
public int OrderNum { get; set; }
|
||||
public bool State { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
|
||||
{
|
||||
public class NoticeUpdateInput
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public NoticeTypeEnum? Type { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public int? OrderNum { get; set; }
|
||||
public bool? State { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Yi.Framework.Ddd.Application.Contracts;
|
||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.Notice;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Contracts.IServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Notice服务抽象
|
||||
/// </summary>
|
||||
public interface INoticeService : IYiCrudAppService<NoticeGetOutputDto, NoticeGetListOutputDto, Guid, NoticeGetListInput, NoticeCreateInput, NoticeUpdateInput>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using Lazy.Captcha.Core;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SqlSugar;
|
||||
using Volo.Abp;
|
||||
@@ -33,15 +34,17 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
private readonly IGuidGenerator _guidGenerator;
|
||||
private readonly RbacOptions _rbacOptions;
|
||||
private readonly IAliyunManger _aliyunManger;
|
||||
private IDistributedCache<UserInfoCacheItem, UserInfoCacheKey> _userCache;
|
||||
public AccountService(IUserRepository userRepository,
|
||||
ICurrentUser currentUser,
|
||||
IAccountManager accountManager,
|
||||
ISqlSugarRepository<MenuEntity> menuRepository,
|
||||
IDistributedCache<CaptchaPhoneCacheItem, CaptchaPhoneCacheKey> phoneCache,
|
||||
IDistributedCache<UserInfoCacheItem, UserInfoCacheKey> userCache,
|
||||
ICaptcha captcha,
|
||||
IGuidGenerator guidGenerator,
|
||||
IOptions<RbacOptions> options,
|
||||
IAliyunManger aliyunManger )
|
||||
IAliyunManger aliyunManger)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_currentUser = currentUser;
|
||||
@@ -52,6 +55,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
_guidGenerator = guidGenerator;
|
||||
_rbacOptions = options.Value;
|
||||
_aliyunManger = aliyunManger;
|
||||
_userCache = userCache;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,10 +117,10 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
[Authorize(AuthenticationSchemes = TokenTypeConst.Refresh)]
|
||||
public async Task<object> PostRefreshAsync([FromQuery] string refresh_token)
|
||||
{
|
||||
var userId = CurrentUser.Id.Value;
|
||||
var accessToken = await _accountManager.GetTokenByUserIdAsync(userId);
|
||||
var refreshToken = _accountManager.CreateRefreshToken(userId);
|
||||
return new { Token = accessToken, RefreshToken = refreshToken };
|
||||
var userId = CurrentUser.Id.Value;
|
||||
var accessToken = await _accountManager.GetTokenByUserIdAsync(userId);
|
||||
var refreshToken = _accountManager.CreateRefreshToken(userId);
|
||||
return new { Token = accessToken, RefreshToken = refreshToken };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -249,7 +253,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询已登录的账户信息
|
||||
/// 查询已登录的账户信息,已缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Route("account")]
|
||||
@@ -263,16 +267,33 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
throw new UserFriendlyException("用户未登录");
|
||||
}
|
||||
//此处从缓存中获取也行
|
||||
//var data = _cacheManager.Get<UserRoleMenuDto>($"Yi:UserInfo:{userId}");
|
||||
var data = await _userRepository.GetUserAllInfoAsync(userId ?? Guid.Empty);
|
||||
//系统用户数据被重置,老前端访问重新授权
|
||||
if (data is null)
|
||||
//此处优先从缓存中获取
|
||||
UserRoleMenuDto output = null;
|
||||
var cacheData = await _userCache.GetAsync(new UserInfoCacheKey(userId.Value));
|
||||
if (cacheData is not null)
|
||||
{
|
||||
throw new AbpAuthorizationException();
|
||||
output = cacheData.Info;
|
||||
}
|
||||
data.Menus.Clear();
|
||||
return data;
|
||||
else
|
||||
{
|
||||
var data = await _userRepository.GetUserAllInfoAsync(userId.Value);
|
||||
//系统用户数据被重置,老前端访问重新授权
|
||||
if (data is null)
|
||||
{
|
||||
throw new AbpAuthorizationException();
|
||||
}
|
||||
data.Menus.Clear();
|
||||
|
||||
output = data;
|
||||
|
||||
var tokenExpiresMinuteTime = LazyServiceProvider.GetRequiredService<IOptions<JwtOptions>>().Value.ExpiresMinuteTime;
|
||||
//将用户信息放入缓存,下次获取直接从缓存中获取即可,过期时间为token过期时间
|
||||
await _userCache.SetAsync(new UserInfoCacheKey(userId.Value), new UserInfoCacheItem(data), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(tokenExpiresMinuteTime) });
|
||||
}
|
||||
|
||||
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -307,10 +328,18 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
/// 退出登录
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<bool> PostLogout()
|
||||
public async Task<bool> PostLogout()
|
||||
{
|
||||
//通过鉴权jwt获取到用户的id
|
||||
var userId = _currentUser.Id;
|
||||
if (userId is null)
|
||||
{
|
||||
return false;
|
||||
// throw new UserFriendlyException("用户已退出");
|
||||
}
|
||||
await _userCache.RemoveAsync(new UserInfoCacheKey(userId.Value));
|
||||
//Jwt去中心化登出,只需用记录日志即可
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
using FreeRedis;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.VisualBasic;
|
||||
using TencentCloud.Mna.V20210119.Models;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.MonitorCache;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
{
|
||||
public class MonitorCacheService : ApplicationService, IMonitorCacheService
|
||||
{
|
||||
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 缓存前缀
|
||||
/// </summary>
|
||||
private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDistributedCacheOptions>>().Value.KeyPrefix;
|
||||
|
||||
private bool EnableRedisCache
|
||||
{
|
||||
get
|
||||
{
|
||||
var redisEnabled = LazyServiceProvider.LazyGetRequiredService<IConfiguration>()["Redis:IsEnabled"];
|
||||
return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 使用懒加载防止报错
|
||||
/// </summary>
|
||||
private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService<IRedisClient>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有key并分组
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("monitor-cache/name")]
|
||||
public List<MonitorCacheNameGetListOutputDto> GetName()
|
||||
{
|
||||
VerifyRedisCacheEnable();
|
||||
var keys = RedisClient.Keys(CacheKeyPrefix + "*");
|
||||
var result = GroupedKeys(keys.ToList());
|
||||
var output = result.Select(x => new MonitorCacheNameGetListOutputDto { CacheName = x }).ToList();
|
||||
return output;
|
||||
}
|
||||
|
||||
private List<string> GroupedKeys(List<string> keys)
|
||||
{
|
||||
HashSet<string> resultSet = new HashSet<string>();
|
||||
foreach (string str in keys)
|
||||
{
|
||||
string[] parts = str.Split(':');
|
||||
|
||||
// 如果字符串中包含冒号,则将第一部分和第二部分进行分组
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
string group = $"{parts[0]}:{parts[1]}";
|
||||
resultSet.Add(group);
|
||||
}
|
||||
// 如果字符串中不包含冒号,则直接进行分组
|
||||
else
|
||||
{
|
||||
resultSet.Add(str);
|
||||
}
|
||||
}
|
||||
return resultSet.ToList();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void VerifyRedisCacheEnable()
|
||||
{
|
||||
if (!EnableRedisCache)
|
||||
{
|
||||
throw new UserFriendlyException("后端程序未使用Redis缓存,无法对Redis进行监控,可切换使用Redis");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[HttpGet("monitor-cache/key/{cacaheName}")]
|
||||
public List<string> GetKey(string cacaheName)
|
||||
{
|
||||
VerifyRedisCacheEnable();
|
||||
var output = RedisClient.Keys($"{cacaheName}:*").Select(x => x.RemovePreFix(cacaheName + ":"));
|
||||
return output.ToList();
|
||||
}
|
||||
|
||||
//全部不为空
|
||||
[HttpGet("monitor-cache/value/{cacaheName}/{cacaheKey}")]
|
||||
public MonitorCacheGetListOutputDto GetValue(string cacaheName, string cacaheKey)
|
||||
{
|
||||
var value = RedisClient.HGet($"{cacaheName}:{cacaheKey}", "data");
|
||||
return new MonitorCacheGetListOutputDto() { CacheKey = cacaheKey, CacheName = cacaheName, CacheValue = value };
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpDelete("monitor-cache/key/{cacaheName}")]
|
||||
public bool DeleteKey(string cacaheName)
|
||||
{
|
||||
VerifyRedisCacheEnable();
|
||||
RedisClient.Del($"{cacaheName}:*");
|
||||
return true;
|
||||
}
|
||||
|
||||
[HttpDelete("monitor-cache/value/{cacaheName}/{cacaheKey}")]
|
||||
public bool DeleteValue(string cacaheName, string cacaheKey)
|
||||
{
|
||||
RedisClient.Del($"{cacaheName}:{cacaheKey}");
|
||||
return true;
|
||||
}
|
||||
|
||||
[HttpDelete("monitor-cache/clear")]
|
||||
public bool DeleteClear()
|
||||
{
|
||||
RedisClient.FlushDb();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.Core.Helper;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
{
|
||||
public class MonitorServerService : ApplicationService, IMonitorServerService
|
||||
{
|
||||
@@ -7,13 +7,13 @@ using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
using Yi.Framework.Rbac.Application.SignalRHubs;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Model;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
{
|
||||
public class OnlineService : ApplicationService, IOnlineService
|
||||
{
|
||||
private ILogger<OnlineService> _logger;
|
||||
private IHubContext<OnlineUserHub> _hub;
|
||||
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineUserHub> hub)
|
||||
private IHubContext<OnlineHub> _hub;
|
||||
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineHub> hub)
|
||||
{
|
||||
_logger = logger;
|
||||
_hub = hub;
|
||||
@@ -26,7 +26,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
/// <returns></returns>
|
||||
public Task<PagedResultDto<OnlineUserModel>> GetListAsync([FromQuery] OnlineUserModel online)
|
||||
{
|
||||
var data = OnlineUserHub.clientUsers;
|
||||
var data = OnlineHub.clientUsers;
|
||||
IEnumerable<OnlineUserModel> dataWhere = data.AsEnumerable();
|
||||
|
||||
if (!string.IsNullOrEmpty(online.Ipaddr))
|
||||
@@ -37,7 +37,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
dataWhere = dataWhere.Where((u) => u.UserName!.Contains(online.UserName));
|
||||
}
|
||||
return Task.FromResult(new PagedResultDto<OnlineUserModel>() { TotalCount = data.Count, Items = dataWhere.ToList() }) ;
|
||||
return Task.FromResult(new PagedResultDto<OnlineUserModel>() { TotalCount = data.Count, Items = dataWhere.ToList() });
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
[Route("online/{connnectionId}")]
|
||||
public async Task<bool> ForceOut(string connnectionId)
|
||||
{
|
||||
if (OnlineUserHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId))
|
||||
if (OnlineHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId))
|
||||
{
|
||||
//前端接受到这个事件后,触发前端自动退出
|
||||
await _hub.Clients.Client(connnectionId).SendAsync("forceOut", "你已被强制退出!");
|
||||
@@ -11,7 +11,7 @@ using Yi.Framework.Rbac.Application.Contracts.Dtos.Task;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
{
|
||||
public class TaskService : ApplicationService, ITaskService
|
||||
{
|
||||
@@ -19,7 +19,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
private readonly IClock _clock;
|
||||
public TaskService(ISchedulerFactory schedulerFactory, IClock clock)
|
||||
{
|
||||
_clock=clock;
|
||||
_clock = clock;
|
||||
_schedulerFactory = schedulerFactory;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
//状态
|
||||
var state = await scheduler.GetTriggerState(trigger.Key);
|
||||
|
||||
|
||||
|
||||
var output = new TaskGetOutput
|
||||
{
|
||||
JobId = jobDetail.Key.Name,
|
||||
@@ -48,7 +48,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap),
|
||||
Concurrent = !jobDetail.ConcurrentExecutionDisallowed,
|
||||
Description = jobDetail.Description,
|
||||
LastRunTime = _clock.Normalize( trigger.GetPreviousFireTimeUtc()?.DateTime??DateTime.MinValue),
|
||||
LastRunTime = _clock.Normalize(trigger.GetPreviousFireTimeUtc()?.DateTime ?? DateTime.MinValue),
|
||||
NextRunTime = _clock.Normalize(trigger.GetNextFireTimeUtc()?.DateTime ?? DateTime.MinValue),
|
||||
AssemblyName = jobDetail.JobType.Assembly.GetName().Name,
|
||||
Status = state.ToString()
|
||||
@@ -56,7 +56,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
|
||||
if (trigger is ISimpleTrigger simple)
|
||||
{
|
||||
output.TriggerArgs =Math.Round(simple.RepeatInterval.TotalMinutes,2) .ToString() + "分钟";
|
||||
output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟";
|
||||
output.Type = JobTypeEnum.Millisecond;
|
||||
output.Millisecond = simple.RepeatInterval.TotalMilliseconds;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
output.TriggerArgs = cron.CronExpressionString!;
|
||||
output.Type = JobTypeEnum.Cron;
|
||||
output.Cron=cron.CronExpressionString;
|
||||
output.Cron = cron.CronExpressionString;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteAsync(IEnumerable<string> id)
|
||||
{
|
||||
{
|
||||
var scheduler = await _schedulerFactory.GetScheduler();
|
||||
await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList());
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.MonitorCache;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
public class MonitorCacheService : ApplicationService, IMonitorCacheService
|
||||
{
|
||||
private static List<MonitorCacheNameGetListOutputDto> monitorCacheNames => new List<MonitorCacheNameGetListOutputDto>()
|
||||
{
|
||||
new MonitorCacheNameGetListOutputDto{ CacheName="Yi:Login",Remark="登录验证码"},
|
||||
new MonitorCacheNameGetListOutputDto{ CacheName="Yi:User",Remark="用户信息"}
|
||||
};
|
||||
private Dictionary<string, string> monitorCacheNamesDic => monitorCacheNames.ToDictionary(x => x.CacheName, x => x.Remark);
|
||||
//private CSRedisClient _cacheClient;
|
||||
public MonitorCacheService()
|
||||
{
|
||||
//_cacheClient = redisCacheClient.Client;
|
||||
}
|
||||
//cacheKey value为空,只要name和备注
|
||||
|
||||
public List<MonitorCacheNameGetListOutputDto> GetName()
|
||||
{
|
||||
//固定的
|
||||
return monitorCacheNames;
|
||||
}
|
||||
[HttpGet("key/{cacaheName}")]
|
||||
public List<string> GetKey(string cacaheName)
|
||||
{
|
||||
//var output = _cacheClient.Keys($"{cacaheName}:*");
|
||||
return new List<string>() { "1233124", "3124", "1231251", "12312412" };
|
||||
}
|
||||
|
||||
//全部不为空
|
||||
[HttpGet("value/{cacaheName}/{cacaheKey}")]
|
||||
public MonitorCacheGetListOutputDto GetValue(string cacaheName, string cacaheKey)
|
||||
{
|
||||
//var value = _cacheClient.Get($"{cacaheName}:{cacaheKey}");
|
||||
return new MonitorCacheGetListOutputDto() { CacheKey = cacaheKey, CacheName = cacaheName, CacheValue = "ttt", Remark = monitorCacheNamesDic[cacaheName] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Yi.Framework.Ddd.Application;
|
||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.Notice;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
using Yi.Framework.Rbac.Application.SignalRHubs;
|
||||
using Yi.Framework.Rbac.Domain.Entities;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Notice服务实现
|
||||
/// </summary>
|
||||
public class NoticeService : YiCrudAppService<NoticeEntity, NoticeGetOutputDto, NoticeGetListOutputDto, Guid, NoticeGetListInput, NoticeCreateInput, NoticeUpdateInput>,
|
||||
INoticeService
|
||||
{
|
||||
private ISqlSugarRepository<NoticeEntity, Guid> _repository;
|
||||
private IHubContext<NoticeHub> _hubContext;
|
||||
public NoticeService(ISqlSugarRepository<NoticeEntity, Guid> repository, IHubContext<NoticeHub> hubContext) : base(repository)
|
||||
{
|
||||
_hubContext = hubContext;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多查
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<PagedResultDto<NoticeGetListOutputDto>> GetListAsync(NoticeGetListInput input)
|
||||
{
|
||||
RefAsync<int> total = 0;
|
||||
|
||||
var entities = await _repository._DbQueryable.WhereIF(input.Type is not null, x => x.Type == input.Type)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title!.Contains(input.Title!))
|
||||
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||
return new PagedResultDto<NoticeGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送在线消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("notice/online/{id}")]
|
||||
public async Task SendOnlineAsync([FromRoute] Guid id)
|
||||
{
|
||||
var entity = await _repository._DbQueryable.FirstAsync(x => x.Id == id);
|
||||
await _hubContext.Clients.All.SendAsync("ReceiveNotice", entity.Type.ToString(), entity.Title, entity.Content);
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送离线消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("notice/offline/{id}")]
|
||||
public async Task SendOfflineAsync([FromRoute] Guid id)
|
||||
{
|
||||
//先发送一个在线
|
||||
await SendOnlineAsync(id);
|
||||
|
||||
//然后将所有用户和通知id进行保留记录,判断是否已读还是未读
|
||||
//在首次请求返回全部未读的通知给前端即可
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Yi.Framework.Rbac.Application.Contracts.Dtos.LoginLog;
|
||||
using Yi.Framework.Rbac.Domain.Entities;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
namespace Yi.Framework.Rbac.Application.Services.RecordLog
|
||||
{
|
||||
public class LoginLogService : YiCrudAppService<LoginLogEntity, LoginLogGetListOutputDto, Guid, LoginLogGetListInputVo>
|
||||
{
|
||||
@@ -7,7 +7,7 @@ using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
using Yi.Framework.Rbac.Domain.Operlog;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.Services
|
||||
namespace Yi.Framework.Rbac.Application.Services.RecordLog
|
||||
{
|
||||
/// <summary>
|
||||
/// OperationLog服务实现
|
||||
@@ -18,7 +18,7 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
private ISqlSugarRepository<OperationLogEntity, Guid> _repository;
|
||||
public OperationLogService(ISqlSugarRepository<OperationLogEntity, Guid> repository) : base(repository)
|
||||
{
|
||||
_repository=repository;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public override async Task<PagedResultDto<OperationLogGetListOutputDto>> GetListAsync(OperationLogGetListInputVo input)
|
||||
@@ -0,0 +1,15 @@
|
||||
using Volo.Abp.AspNetCore.SignalR;
|
||||
|
||||
namespace Yi.Framework.Rbac.Application.SignalRHubs
|
||||
{
|
||||
[HubRoute("/hub/notice")]
|
||||
public class NoticeHub : AbpHub
|
||||
{
|
||||
/// <summary>
|
||||
/// 由于发布功能,主要是服务端项客户端主动推送
|
||||
/// </summary>
|
||||
public NoticeHub()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs
|
||||
{
|
||||
[HubRoute("/hub/main")]
|
||||
[Authorize]
|
||||
public class OnlineUserHub : AbpHub
|
||||
public class OnlineHub : AbpHub
|
||||
{
|
||||
public static readonly List<OnlineUserModel> clientUsers = new();
|
||||
private readonly static object objLock = new object();
|
||||
|
||||
private HttpContext? _httpContext;
|
||||
private ILogger<OnlineUserHub> _logger => LoggerFactory.CreateLogger<OnlineUserHub>();
|
||||
public OnlineUserHub(IHttpContextAccessor httpContextAccessor)
|
||||
private ILogger<OnlineHub> _logger => LoggerFactory.CreateLogger<OnlineHub>();
|
||||
public OnlineHub(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContext = httpContextAccessor?.HttpContext;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace Yi.Framework.Rbac.Domain.Shared.Caches
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Yi:Phone:{Phone}";
|
||||
return $"Phone:{Phone}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Dtos;
|
||||
|
||||
namespace Yi.Framework.Rbac.Domain.Shared.Caches
|
||||
{
|
||||
public class UserInfoCacheItem
|
||||
{
|
||||
public UserInfoCacheItem(UserRoleMenuDto info) { Info = info; }
|
||||
/// <summary>
|
||||
/// 存储的用户信息
|
||||
/// </summary>
|
||||
public UserRoleMenuDto Info { get; set; }
|
||||
}
|
||||
public class UserInfoCacheKey
|
||||
{
|
||||
public UserInfoCacheKey(Guid userId) { UserId = userId; }
|
||||
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"User:{UserId}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yi.Framework.Rbac.Domain.Shared.Enums
|
||||
{
|
||||
public enum NoticeTypeEnum
|
||||
{
|
||||
[Description("走马灯")]
|
||||
MerryGoRound = 0,
|
||||
[Description("提示弹窗")]
|
||||
Popup = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Auditing;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
using Yi.Framework.Core.Data;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.Rbac.Domain.Entities
|
||||
{
|
||||
[SugarTable("Notice")]
|
||||
public class NoticeEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
|
||||
{
|
||||
|
||||
[SugarColumn(IsPrimaryKey = true)]
|
||||
public override Guid Id { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 公告标题
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public NoticeTypeEnum Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||
public string Content { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public DateTime CreationTime { get; set; }
|
||||
|
||||
public Guid? CreatorId { get; set; }
|
||||
|
||||
public Guid? LastModifierId { get; set; }
|
||||
|
||||
public DateTime? LastModificationTime { get; set; }
|
||||
|
||||
public int OrderNum { get; set; }
|
||||
public bool State { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace Yi.Framework.Rbac.Domain.Entities
|
||||
/// 岗位表
|
||||
///</summary>
|
||||
[SugarTable("Post")]
|
||||
public partial class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
|
||||
public class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Yi.Framework.Rbac.Domain.Entities;
|
||||
/// 角色部门关系表
|
||||
///</summary>
|
||||
[SugarTable("RoleDept")]
|
||||
public partial class RoleDeptEntity : Entity<Guid>
|
||||
public class RoleDeptEntity : Entity<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
|
||||
@@ -6,15 +6,15 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
using Volo.Abp.Domain.Services;
|
||||
using Volo.Abp.EventBus.Local;
|
||||
using Volo.Abp.Security.Claims;
|
||||
using Volo.Abp.Users;
|
||||
using Yi.Framework.Core.Helper;
|
||||
using Yi.Framework.Rbac.Domain.Entities;
|
||||
using Yi.Framework.Rbac.Domain.Repositories;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Caches;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Consts;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Dtos;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Etos;
|
||||
@@ -38,6 +38,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
||||
private UserManager _userManager;
|
||||
private ISqlSugarRepository<RoleEntity> _roleRepository;
|
||||
private RefreshJwtOptions _refreshJwtOptions;
|
||||
|
||||
public AccountManager(IUserRepository repository
|
||||
, IHttpContextAccessor httpContextAccessor
|
||||
, IOptions<JwtOptions> jwtOptions
|
||||
@@ -87,9 +88,9 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
||||
loginEto.UserId = userInfo.User.Id;
|
||||
await _localEventBus.PublishAsync(loginEto);
|
||||
}
|
||||
var accessToken = CreateToken(this.UserInfoToClaim(userInfo));
|
||||
//将用户信息添加到缓存中,需要考虑的是更改了用户、角色、菜单等整个体系都需要将缓存进行刷新,看具体业务进行选择
|
||||
|
||||
var accessToken = CreateToken(this.UserInfoToClaim(userInfo));
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
@@ -175,11 +176,12 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
||||
{
|
||||
userAction.Invoke(user);
|
||||
}
|
||||
if (user == null)
|
||||
//这里为了兼容解决数据库开启了大小写不敏感问题,还要将用户名进行二次效验
|
||||
if (user != null&&user.UserName==userName)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj" />
|
||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Yi.Framework.Rbac.Domain.Shared\Yi.Framework.Rbac.Domain.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -3,6 +3,7 @@ using Volo.Abp.AspNetCore.SignalR;
|
||||
using Volo.Abp.Caching;
|
||||
using Volo.Abp.Domain;
|
||||
using Volo.Abp.Modularity;
|
||||
using Yi.Framework.Caching.FreeRedis;
|
||||
using Yi.Framework.Mapster;
|
||||
using Yi.Framework.Rbac.Domain.Authorization;
|
||||
using Yi.Framework.Rbac.Domain.Operlog;
|
||||
@@ -13,6 +14,7 @@ namespace Yi.Framework.Rbac.Domain
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(YiFrameworkRbacDomainSharedModule),
|
||||
typeof(YiFrameworkCachingFreeRedisModule),
|
||||
|
||||
typeof(AbpAspNetCoreSignalRModule),
|
||||
typeof(AbpDddDomainModule),
|
||||
|
||||
@@ -1125,6 +1125,75 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
||||
|
||||
|
||||
|
||||
//通知公告
|
||||
MenuEntity notice = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
|
||||
MenuName = "通知公告",
|
||||
PermissionCode = "system:notice:list",
|
||||
MenuType = MenuTypeEnum.Menu,
|
||||
Router = "notice",
|
||||
IsShow = true,
|
||||
IsLink = false,
|
||||
IsCache = true,
|
||||
Component = "system/notice/index",
|
||||
MenuIcon = "message",
|
||||
OrderNum = 93,
|
||||
ParentId = system.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
entities.Add(notice);
|
||||
|
||||
MenuEntity noticeQuery = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
|
||||
MenuName = "通知查询",
|
||||
PermissionCode = "system:notice:query",
|
||||
MenuType = MenuTypeEnum.Component,
|
||||
OrderNum = 100,
|
||||
ParentId = notice.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
entities.Add(noticeQuery);
|
||||
|
||||
MenuEntity noticeAdd = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
|
||||
MenuName = "通知新增",
|
||||
PermissionCode = "system:notice:add",
|
||||
MenuType = MenuTypeEnum.Component,
|
||||
OrderNum = 100,
|
||||
ParentId = notice.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
entities.Add(noticeAdd);
|
||||
|
||||
MenuEntity noticeEdit = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
|
||||
MenuName = "通知修改",
|
||||
PermissionCode = "system:notice:edit",
|
||||
MenuType = MenuTypeEnum.Component,
|
||||
OrderNum = 100,
|
||||
ParentId = notice.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
entities.Add(noticeEdit);
|
||||
|
||||
MenuEntity noticeRemove = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
|
||||
MenuName = "通知删除",
|
||||
PermissionCode = "system:notice:remove",
|
||||
MenuType = MenuTypeEnum.Component,
|
||||
OrderNum = 100,
|
||||
ParentId = notice.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
entities.Add(noticeRemove);
|
||||
|
||||
|
||||
|
||||
//日志管理
|
||||
MenuEntity log = new MenuEntity(_guidGenerator.Create())
|
||||
{
|
||||
@@ -1135,7 +1204,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
||||
IsShow = true,
|
||||
IsLink = false,
|
||||
MenuIcon = "log",
|
||||
OrderNum = 93,
|
||||
OrderNum = 92,
|
||||
ParentId = system.Id,
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Uow;
|
||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
||||
@@ -117,5 +118,19 @@ namespace Yi.Abp.Application.Services
|
||||
var entity = new BannerEntity();
|
||||
var dto = entity.Adapt<BannerGetListOutputDto>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 速率限制
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
// [DisableRateLimiting]
|
||||
//[EnableRateLimiting("sliding")]
|
||||
public int GetRateLimiting()
|
||||
{
|
||||
RequestNumber++;
|
||||
return RequestNumber;
|
||||
}
|
||||
private static int RequestNumber { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<ProjectReference Include="..\..\framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\..\module\audit-logging\Yi.Framework.AuditLogging.SqlSugarCore\Yi.Framework.AuditLogging.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.SqlSugarCore\Yi.Framework.Bbs.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\..\module\code-gen\Yi.Framework.CodeGen.SqlSugarCore\Yi.Framework.CodeGen.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.SqlSugarCore\Yi.Framework.Rbac.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\..\module\tenant-management\Yi.Framework.TenantManagement.SqlSugarCore\Yi.Framework.TenantManagement.SqlSugarCore.csproj" />
|
||||
<ProjectReference Include="..\Yi.Abp.Domain\Yi.Abp.Domain.csproj" />
|
||||
|
||||
@@ -4,6 +4,7 @@ using Yi.Abp.Domain;
|
||||
using Yi.Abp.SqlSugarCore;
|
||||
using Yi.Framework.AuditLogging.SqlSugarCore;
|
||||
using Yi.Framework.Bbs.SqlSugarCore;
|
||||
using Yi.Framework.CodeGen.SqlSugarCore;
|
||||
using Yi.Framework.Mapster;
|
||||
using Yi.Framework.Rbac.SqlSugarCore;
|
||||
using Yi.Framework.SqlSugarCore;
|
||||
@@ -17,6 +18,7 @@ namespace Yi.Abp.SqlsugarCore
|
||||
|
||||
typeof(YiFrameworkRbacSqlSugarCoreModule),
|
||||
typeof(YiFrameworkBbsSqlSugarCoreModule),
|
||||
typeof(YiFrameworkCodeGenSqlSugarCoreModule),
|
||||
|
||||
typeof(YiFrameworkAuditLoggingSqlSugarCoreModule),
|
||||
typeof(YiFrameworkTenantManagementSqlSugarCoreModule),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using SqlSugar;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Yi.Framework.Rbac.SqlSugarCore;
|
||||
using Yi.Framework.SqlSugarCore;
|
||||
|
||||
namespace Yi.Abp.SqlSugarCore
|
||||
{
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.RateLimiting;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json.Converters;
|
||||
@@ -84,10 +87,12 @@ namespace Yi.Abp.Web
|
||||
});
|
||||
|
||||
//设置缓存不要过期,默认滑动20分钟
|
||||
Configure<AbpDistributedCacheOptions>(cacheOptions =>
|
||||
{
|
||||
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration =null;
|
||||
});
|
||||
Configure<AbpDistributedCacheOptions>(cacheOptions =>
|
||||
{
|
||||
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
|
||||
//缓存key前缀
|
||||
cacheOptions.KeyPrefix = "Yi:";
|
||||
});
|
||||
|
||||
|
||||
Configure<AbpAntiForgeryOptions>(options =>
|
||||
@@ -133,24 +138,62 @@ namespace Yi.Abp.Web
|
||||
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
|
||||
});
|
||||
|
||||
|
||||
//速率限制
|
||||
//每60秒限制100个请求,滑块添加,分6段
|
||||
service.AddRateLimiter(_ =>
|
||||
{
|
||||
_.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
||||
_.OnRejected = (context, _) =>
|
||||
{
|
||||
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
|
||||
{
|
||||
context.HttpContext.Response.Headers.RetryAfter =
|
||||
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
|
||||
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
|
||||
|
||||
return new ValueTask();
|
||||
};
|
||||
|
||||
//全局使用,链式表达式
|
||||
_.GlobalLimiter = PartitionedRateLimiter.CreateChained(
|
||||
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
|
||||
{
|
||||
var userAgent = httpContext.Request.Headers.UserAgent.ToString();
|
||||
|
||||
return RateLimitPartition.GetSlidingWindowLimiter
|
||||
(userAgent, _ =>
|
||||
new SlidingWindowRateLimiterOptions
|
||||
{
|
||||
PermitLimit = 100,
|
||||
Window = TimeSpan.FromSeconds(60),
|
||||
SegmentsPerWindow = 6,
|
||||
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
//jwt鉴权
|
||||
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
|
||||
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
|
||||
|
||||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtOptions.Issuer,
|
||||
ValidAudience = jwtOptions.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtOptions.Issuer,
|
||||
ValidAudience = jwtOptions.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
@@ -159,21 +202,21 @@ namespace Yi.Abp.Web
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
})
|
||||
.AddJwtBearer(TokenTypeConst.Refresh, options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
};
|
||||
})
|
||||
.AddJwtBearer(TokenTypeConst.Refresh, options =>
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = refreshJwtOptions.Issuer,
|
||||
ValidAudience = refreshJwtOptions.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = refreshJwtOptions.Issuer,
|
||||
ValidAudience = refreshJwtOptions.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var refresh_token = context.Request.Headers["refresh_token"];
|
||||
if (!string.IsNullOrEmpty(refresh_token))
|
||||
@@ -189,17 +232,17 @@ namespace Yi.Abp.Web
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
})
|
||||
.AddQQ(options =>
|
||||
{
|
||||
configuration.GetSection("OAuth:QQ").Bind(options);
|
||||
})
|
||||
.AddGitee(options =>
|
||||
{
|
||||
configuration.GetSection("OAuth:Gitee").Bind(options);
|
||||
});
|
||||
})
|
||||
.AddQQ(options =>
|
||||
{
|
||||
configuration.GetSection("OAuth:QQ").Bind(options);
|
||||
})
|
||||
.AddGitee(options =>
|
||||
{
|
||||
configuration.GetSection("OAuth:Gitee").Bind(options);
|
||||
});
|
||||
|
||||
//授权
|
||||
context.Services.AddAuthorization();
|
||||
@@ -219,6 +262,9 @@ namespace Yi.Abp.Web
|
||||
//跨域
|
||||
app.UseCors(DefaultCorsPolicyName);
|
||||
|
||||
//速率限制
|
||||
app.UseRateLimiter();
|
||||
|
||||
//无感token,先刷新再鉴权
|
||||
app.UseRefreshToken();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"EnabledSqlLog": true,
|
||||
"EnabledDbSeed": true,
|
||||
//SAAS多租户
|
||||
"EnabledSaasMultiTenancy":false
|
||||
"EnabledSaasMultiTenancy": false
|
||||
//读写分离地址
|
||||
//"ReadUrl": [
|
||||
// "DataSource=[xxxx]", //Sqlite
|
||||
@@ -32,6 +32,12 @@
|
||||
//]
|
||||
},
|
||||
|
||||
//redis使用freeesql参数在“FreeSqlOptions的ConnectionStringBuilder中”
|
||||
"Redis": {
|
||||
"IsEnabled": false,
|
||||
"Configuration": "127.0.0.1:6379,password=123,defaultDatabase=13"
|
||||
},
|
||||
|
||||
//鉴权
|
||||
"JwtOptions": {
|
||||
"Issuer": "https://ccnetcore.com",
|
||||
@@ -47,6 +53,7 @@
|
||||
"ExpiresMinuteTime": 172800
|
||||
},
|
||||
|
||||
|
||||
//第三方登录
|
||||
"OAuth": {
|
||||
//QQ
|
||||
|
||||
Binary file not shown.
80
Yi.Bbs.Vue3/package-lock.json
generated
80
Yi.Bbs.Vue3/package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@lucky-canvas/vue": "^0.1.11",
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"axios": "^1.3.4",
|
||||
"dayjs": "^1.11.10",
|
||||
@@ -855,6 +856,51 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@lucky-canvas/vue": {
|
||||
"version": "0.1.11",
|
||||
"resolved": "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz",
|
||||
"integrity": "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg==",
|
||||
"dependencies": {
|
||||
"@vue/composition-api": "^1.0.0",
|
||||
"lucky-canvas": "^1.7.23",
|
||||
"vue-demi": "^0.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.0.0 || >=3.0.0-rc.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@lucky-canvas/vue/node_modules/@vue/composition-api": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz",
|
||||
"integrity": "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==",
|
||||
"peerDependencies": {
|
||||
"vue": ">= 2.5 < 2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@lucky-canvas/vue/node_modules/vue-demi": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz",
|
||||
"integrity": "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-beta.1",
|
||||
"vue": "^2.6.0 || >=3.0.0-rc.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/signalr": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz",
|
||||
@@ -2673,6 +2719,11 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/lucky-canvas": {
|
||||
"version": "1.7.27",
|
||||
"resolved": "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz",
|
||||
"integrity": "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ=="
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.25.9",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz",
|
||||
@@ -4617,6 +4668,30 @@
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@lucky-canvas/vue": {
|
||||
"version": "0.1.11",
|
||||
"resolved": "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz",
|
||||
"integrity": "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg==",
|
||||
"requires": {
|
||||
"@vue/composition-api": "^1.0.0",
|
||||
"lucky-canvas": "^1.7.23",
|
||||
"vue-demi": "^0.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/composition-api": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz",
|
||||
"integrity": "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==",
|
||||
"requires": {}
|
||||
},
|
||||
"vue-demi": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz",
|
||||
"integrity": "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@microsoft/signalr": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz",
|
||||
@@ -6128,6 +6203,11 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lucky-canvas": {
|
||||
"version": "1.7.27",
|
||||
"resolved": "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz",
|
||||
"integrity": "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ=="
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.9",
|
||||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@lucky-canvas/vue": "^0.1.11",
|
||||
"@microsoft/signalr": "^8.0.0",
|
||||
"axios": "^1.3.4",
|
||||
"dayjs": "^1.11.10",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import signalR from "@/utils/signalR";
|
||||
import noticeSignalR from "@/utils/noticeSignalR";
|
||||
import useConfigStore from "@/stores/config";
|
||||
import { ElConfigProvider } from "element-plus";
|
||||
import useUserStore from "@/stores/user.js";
|
||||
@@ -25,9 +26,8 @@ if (loading !== null) {
|
||||
//加载全局信息
|
||||
onMounted(async () => {
|
||||
await configStore.getConfig();
|
||||
// setInterval(() => {
|
||||
// console.log("token的值:"+tokenValue.value);
|
||||
// }, 1000); // 1000毫秒,即1秒
|
||||
noticeSignalR.close();
|
||||
noticeSignalR.init(`notice`);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -13,3 +13,10 @@ export function signInRecord() {
|
||||
method: "get"
|
||||
});
|
||||
}
|
||||
|
||||
export function luckyWheel() {
|
||||
return request({
|
||||
url: "/lucky/wheel",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<el-icon><Memo /></el-icon>
|
||||
<span>任务列表</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="4" :route="{path:'/activity/sign'}">
|
||||
<el-menu-item index="4" :route="{path:'/activity/lucky'}">
|
||||
<el-icon><HelpFilled /></el-icon>
|
||||
<span>大转盘</span>
|
||||
</el-menu-item>
|
||||
|
||||
@@ -11,6 +11,7 @@ import "@/assets/styles/index.scss"; // global css
|
||||
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
import directive from "./directive"; // directive
|
||||
import VueLuckyCanvas from '@lucky-canvas/vue'
|
||||
|
||||
import "./permission";
|
||||
|
||||
@@ -24,6 +25,7 @@ import "./permission";
|
||||
app.use(pinia);
|
||||
directive(app);
|
||||
app.use(router);
|
||||
app.use(VueLuckyCanvas);
|
||||
await router.isReady();
|
||||
app.mount("#app");
|
||||
})();
|
||||
|
||||
@@ -122,6 +122,14 @@ const router = createRouter({
|
||||
title: "等级",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "lucky",
|
||||
path: "lucky",
|
||||
component: () => import("../views/lucky/Index.vue"),
|
||||
meta: {
|
||||
title: "大转盘",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },
|
||||
|
||||
107
Yi.Bbs.Vue3/src/utils/noticeSignalR.js
Normal file
107
Yi.Bbs.Vue3/src/utils/noticeSignalR.js
Normal file
@@ -0,0 +1,107 @@
|
||||
// 官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio
|
||||
import * as signalR from "@microsoft/signalr";
|
||||
|
||||
export default {
|
||||
// signalR对象
|
||||
SR: {},
|
||||
// 失败连接重试次数
|
||||
failNum: 4,
|
||||
async init(url) {
|
||||
const connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl(`${import.meta.env.VITE_APP_BASE_WS}/` + url)
|
||||
.withAutomaticReconnect() //自动重新连接
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.build();
|
||||
|
||||
|
||||
this.SR = connection;
|
||||
// 断线重连
|
||||
connection.onclose(async () => {
|
||||
console.log("断开连接了");
|
||||
console.assert(
|
||||
connection.state === signalR.HubConnectionState.Disconnected
|
||||
);
|
||||
// 建议用户重新刷新浏览器
|
||||
});
|
||||
|
||||
connection.onreconnected(() => {
|
||||
console.log("断线重新连接成功");
|
||||
});
|
||||
this.receiveMsg(connection);
|
||||
// 启动
|
||||
await this.start();
|
||||
},
|
||||
/**
|
||||
* 调用 this.signalR.start().then(async () => { await this.SR.invoke("method")})
|
||||
* @returns
|
||||
*/
|
||||
async close() {
|
||||
try {
|
||||
var that = this;
|
||||
await this.SR.stop();
|
||||
this.SR = {};
|
||||
} catch { }
|
||||
},
|
||||
|
||||
async start() {
|
||||
var that = this;
|
||||
|
||||
try {
|
||||
//使用async和await 或 promise的then 和catch 处理来自服务端的异常
|
||||
await this.SR.start();
|
||||
//console.assert(this.SR.state === signalR.HubConnectionState.Connected);
|
||||
//console.log('signalR 连接成功了', this.SR.state);
|
||||
return true;
|
||||
} catch (error) {
|
||||
that.failNum--;
|
||||
//console.log(`失败重试剩余次数${that.failNum}`, error)
|
||||
if (that.failNum > 0) {
|
||||
setTimeout(async () => {
|
||||
await this.SR.start();
|
||||
}, 5000);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// 接收消息处理
|
||||
receiveMsg(connection) {
|
||||
connection.on("receiveNotice", (type, title, content) => {
|
||||
|
||||
switch (type) {
|
||||
case "MerryGoRound":
|
||||
ElNotification({
|
||||
title: title,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: content,
|
||||
})
|
||||
break;
|
||||
case "Popup":
|
||||
ElNotification({
|
||||
title: title,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: content,
|
||||
})
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// connection.on("onlineNum", (data) => {
|
||||
// store.dispatch("socket/changeOnlineNum", data);
|
||||
// });
|
||||
// // 接收欢迎语
|
||||
// connection.on("welcome", (data) => {
|
||||
// console.log('welcome', data)
|
||||
// Notification.info(data)
|
||||
// });
|
||||
// // 接收后台手动推送消息
|
||||
// connection.on("receiveNotice", (title, data) => {
|
||||
// Notification({
|
||||
// type: 'info',
|
||||
// title: title,
|
||||
// message: data,
|
||||
// dangerouslyUseHTMLString: true,
|
||||
// duration: 0
|
||||
// })
|
||||
// })
|
||||
},
|
||||
};
|
||||
@@ -92,7 +92,7 @@ if(registerForm.password!=passwordConfirm.value)
|
||||
});
|
||||
|
||||
//成功
|
||||
if (response!=undefined) {
|
||||
if (response.status==204) {
|
||||
ElMessage({
|
||||
message: `恭喜!${registerForm.userName},注册成功!请登录!`,
|
||||
type: 'success',
|
||||
|
||||
@@ -39,9 +39,10 @@ import {getList,upgrade} from '@/apis/levelApi.js'
|
||||
import {getBbsUserProfile} from '@/apis/userApi.js'
|
||||
import { ref,onMounted, reactive,computed } from 'vue'
|
||||
import useAuths from '@/hooks/useAuths.js';
|
||||
const { isLogin,currentUserInfo } = useAuths();
|
||||
import useUserStore from "@/stores/user";
|
||||
const { isLogin } = useAuths();
|
||||
const userInfo=ref({});
|
||||
|
||||
const currentUserInfo=useUserStore();
|
||||
const levelData =ref([]);
|
||||
const moneyNum=ref(1);
|
||||
|
||||
@@ -73,7 +74,7 @@ const loadLevelData= async () => {
|
||||
const loadUserInfoData=async()=>{
|
||||
if(isLogin)
|
||||
{
|
||||
const {data}= await getBbsUserProfile(currentUserInfo.value.id);
|
||||
const {data}= await getBbsUserProfile(currentUserInfo.id);
|
||||
userInfo.value=data;
|
||||
}
|
||||
}
|
||||
|
||||
118
Yi.Bbs.Vue3/src/views/lucky/Index.vue
Normal file
118
Yi.Bbs.Vue3/src/views/lucky/Index.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>谨记人生赌博,不如理性规划</h2>
|
||||
<h3>50钱钱一次,我的钱钱:{{ userInfo?.money ?? '未登录' }}</h3>
|
||||
<LuckyWheel class="wheel" ref="myLucky" width="500px" height="500px" :prizes="prizes" :blocks="blocks"
|
||||
:buttons="buttons" @start="startCallback" @end="endCallback" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import useAuths from '@/hooks/useAuths.js';
|
||||
const { isLogin } = useAuths();
|
||||
import { getBbsUserProfile } from '@/apis/userApi.js'
|
||||
import { luckyWheel } from '@/apis/integralApi.js'
|
||||
import useUserStore from "@/stores/user";
|
||||
const userInfo = ref({});
|
||||
const currentUserInfo=useUserStore();
|
||||
onMounted(async () => {
|
||||
await loadUserInfoData();
|
||||
})
|
||||
const loadUserInfoData = async () => {
|
||||
if (isLogin) {
|
||||
const { data } = await getBbsUserProfile(currentUserInfo.id);
|
||||
userInfo.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
const blocks = [{ padding: '13px', background: '#617df2' }];
|
||||
const prizes = [
|
||||
{ fonts: [{ text: '啥也没有', top: '10%' }], background: '#e9e8fe' },
|
||||
{ fonts: [{ text: '10', top: '10%' }], background: '#b8c5f2' },
|
||||
{ fonts: [{ text: '30', top: '10%' }], background: '#e9e8fe' },
|
||||
{ fonts: [{ text: '50', top: '10%' }], background: '#b8c5f2' },
|
||||
{ fonts: [{ text: '80', top: '10%' }], background: '#e9e8fe' },
|
||||
{ fonts: [{ text: '100', top: '10%' }], background: '#b8c5f2' },
|
||||
{ fonts: [{ text: '150', top: '10%' }], background: '#e9e8fe' },
|
||||
{ fonts: [{ text: '200', top: '10%' }], background: '#b8c5f2' },
|
||||
{ fonts: [{ text: '300', top: '10%' }], background: '#e9e8fe' },
|
||||
{ fonts: [{ text: '666', top: '10%' }], background: '#FAD400' }
|
||||
];
|
||||
const buttons = [{
|
||||
radius: '35%',
|
||||
background: '#8a9bf3',
|
||||
pointer: true,
|
||||
fonts: [{ text: '启动', top: '-10px' }]
|
||||
}];
|
||||
|
||||
const myLucky = ref(null);
|
||||
// 点击抽奖按钮会触发star回调
|
||||
const startCallback = () => {
|
||||
var index =0;
|
||||
// 调用抽奖组件的play方法开始游戏
|
||||
if (!isLogin) {
|
||||
ElMessage({
|
||||
message: '请登录后启动!',
|
||||
type: 'warning',
|
||||
})
|
||||
return;
|
||||
}
|
||||
ElMessageBox.confirm(
|
||||
'每次启动需要消耗50钱钱,确定要启动吗?',
|
||||
'警告',
|
||||
{
|
||||
confirmButtonText: '启动',
|
||||
cancelButtonText: '放弃',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
myLucky.value.play()
|
||||
|
||||
|
||||
|
||||
|
||||
//等待3秒
|
||||
// 模拟调用接口异步抽奖
|
||||
setTimeout(() => {
|
||||
// 假设后端返回的中奖索引是0
|
||||
// 调用stop停止旋转并传递中奖索引
|
||||
}, 3000)
|
||||
index= (await luckyWheel()).data;
|
||||
myLucky.value.stop(index)
|
||||
|
||||
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '成功克制',
|
||||
})
|
||||
})
|
||||
|
||||
};
|
||||
// 抽奖结束会触发end回调
|
||||
const endCallback = async (prize) => {
|
||||
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: `恭喜你抽中了[${prize.fonts[0].text}]`,
|
||||
})
|
||||
await loadUserInfoData();
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.wheel {
|
||||
margin: auto;
|
||||
margin-top: 10%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -34,6 +34,7 @@
|
||||
import { onMounted, ref, reactive, computed, nextTick, watch } from "vue";
|
||||
import { signIn, signInRecord } from "@/apis/integralApi.js";
|
||||
import useAuths from "@/hooks/useAuths";
|
||||
|
||||
const { isLogin } = useAuths();
|
||||
const number=ref(0);
|
||||
const signInData=ref([]);
|
||||
|
||||
@@ -286,6 +286,15 @@
|
||||
"@jridgewell/resolve-uri" "3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
||||
|
||||
"@lucky-canvas/vue@^0.1.11":
|
||||
"integrity" "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg=="
|
||||
"resolved" "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz"
|
||||
"version" "0.1.11"
|
||||
dependencies:
|
||||
"@vue/composition-api" "^1.0.0"
|
||||
"lucky-canvas" "^1.7.23"
|
||||
"vue-demi" "^0.7.4"
|
||||
|
||||
"@microsoft/signalr@^8.0.0":
|
||||
"integrity" "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA=="
|
||||
"resolved" "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz"
|
||||
@@ -475,6 +484,11 @@
|
||||
"@vue/compiler-dom" "3.2.47"
|
||||
"@vue/shared" "3.2.47"
|
||||
|
||||
"@vue/composition-api@^1.0.0", "@vue/composition-api@^1.0.0-beta.1":
|
||||
"integrity" "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw=="
|
||||
"resolved" "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz"
|
||||
"version" "1.7.2"
|
||||
|
||||
"@vue/devtools-api@^6.4.5", "@vue/devtools-api@^6.5.0":
|
||||
"integrity" "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
|
||||
"resolved" "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz"
|
||||
@@ -1499,6 +1513,11 @@
|
||||
dependencies:
|
||||
"yallist" "^4.0.0"
|
||||
|
||||
"lucky-canvas@^1.7.23":
|
||||
"integrity" "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ=="
|
||||
"resolved" "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz"
|
||||
"version" "1.7.27"
|
||||
|
||||
"magic-string@^0.25.7":
|
||||
"integrity" "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="
|
||||
"resolved" "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz"
|
||||
@@ -2239,6 +2258,11 @@
|
||||
"resolved" "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz"
|
||||
"version" "0.13.11"
|
||||
|
||||
"vue-demi@^0.7.4":
|
||||
"integrity" "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ=="
|
||||
"resolved" "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz"
|
||||
"version" "0.7.5"
|
||||
|
||||
"vue-router@^4.1.6":
|
||||
"integrity" "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ=="
|
||||
"resolved" "https://registry.npmmirror.com/vue-router/-/vue-router-4.1.6.tgz"
|
||||
@@ -2246,7 +2270,7 @@
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.4.5"
|
||||
|
||||
"vue@^2.6.14 || ^3.2.0", "vue@^3.0.0-0 || ^2.6.0", "vue@^3.2.0", "vue@^3.2.23", "vue@^3.2.25", "vue@^3.2.47", "vue@2 || 3", "vue@3.2.47":
|
||||
"vue@^2.0.0 || >=3.0.0-rc.0", "vue@^2.6.0 || >=3.0.0-rc.1", "vue@^2.6.14 || ^3.2.0", "vue@^3.0.0-0 || ^2.6.0", "vue@^3.2.0", "vue@^3.2.23", "vue@^3.2.25", "vue@^3.2.47", "vue@>= 2.5 < 2.7", "vue@2 || 3", "vue@3.2.47":
|
||||
"integrity" "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ=="
|
||||
"resolved" "https://registry.npmmirror.com/vue/-/vue-3.2.47.tgz"
|
||||
"version" "3.2.47"
|
||||
|
||||
41
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/00.模块与项目.md
Normal file
41
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/00.模块与项目.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## 模块与项目
|
||||
意框架是一个基于Abp.VNext的框架,完美使用模块化理念进行开发。既然是模块化开发,就有`项目`与`项目`的概念。
|
||||
|
||||
很多人问到了我,我的代码应该放到哪里,其实是没有分清楚模块与项目,弄清楚这个,再下手撸码,才更有方向。
|
||||
|
||||
其实不必一堆概念,只需要心中思考一下
|
||||
|
||||
> 我接下来要开发的业务是否有必要被其他项目依赖使用?
|
||||
|
||||
例如:内置的Rbac模块、Bbs模块,单独具备权限管理和社区论坛的功能,公开给大家复用引用,这就可以当成一个模块
|
||||
|
||||
`但是`,有时候如果我不认为他有必要复用,就是公司的一个内部系统,想要快速开发并交付,要同时具备权限管理、商城、审批等各种功能,那就直接当一个项目开发即可,不一定需要将各个模块拆的太散
|
||||
|
||||
> 这个划分的界限,是由项目来决定
|
||||
|
||||
注意:模块的代码与项目的代码结构几乎没有区别
|
||||
|
||||
这意味,有一个最好的方式,先将业务全部写在项目中,等稳定之后,在复制抽象到模块中,完全没有问题。
|
||||
|
||||
### 模块的优缺点
|
||||
- 优点:高度抽象复用
|
||||
- 缺点:肉眼可见的程序集增加、维护成本更高
|
||||
|
||||
### 模块
|
||||

|
||||
|
||||
代码位置放在`module`目录下,单独建立一个自己的模块名称,可使用`脚手架使用`将默认代码生成在这里。
|
||||
|
||||
### 项目
|
||||

|
||||
|
||||
框架内置一个host项目,代码位置存放在`src`中,直接使用即可,如果想更换命名,可以使用上一节的`脚手架使用`。
|
||||
|
||||
## 总结
|
||||
> 由于很多人询问我这个问题,所以单独写一篇,方便大家理解。
|
||||
|
||||
先区分模块还是项目,然后代码写到对应的位置即可
|
||||
|
||||
理论上,按这套规则意味着,只有在自己的`module`、`src`下才需要写代码,其他地方都是内置好了的,通过继承、实现等方式扩展即可
|
||||
|
||||
当然,你可以不按这套规则出发,目录结构按自己的舒服的方式去设计,当然也是可以的,不过这得花费一些时间了。
|
||||
0
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/01.依赖关系.md
Normal file
0
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/01.依赖关系.md
Normal file
BIN
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image-1.png
Normal file
BIN
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
BIN
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image.png
Normal file
BIN
Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
34
Yi.Doc.Md/01.框架快速开始教程/05.脚手架使用.md
Normal file
34
Yi.Doc.Md/01.框架快速开始教程/05.脚手架使用.md
Normal file
@@ -0,0 +1,34 @@
|
||||
## 简介
|
||||
上节说到,真正关注的代码其实只用在src中
|
||||

|
||||
当我们要新建一个项目或者模块的时候,并不想取这个`Yi.Abp`的名字,我们可以使用dotnet的脚手架进行模板的生成
|
||||
|
||||
**环境**:只需要dotnet sdk即可
|
||||
|
||||
## 步骤
|
||||

|
||||
在模板文件目录上,有一个`.template.config`文件夹,就是通过这个进行控制模板的生成及替换
|
||||
|
||||
进入该目录,使用cmd执行以以下命令:
|
||||
``` shell
|
||||
dotnet new install . --force
|
||||
```
|
||||
|
||||

|
||||
|
||||
出现 `已安装以下模板` 及代表安装完成
|
||||
|
||||
>我们只需要安装一次即可,如果模板文件发生变化,我们生成出来的文件也是一样会变化的
|
||||
|
||||
当模板安装完成,接下来我们可以选择一个自己想要的空白文件夹,输入命令:
|
||||
|
||||
``` shell
|
||||
dotnet new yi --name=Acme.BookStore
|
||||
#Acme.BookStore可以替换成你想要生成的名称即可
|
||||
```
|
||||
|
||||

|
||||
|
||||
最后查看目录:
|
||||

|
||||
这个便是我们想要的结果了
|
||||
@@ -35,15 +35,15 @@ export function getCacheValue(cacheName, cacheKey) {
|
||||
// 清理指定名称缓存
|
||||
export function clearCacheName(cacheName) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheName/' + cacheName,
|
||||
url: '/monitor-cache/key/' + cacheName,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 清理指定键名缓存
|
||||
export function clearCacheKey(cacheKey) {
|
||||
export function clearCacheKey(cacheName,cacheKey) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheKey/' + cacheKey,
|
||||
url: '/monitor-cache/value/'+cacheName+'/' + cacheKey,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export function clearCacheKey(cacheKey) {
|
||||
// 清理全部缓存
|
||||
export function clearCacheAll() {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheAll',
|
||||
url: '/monitor-cache/clear',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ import request from '@/utils/request'
|
||||
// 查询公告列表
|
||||
export function listNotice(query) {
|
||||
return request({
|
||||
url: '/system/notice/list',
|
||||
url: '/notice',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询公告详细
|
||||
export function getNotice(noticeId) {
|
||||
export function getNotice(id) {
|
||||
return request({
|
||||
url: '/system/notice/' + noticeId,
|
||||
url: `/notice/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -20,26 +20,41 @@ export function getNotice(noticeId) {
|
||||
// 新增公告
|
||||
export function addNotice(data) {
|
||||
return request({
|
||||
url: '/system/notice',
|
||||
url: '/notice',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改公告
|
||||
export function updateNotice(data) {
|
||||
export function updateNotice(id,data) {
|
||||
return request({
|
||||
url: '/system/notice',
|
||||
url: `/notice/${id}`,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公告
|
||||
export function delNotice(noticeId) {
|
||||
export function delNotice(ids) {
|
||||
return request({
|
||||
url: '/system/notice',
|
||||
url: `/notice`,
|
||||
method: 'delete',
|
||||
params:{id:noticeId}
|
||||
params:{id:ids}
|
||||
})
|
||||
}
|
||||
|
||||
// 发送在线公告
|
||||
export function sendOnlineNotice(id) {
|
||||
return request({
|
||||
url: '/notice/online/'+id,
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
// 发送离线公告
|
||||
export function sendOfflineNotice(id) {
|
||||
return request({
|
||||
url: '/notice/offline/'+id,
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<transition name="slide-fade" mode="out-in">
|
||||
<keep-alive :include="tagsViewStore.cachedViews">
|
||||
<component v-if="!route.meta.link" :is="Component" :key="route.path"/>
|
||||
</keep-alive>
|
||||
@@ -19,6 +19,24 @@ const tagsViewStore = useTagsViewStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/*
|
||||
进入和离开动画可以使用不同
|
||||
持续时间和速度曲线。
|
||||
*/
|
||||
.slide-fade-enter-active {
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
|
||||
}
|
||||
|
||||
.slide-fade-enter-from,
|
||||
.slide-fade-leave-to {
|
||||
transform: translateX(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
/* 50= navbar 50 */
|
||||
min-height: calc(100vh - 50px);
|
||||
|
||||
@@ -374,7 +374,8 @@ const handleCodeToWeb = async () => {
|
||||
/** CodeToWeb */
|
||||
const handleWebToCode = async () => {
|
||||
const response= await webToCode(ids.value);
|
||||
if(response.statusCode==200)
|
||||
console.log(response,"response");
|
||||
if(response.status==200||response.status==204)
|
||||
{
|
||||
proxy.$modal.msgSuccess("代码生成成功");
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ function refreshCacheKeys() {
|
||||
|
||||
/** 清理指定键名缓存 */
|
||||
function handleClearCacheKey(cacheKey) {
|
||||
clearCacheKey(cacheKey).then(response => {
|
||||
clearCacheKey(nowCacheName.value,cacheKey).then(response => {
|
||||
proxy.$modal.msgSuccess("清理缓存键名[" + cacheKey + "]成功");
|
||||
getCacheKeys();
|
||||
});
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-form-item label="公告标题" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.noticeTitle"
|
||||
v-model="queryParams.title"
|
||||
placeholder="请输入公告标题"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人员" prop="createBy">
|
||||
<el-input
|
||||
v-model="queryParams.createBy"
|
||||
placeholder="请输入操作人员"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="noticeType">
|
||||
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="queryParams.type" placeholder="公告类型" clearable>
|
||||
<el-option
|
||||
v-for="dict in sys_notice_type"
|
||||
:key="dict.value"
|
||||
@@ -68,31 +60,47 @@
|
||||
|
||||
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" prop="noticeId" width="100" />
|
||||
<el-table-column label="序号" align="center" prop="id" width="300" />
|
||||
<el-table-column
|
||||
label="公告标题"
|
||||
align="center"
|
||||
prop="noticeTitle"
|
||||
prop="title"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
|
||||
<el-table-column label="公告类型" align="center" prop="type" width="100">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_notice_type" :value="scope.row.noticeType" />
|
||||
<dict-tag :options="sys_notice_type" :value="scope.row.type" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" width="100">
|
||||
<el-table-column label="状态" align="center" prop="state" width="100">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_notice_status" :value="scope.row.status" />
|
||||
<el-tag type="info">{{sys_notice_state.filter(x=>x.value==scope.row.state)[0]?.label}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建者" align="center" prop="createBy" width="100" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
|
||||
<el-table-column label="创建时间" align="center" prop="creationTime" width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
||||
<span>{{ parseTime(scope.row.creationTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
icon="Promotion"
|
||||
@click="handleOnlineSend(scope.row.id)"
|
||||
v-hasPermi="['system:notice:edit']"
|
||||
>在线发送</el-button>
|
||||
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
icon="Promotion"
|
||||
@click="handleOfflineSend(scope.row.id)"
|
||||
v-hasPermi="['system:notice:edit']"
|
||||
>离线发送</el-button>
|
||||
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
icon="Edit"
|
||||
@@ -122,13 +130,13 @@
|
||||
<el-form ref="noticeRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
|
||||
<el-form-item label="公告标题" prop="title">
|
||||
<el-input v-model="form.title" placeholder="请输入公告标题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="公告类型" prop="noticeType">
|
||||
<el-select v-model="form.noticeType" placeholder="请选择">
|
||||
<el-form-item label="公告类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in sys_notice_type"
|
||||
:key="dict.value"
|
||||
@@ -140,9 +148,9 @@
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio-group v-model="form.state">
|
||||
<el-radio
|
||||
v-for="dict in sys_notice_status"
|
||||
v-for="dict in sys_notice_state"
|
||||
:key="dict.value"
|
||||
:label="dict.value"
|
||||
>{{ dict.label }}</el-radio>
|
||||
@@ -155,7 +163,7 @@
|
||||
:rows="6"
|
||||
type="textarea"
|
||||
placeholder="请输入内容"
|
||||
v-model="form.noticeContent"
|
||||
v-model="form.content"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -172,11 +180,17 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Notice">
|
||||
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
|
||||
import { sendOnlineNotice,sendOfflineNotice,listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { sys_notice_status, sys_notice_type } = proxy.useDict("sys_notice_status", "sys_notice_type");
|
||||
|
||||
const sys_notice_state=[
|
||||
{label:'启用',value:true},
|
||||
{label:'停用',value:false}
|
||||
];
|
||||
const sys_notice_type=[
|
||||
{label:'走马灯',value:'MerryGoRound'},
|
||||
{label:'提示弹窗',value:'Popup'}
|
||||
];
|
||||
const noticeList = ref([]);
|
||||
const open = ref(false);
|
||||
const loading = ref(true);
|
||||
@@ -192,13 +206,13 @@ const data = reactive({
|
||||
queryParams: {
|
||||
skipCount: 1,
|
||||
maxResultCount: 10,
|
||||
noticeTitle: undefined,
|
||||
title: undefined,
|
||||
createBy: undefined,
|
||||
status: undefined
|
||||
state: undefined
|
||||
},
|
||||
rules: {
|
||||
noticeTitle: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
|
||||
noticeType: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
|
||||
title: [{ required: true, message: "公告标题不能为空", trigger: "blur" }],
|
||||
type: [{ required: true, message: "公告类型不能为空", trigger: "change" }]
|
||||
},
|
||||
});
|
||||
|
||||
@@ -208,8 +222,8 @@ const { queryParams, form, rules } = toRefs(data);
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
listNotice(queryParams.value).then(response => {
|
||||
noticeList.value = response.rows;
|
||||
total.value = response.total;
|
||||
noticeList.value = response.data.items;
|
||||
total.value = response.data.totalCount;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
@@ -221,11 +235,11 @@ function cancel() {
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
noticeId: undefined,
|
||||
noticeTitle: undefined,
|
||||
noticeType: undefined,
|
||||
noticeContent: undefined,
|
||||
status: "0"
|
||||
id: undefined,
|
||||
title: undefined,
|
||||
type: undefined,
|
||||
content: undefined,
|
||||
state: true
|
||||
};
|
||||
proxy.resetForm("noticeRef");
|
||||
}
|
||||
@@ -241,7 +255,7 @@ function resetQuery() {
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.noticeId);
|
||||
ids.value = selection.map(item => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
@@ -254,8 +268,8 @@ function handleAdd() {
|
||||
/**修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
const noticeId = row.noticeId || ids.value;
|
||||
getNotice(noticeId).then(response => {
|
||||
const id = row.id || ids.value;
|
||||
getNotice(id).then(response => {
|
||||
form.value = response.data;
|
||||
open.value = true;
|
||||
title.value = "修改公告";
|
||||
@@ -265,12 +279,13 @@ function handleUpdate(row) {
|
||||
function submitForm() {
|
||||
proxy.$refs["noticeRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.noticeId != undefined) {
|
||||
updateNotice(form.value).then(response => {
|
||||
if (form.value.id != undefined) {
|
||||
updateNotice(form.value.id,form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
|
||||
} else {
|
||||
addNotice(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
@@ -283,14 +298,23 @@ function submitForm() {
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const noticeIds = row.noticeId || ids.value
|
||||
proxy.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
|
||||
return delNotice(noticeIds);
|
||||
const ids2 = row.id || ids.value
|
||||
proxy.$modal.confirm('是否确认删除公告编号为"' + ids2 + '"的数据项?').then(function() {
|
||||
return delNotice(ids2);
|
||||
}).then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
const handleOnlineSend=async (id)=>{
|
||||
await sendOnlineNotice(id);
|
||||
proxy.$modal.msgSuccess("在线消息发送成功");
|
||||
|
||||
}
|
||||
const handleOfflineSend=async (id)=>{
|
||||
await sendOfflineNotice(id);
|
||||
proxy.$modal.msgSuccess("离线消息发送成功");
|
||||
}
|
||||
getList();
|
||||
</script>
|
||||
|
||||
@@ -211,11 +211,11 @@ const deptRef = ref(null);
|
||||
|
||||
/** 数据范围选项*/
|
||||
const dataScopeOptions = ref([
|
||||
{ value: 0, label: "全部数据权限" },
|
||||
{ value: 1, label: "自定数据权限" },
|
||||
{ value: 2, label: "本部门数据权限" },
|
||||
{ value: 3, label: "本部门及以下数据权限" },
|
||||
{ value: 4, label: "仅本人数据权限" },
|
||||
{ value: 'ALL', label: "全部数据权限" },
|
||||
{ value: 'CUSTOM', label: "自定数据权限" },
|
||||
{ value: 'DEPT', label: "本部门数据权限" },
|
||||
{ value: 'DEPT_FOLLOW', label: "本部门及以下数据权限" },
|
||||
{ value: 'USER', label: "仅本人数据权限" },
|
||||
]);
|
||||
|
||||
const data = reactive({
|
||||
|
||||
Reference in New Issue
Block a user