mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-04-17 06:36:36 +08:00
Compare commits
75 Commits
abp-dev-10
...
dev-Entity
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dfaf75440 | ||
|
|
6be5398114 | ||
|
|
3932b24fda | ||
|
|
356938d6d3 | ||
|
|
1090907178 | ||
|
|
da2f7073f9 | ||
|
|
f656ec32c1 | ||
|
|
1cc0ef916f | ||
|
|
5d793344cd | ||
|
|
bcaca0b782 | ||
|
|
5cee7319c6 | ||
|
|
e960db0d3e | ||
|
|
eb2c05e9df | ||
|
|
353a6b9d0c | ||
|
|
5d2d269f11 | ||
|
|
9acb157fae | ||
|
|
4198b53996 | ||
|
|
fdec9ed6b8 | ||
|
|
84cd83894b | ||
|
|
18dd177961 | ||
|
|
41f91ea12d | ||
|
|
91bf5f93cd | ||
|
|
9445fa8005 | ||
|
|
6b491d1246 | ||
|
|
6b47ae232d | ||
|
|
536c3cc56b | ||
|
|
b75a8cb60d | ||
|
|
17bc4ade84 | ||
|
|
aea0896356 | ||
|
|
ae82a2d1cf | ||
|
|
2412bc1da4 | ||
|
|
42b00515eb | ||
|
|
f3c5d0862b | ||
|
|
e832921edf | ||
|
|
0c0ead26c0 | ||
|
|
f9a018638b | ||
|
|
d5ca8ddf1e | ||
|
|
650c29e75a | ||
|
|
ed5c20c612 | ||
|
|
49f1d1a8fa | ||
|
|
a87d6345c2 | ||
|
|
d83db53acb | ||
|
|
c944bd3b0e | ||
|
|
751cc3cadb | ||
|
|
80fe1116a8 | ||
|
|
9aaa88ef51 | ||
|
|
ef2d00a254 | ||
|
|
d38159f68b | ||
|
|
dd29c9a2fa | ||
|
|
ca1b8a728d | ||
|
|
6b647cf4ea | ||
|
|
0e6f79c28e | ||
|
|
894d4eb051 | ||
|
|
8d9c5bb762 | ||
|
|
7a916fc78e | ||
|
|
73db2a202a | ||
|
|
f9890bdc7f | ||
|
|
8a0c0de8a1 | ||
|
|
8c940126b5 | ||
|
|
71b7b7cc79 | ||
|
|
f6be4ad7ac | ||
|
|
f6cbe899c6 | ||
|
|
7598c8319f | ||
|
|
a798f36529 | ||
|
|
59d9674aeb | ||
|
|
36ed5400be | ||
|
|
6378c69764 | ||
|
|
b44db20938 | ||
|
|
61cd7b42d4 | ||
|
|
77d64796e0 | ||
|
|
a4001c21b1 | ||
|
|
9e1d01774f | ||
|
|
be4f0a2a90 | ||
|
|
c45c17748e | ||
|
|
57ad7ae1a3 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -269,6 +269,7 @@ dist
|
|||||||
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json
|
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json
|
||||||
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Development.json
|
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Development.json
|
||||||
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Production.json
|
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Production.json
|
||||||
|
/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json
|
||||||
database_backup
|
database_backup
|
||||||
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Staging.json
|
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Staging.json
|
||||||
/Yi.Abp.Net8/src/Yi.Abp.Web/logs/
|
/Yi.Abp.Net8/src/Yi.Abp.Web/logs/
|
||||||
|
|||||||
@@ -80,20 +80,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.S
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore.Authentication.OAuth", "framework\Yi.Framework.AspNetCore.Authentication.OAuth\Yi.Framework.AspNetCore.Authentication.OAuth.csproj", "{791AC2FA-50D3-4408-8D68-31DA72F608BE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore.Authentication.OAuth", "framework\Yi.Framework.AspNetCore.Authentication.OAuth\Yi.Framework.AspNetCore.Authentication.OAuth.csproj", "{791AC2FA-50D3-4408-8D68-31DA72F608BE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{01300F0F-686E-47B3-821D-12424177867B}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Web", "sample\Acme.BookStore.Web\Acme.BookStore.Web.csproj", "{576DBC97-4E5D-4444-B65C-F41649A5F8E0}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Shared", "sample\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj", "{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain", "sample\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj", "{B615847F-8568-41D1-8B7E-63D61AE69F3D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Contracts", "sample\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj", "{20827DB5-5CDE-491A-82E8-3CAB82618C1E}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application", "sample\Acme.BookStore.Application\Acme.BookStore.Application.csproj", "{320273B6-7AE3-42DA-9675-D9AD4928A289}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.SqlSugarCore", "sample\Acme.BookStore.SqlSugarCore\Acme.BookStore.SqlSugarCore.csproj", "{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Test", "test\Yi.Abp.Test\Yi.Abp.Test.csproj", "{68627BC2-F049-4C69-AD17-81DF9478E8CE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Test", "test\Yi.Abp.Test\Yi.Abp.Test.csproj", "{68627BC2-F049-4C69-AD17-81DF9478E8CE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{499A8C71-7892-42D0-A77E-48756E1EFF16}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{499A8C71-7892-42D0-A77E-48756E1EFF16}"
|
||||||
@@ -170,6 +156,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.HttpApi.Client"
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.BackgroundWorkers.Hangfire", "framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj", "{862CA181-BEE6-4870-82D2-B662E527ED8C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -276,30 +264,6 @@ Global
|
|||||||
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -428,6 +392,10 @@ Global
|
|||||||
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -461,12 +429,6 @@ Global
|
|||||||
{73CCF2C4-B9FD-44AB-8D4B-0A421805B094} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
{73CCF2C4-B9FD-44AB-8D4B-0A421805B094} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
|
||||||
{791AC2FA-50D3-4408-8D68-31DA72F608BE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
{576DBC97-4E5D-4444-B65C-F41649A5F8E0} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{B615847F-8568-41D1-8B7E-63D61AE69F3D} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{20827DB5-5CDE-491A-82E8-3CAB82618C1E} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{320273B6-7AE3-42DA-9675-D9AD4928A289} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7} = {01300F0F-686E-47B3-821D-12424177867B}
|
|
||||||
{68627BC2-F049-4C69-AD17-81DF9478E8CE} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
|
||||||
{499A8C71-7892-42D0-A77E-48756E1EFF16} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
{499A8C71-7892-42D0-A77E-48756E1EFF16} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
||||||
@@ -503,6 +465,7 @@ Global
|
|||||||
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
|
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
|
||||||
|
|||||||
@@ -9,84 +9,89 @@ using Microsoft.OpenApi.Any;
|
|||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Volo.Abp.AspNetCore.Mvc;
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Options;
|
||||||
|
|
||||||
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class SwaggerAddExtensions
|
public static class SwaggerAddExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services, Action<SwaggerGenOptions>? action=null)
|
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services,
|
||||||
|
Action<SwaggerGenOptions>? action = null)
|
||||||
{
|
{
|
||||||
|
var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
|
||||||
var mvcOptions = serviceProvider.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
|
var mvcSettings =
|
||||||
|
mvcOptions.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
||||||
var mvcSettings = mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
|
||||||
|
|
||||||
|
|
||||||
services.AddAbpSwaggerGen(
|
services.AddAbpSwaggerGen(
|
||||||
options =>
|
options =>
|
||||||
{
|
|
||||||
if (action is not null)
|
|
||||||
{
|
{
|
||||||
action.Invoke(options);
|
if (action is not null)
|
||||||
}
|
|
||||||
|
|
||||||
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
|
||||||
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
|
||||||
{
|
|
||||||
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
|
||||||
{
|
{
|
||||||
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
action.Invoke(options);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 根据分组名称过滤 API 文档
|
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
||||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
||||||
{
|
|
||||||
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
|
||||||
{
|
{
|
||||||
var settingOrNull = mvcSettings.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly).FirstOrDefault();
|
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
||||||
if (settingOrNull is not null)
|
|
||||||
{
|
{
|
||||||
return docName == settingOrNull.RemoteServiceName;
|
options.SwaggerDoc(setting.RemoteServiceName,
|
||||||
|
new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
options.CustomSchemaIds(type => type.FullName);
|
// 根据分组名称过滤 API 文档
|
||||||
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||||
if (basePath is not null)
|
|
||||||
{
|
|
||||||
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
|
||||||
{
|
{
|
||||||
options.IncludeXmlComments(item, true);
|
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
||||||
|
{
|
||||||
|
var settingOrNull = mvcSettings
|
||||||
|
.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly)
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (settingOrNull is not null)
|
||||||
|
{
|
||||||
|
return docName == settingOrNull.RemoteServiceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
options.CustomSchemaIds(type => type.FullName);
|
||||||
|
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
||||||
|
if (basePath is not null)
|
||||||
|
{
|
||||||
|
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
||||||
|
{
|
||||||
|
options.IncludeXmlComments(item, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Description = "直接输入Token即可",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "bearer"
|
||||||
|
});
|
||||||
|
var scheme = new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
||||||
|
};
|
||||||
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
|
{
|
||||||
|
[scheme] = new string[0]
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AddRequiredHeaderParameter>();
|
||||||
|
options.SchemaFilter<EnumSchemaFilter>();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
|
||||||
{
|
|
||||||
Description = "直接输入Token即可",
|
|
||||||
Name = "Authorization",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Type = SecuritySchemeType.Http,
|
|
||||||
Scheme = "bearer"
|
|
||||||
});
|
|
||||||
var scheme = new OpenApiSecurityScheme()
|
|
||||||
{
|
|
||||||
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
|
||||||
};
|
|
||||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
|
||||||
{
|
|
||||||
[scheme] = new string[0]
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AddRequiredHeaderParameter>();
|
|
||||||
options.SchemaFilter<EnumSchemaFilter>();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
@@ -103,7 +108,6 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model"></param>
|
/// <param name="model"></param>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
|
|
||||||
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
||||||
{
|
{
|
||||||
if (context.Type.IsEnum)
|
if (context.Type.IsEnum)
|
||||||
@@ -112,7 +116,7 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
model.Type = "string";
|
model.Type = "string";
|
||||||
model.Format = null;
|
model.Format = null;
|
||||||
|
|
||||||
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
Enum.GetNames(context.Type)
|
Enum.GetNames(context.Type)
|
||||||
.ToList()
|
.ToList()
|
||||||
@@ -121,9 +125,10 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
Enum e = (Enum)Enum.Parse(context.Type, name);
|
Enum e = (Enum)Enum.Parse(context.Type, name);
|
||||||
var descrptionOrNull = GetEnumDescription(e);
|
var descrptionOrNull = GetEnumDescription(e);
|
||||||
model.Enum.Add(new OpenApiString(name));
|
model.Enum.Add(new OpenApiString(name));
|
||||||
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
stringBuilder.Append(
|
||||||
|
$"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
||||||
});
|
});
|
||||||
model.Description= stringBuilder.ToString();
|
model.Description = stringBuilder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,13 +138,13 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||||
return attributes.Length > 0 ? attributes[0].Description : null;
|
return attributes.Length > 0 ? attributes[0].Description : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class AddRequiredHeaderParameter : IOperationFilter
|
public class AddRequiredHeaderParameter : IOperationFilter
|
||||||
{
|
{
|
||||||
public static string HeaderKey { get; set; } = "__tenant";
|
public static string HeaderKey { get; set; } = "__tenant";
|
||||||
|
|
||||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
{
|
{
|
||||||
if (operation.Parameters == null)
|
if (operation.Parameters == null)
|
||||||
@@ -150,8 +155,8 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
In = ParameterLocation.Header,
|
In = ParameterLocation.Header,
|
||||||
Required = false,
|
Required = false,
|
||||||
AllowEmptyValue = true,
|
AllowEmptyValue = true,
|
||||||
Description="租户id或者租户名称(可空为默认租户)"
|
Description = "租户id或者租户名称(可空为默认租户)"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore;
|
||||||
|
|
||||||
|
public class RealIpHttpContextWebClientInfoProvider : HttpContextWebClientInfoProvider
|
||||||
|
{
|
||||||
|
public RealIpHttpContextWebClientInfoProvider(ILogger<HttpContextWebClientInfoProvider> logger,
|
||||||
|
IHttpContextAccessor httpContextAccessor) : base(logger, httpContextAccessor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string? GetClientIpAddress()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpContext = HttpContextAccessor.HttpContext;
|
||||||
|
|
||||||
|
var headers = httpContext?.Request?.Headers;
|
||||||
|
|
||||||
|
if (headers != null && headers.ContainsKey("X-Forwarded-For"))
|
||||||
|
{
|
||||||
|
httpContext.Connection.RemoteIpAddress =
|
||||||
|
IPAddress.Parse(headers["X-Forwarded-For"].FirstOrDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpContext?.Connection?.RemoteIpAddress?.ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogException(ex, LogLevel.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.AspNetCore.Mvc;
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
using Yi.Framework.AspNetCore.Mvc;
|
using Yi.Framework.AspNetCore.Mvc;
|
||||||
@@ -22,6 +23,11 @@ namespace Yi.Framework.AspNetCore
|
|||||||
)]
|
)]
|
||||||
public class YiFrameworkAspNetCoreModule : AbpModule
|
public class YiFrameworkAspNetCoreModule : AbpModule
|
||||||
{
|
{
|
||||||
|
public override void PostConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
var services = context.Services;
|
||||||
|
services.Replace(new ServiceDescriptor(typeof(IWebClientInfoProvider),
|
||||||
|
typeof(RealIpHttpContextWebClientInfoProvider), ServiceLifetime.Transient));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using Hangfire.Server;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Threading;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
public class UnitOfWorkHangfireFilter : IServerFilter, ISingletonDependency
|
||||||
|
{
|
||||||
|
private const string CurrentJobUow = "HangfireUnitOfWork";
|
||||||
|
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
||||||
|
|
||||||
|
public UnitOfWorkHangfireFilter(IUnitOfWorkManager unitOfWorkManager)
|
||||||
|
{
|
||||||
|
_unitOfWorkManager = unitOfWorkManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPerforming(PerformingContext context)
|
||||||
|
{
|
||||||
|
var uow = _unitOfWorkManager.Begin();
|
||||||
|
context.Items.Add(CurrentJobUow, uow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPerformed(PerformedContext context)
|
||||||
|
{
|
||||||
|
AsyncHelper.RunSync(()=>OnPerformedAsync(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnPerformedAsync(PerformedContext context)
|
||||||
|
{
|
||||||
|
if (context.Items.TryGetValue(CurrentJobUow, out var obj)
|
||||||
|
&& obj is IUnitOfWork uow)
|
||||||
|
{
|
||||||
|
if (context.Exception == null && !uow.IsCompleted)
|
||||||
|
{
|
||||||
|
await uow.CompleteAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await uow.RollbackAsync();
|
||||||
|
}
|
||||||
|
uow.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Hangfire;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.BackgroundWorkers;
|
||||||
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
[DependsOn(typeof(AbpBackgroundWorkersHangfireModule))]
|
||||||
|
public class YiFrameworkBackgroundWorkersHangfireModule : AbpModule
|
||||||
|
{
|
||||||
|
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
|
{
|
||||||
|
//定时任务自动注入,Abp默认只有在Quartz才实现
|
||||||
|
var backgroundWorkerManager = context.ServiceProvider.GetRequiredService<IBackgroundWorkerManager>();
|
||||||
|
var works = context.ServiceProvider.GetServices<IHangfireBackgroundWorker>();
|
||||||
|
|
||||||
|
foreach (var work in works)
|
||||||
|
{
|
||||||
|
//如果为空,默认使用服务器本地utc时间
|
||||||
|
work.TimeZone ??= TimeZoneInfo.Local;
|
||||||
|
await backgroundWorkerManager.AddAsync(work);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
|
||||||
|
{
|
||||||
|
var services = context.ServiceProvider;
|
||||||
|
GlobalJobFilters.Filters.Add(services.GetRequiredService<UnitOfWorkHangfireFilter>());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
public class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar
|
||||||
|
{
|
||||||
|
protected override bool IsConventionalRegistrationDisabled(Type type)
|
||||||
|
{
|
||||||
|
return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) || base.IsConventionalRegistrationDisabled(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<Type> GetExposedServiceTypes(Type type)
|
||||||
|
{
|
||||||
|
return new List<Type>()
|
||||||
|
{
|
||||||
|
typeof(IHangfireBackgroundWorker)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using Hangfire.Dashboard;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, ITransientDependency
|
||||||
|
{
|
||||||
|
private const string Bearer = "Bearer: ";
|
||||||
|
private string RequireUser { get; set; } = "cc";
|
||||||
|
private TimeSpan ExpiresTime { get; set; } = TimeSpan.FromMinutes(10);
|
||||||
|
private IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public YiTokenAuthorizationFilter(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YiTokenAuthorizationFilter SetRequireUser(string userName)
|
||||||
|
{
|
||||||
|
RequireUser = userName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public YiTokenAuthorizationFilter SetExpiresTime(TimeSpan expiresTime)
|
||||||
|
{
|
||||||
|
ExpiresTime = expiresTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Authorize(DashboardContext context)
|
||||||
|
{
|
||||||
|
var httpContext = context.GetHttpContext();
|
||||||
|
var _currentUser = _serviceProvider.GetRequiredService<ICurrentUser>();
|
||||||
|
//如果验证通过,设置cookies
|
||||||
|
if (_currentUser.IsAuthenticated)
|
||||||
|
{
|
||||||
|
var cookieOptions = new CookieOptions
|
||||||
|
{
|
||||||
|
Expires = DateTimeOffset.Now + ExpiresTime, // 设置 cookie 过期时间,10分钟
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var authorization = httpContext.Request.Headers["Authorization"].ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(authorization))
|
||||||
|
{
|
||||||
|
var token = httpContext.Request.Headers["Authorization"].ToString().Substring(Bearer.Length - 1);
|
||||||
|
httpContext.Response.Cookies.Append("Token", token, cookieOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentUser.UserName == RequireUser)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetChallengeResponse(httpContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetChallengeResponse(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = 401;
|
||||||
|
httpContext.Response.ContentType = "text/html; charset=utf-8";
|
||||||
|
string html = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Token 输入</title>
|
||||||
|
<script>
|
||||||
|
function sendToken() {
|
||||||
|
// 获取输入的 token
|
||||||
|
var token = document.getElementById("tokenInput").value;
|
||||||
|
// 构建请求 URL
|
||||||
|
var url = "/hangfire";
|
||||||
|
// 发送 GET 请求
|
||||||
|
fetch(url,{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json', // 设置内容类型为 JSON
|
||||||
|
'Authorization': 'Bearer '+encodeURIComponent(token), // 设置授权头,例如使用 Bearer token
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.text(); // 或使用 response.json() 如果返回的是 JSON
|
||||||
|
}
|
||||||
|
throw new Error('Network response was not ok.');
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
// 处理成功返回的数据
|
||||||
|
document.open();
|
||||||
|
document.write(data);
|
||||||
|
document.close();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
// 处理错误
|
||||||
|
console.error('There has been a problem with your fetch operation:', error);
|
||||||
|
alert("请求失败: " + error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body style="text-align: center;">
|
||||||
|
<h1>Yi-hangfire</h1>
|
||||||
|
<h1>输入您的Token,我们将验证您是否为管理员</h1>
|
||||||
|
<input type="text" id="tokenInput" placeholder="请输入 token" />
|
||||||
|
<button onclick="sendToken()">校验</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""";
|
||||||
|
httpContext.Response.WriteAsync(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> AuthorizeAsync(DashboardContext context)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Authorize(context));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Json;
|
||||||
|
|
||||||
|
public class DatetimeJsonConverter : JsonConverter<DateTime>
|
||||||
|
{
|
||||||
|
private string _format;
|
||||||
|
public DatetimeJsonConverter(string format="yyyy-MM-dd HH:mm:ss")
|
||||||
|
{
|
||||||
|
_format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if(reader.TokenType==JsonTokenType.String)
|
||||||
|
{
|
||||||
|
if (DateTime.TryParse(reader.GetString(), out DateTime dateTime)) return dateTime;
|
||||||
|
}
|
||||||
|
return reader.GetDateTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(value.ToString(_format));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
using ArgumentException = System.ArgumentException;
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore.Abstractions
|
namespace Yi.Framework.SqlSugarCore.Abstractions
|
||||||
{
|
{
|
||||||
@@ -53,6 +54,5 @@ namespace Yi.Framework.SqlSugarCore.Abstractions
|
|||||||
/// 开启Saas多租户
|
/// 开启Saas多租户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnabledSaasMultiTenancy { get; set; } = false;
|
public bool EnabledSaasMultiTenancy { get; set; } = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using SqlSugar;
|
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore.Abstractions
|
|
||||||
{
|
|
||||||
public interface ISqlSugarDbConnectionCreator
|
|
||||||
{
|
|
||||||
DbConnOptions Options { get; }
|
|
||||||
Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }
|
|
||||||
Action<object, DataAfterModel> DataExecuted { get; set; }
|
|
||||||
Action<object, DataFilterModel> DataExecuting { get; set; }
|
|
||||||
Action<string, SugarParameter[]> OnLogExecuting { get; set; }
|
|
||||||
Action<string, SugarParameter[]> OnLogExecuted { get; set; }
|
|
||||||
Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
|
|
||||||
|
|
||||||
ConnectionConfig Build(Action<ConnectionConfig>? action = null);
|
|
||||||
void SetDbAop(ISqlSugarClient currentDb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,14 +10,14 @@ namespace Yi.Framework.SqlSugarCore.Abstractions
|
|||||||
{
|
{
|
||||||
public interface ISqlSugarDbContext
|
public interface ISqlSugarDbContext
|
||||||
{
|
{
|
||||||
// IAbpLazyServiceProvider LazyServiceProvider { get; set; }
|
/// <summary>
|
||||||
|
/// SqlSugarDb
|
||||||
|
/// </summary>
|
||||||
ISqlSugarClient SqlSugarClient { get; }
|
ISqlSugarClient SqlSugarClient { get; }
|
||||||
DbConnOptions Options { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据库备份
|
/// 数据库备份
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void BackupDataBase();
|
void BackupDataBase();
|
||||||
void SetSqlSugarClient(ISqlSugarClient sqlSugarClient);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
public interface ISqlSugarDbContextDependencies
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 执行顺序
|
||||||
|
/// </summary>
|
||||||
|
int ExecutionOrder { get; }
|
||||||
|
|
||||||
|
void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient);
|
||||||
|
void DataExecuted(object oldValue, DataAfterModel entityInfo);
|
||||||
|
void DataExecuting(object oldValue, DataFilterModel entityInfo);
|
||||||
|
|
||||||
|
void OnLogExecuting(string sql, SugarParameter[] pars);
|
||||||
|
void OnLogExecuted(string sql, SugarParameter[] pars);
|
||||||
|
|
||||||
|
void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo);
|
||||||
|
}
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Auditing;
|
||||||
|
using Volo.Abp.Data;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
using Volo.Abp.Domain.Entities.Events;
|
||||||
|
using Volo.Abp.Guids;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.SqlSugarCore;
|
||||||
|
|
||||||
|
public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||||
|
{
|
||||||
|
protected DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||||
|
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
||||||
|
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
|
||||||
|
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
|
||||||
|
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||||
|
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
||||||
|
public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
|
||||||
|
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
|
||||||
|
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
|
||||||
|
|
||||||
|
protected IEntityChangeEventHelper EntityChangeEventHelper =>
|
||||||
|
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
|
||||||
|
|
||||||
|
public DefaultSqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
if (IsSoftDeleteFilterEnabled)
|
||||||
|
{
|
||||||
|
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMultiTenantFilterEnabled)
|
||||||
|
{
|
||||||
|
//表达式里只能有具体值,不能运算
|
||||||
|
var expressionCurrentTenant = CurrentTenant.Id ?? null;
|
||||||
|
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == expressionCurrentTenant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DataExecuting(object oldValue, DataFilterModel entityInfo)
|
||||||
|
{
|
||||||
|
//审计日志
|
||||||
|
switch (entityInfo.OperationType)
|
||||||
|
{
|
||||||
|
case DataFilterType.UpdateByObject:
|
||||||
|
|
||||||
|
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
|
||||||
|
{
|
||||||
|
if (!DateTime.MinValue.Equals(oldValue))
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(DateTime.Now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
|
||||||
|
{
|
||||||
|
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||||
|
{
|
||||||
|
if (CurrentUser.Id != null)
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(CurrentUser.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DataFilterType.InsertByObject:
|
||||||
|
|
||||||
|
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
|
||||||
|
{
|
||||||
|
//类型为guid
|
||||||
|
if (typeof(Guid) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||||
|
{
|
||||||
|
//主键为空或者为默认最小值
|
||||||
|
if (Guid.Empty.Equals(oldValue))
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(GuidGenerator.Create());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
|
||||||
|
{
|
||||||
|
//为空或者为默认最小值
|
||||||
|
if (DateTime.MinValue.Equals(oldValue))
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(DateTime.Now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
|
||||||
|
{
|
||||||
|
//类型为guid
|
||||||
|
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||||
|
{
|
||||||
|
if (CurrentUser.Id is not null)
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(CurrentUser.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
|
||||||
|
{
|
||||||
|
if (CurrentTenant.Id is not null)
|
||||||
|
{
|
||||||
|
entityInfo.SetValue(CurrentTenant.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//实体变更领域事件
|
||||||
|
switch (entityInfo.OperationType)
|
||||||
|
{
|
||||||
|
case DataFilterType.InsertByObject:
|
||||||
|
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||||
|
{
|
||||||
|
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DataFilterType.UpdateByObject:
|
||||||
|
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||||
|
{
|
||||||
|
//软删除,发布的是删除事件
|
||||||
|
if (entityInfo.EntityValue is ISoftDelete softDelete)
|
||||||
|
{
|
||||||
|
if (softDelete.IsDeleted == true)
|
||||||
|
{
|
||||||
|
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DataFilterType.DeleteByObject:
|
||||||
|
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||||
|
{
|
||||||
|
//这里sqlsugar有个特殊,删除会返回批量的结果
|
||||||
|
if (entityInfo.EntityValue is IEnumerable entityValues)
|
||||||
|
{
|
||||||
|
foreach (var entityValue in entityValues)
|
||||||
|
{
|
||||||
|
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//实体领域事件-所有操作类型
|
||||||
|
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||||
|
{
|
||||||
|
var eventReport = CreateEventReport(entityInfo.EntityValue);
|
||||||
|
PublishEntityEvents(eventReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||||
|
{
|
||||||
|
if (Options.EnabledSqlLog)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine("==========Yi-SQL执行:==========");
|
||||||
|
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
|
||||||
|
sb.AppendLine("===============================");
|
||||||
|
Logger.CreateLogger<DefaultSqlSugarDbContext>().LogDebug(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||||
|
{
|
||||||
|
if (Options.EnabledSqlLog)
|
||||||
|
{
|
||||||
|
var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
|
||||||
|
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo)
|
||||||
|
{
|
||||||
|
if (propertyInfo.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新
|
||||||
|
{
|
||||||
|
entityColumnInfo.IsEnableUpdateVersionValidation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propertyInfo.PropertyType == typeof(ExtraPropertyDictionary))
|
||||||
|
{
|
||||||
|
entityColumnInfo.IsIgnore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propertyInfo.Name == nameof(Entity<object>.Id))
|
||||||
|
{
|
||||||
|
entityColumnInfo.IsPrimarykey = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建领域事件报告
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected virtual EntityEventReport? CreateEventReport(object entity)
|
||||||
|
{
|
||||||
|
var eventReport = new EntityEventReport();
|
||||||
|
|
||||||
|
//判断是否为领域事件-聚合根
|
||||||
|
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
|
||||||
|
if (generatesDomainEventsEntity == null)
|
||||||
|
{
|
||||||
|
return eventReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray();
|
||||||
|
if (localEvents != null && localEvents.Any())
|
||||||
|
{
|
||||||
|
eventReport.DomainEvents.AddRange(
|
||||||
|
localEvents.Select(
|
||||||
|
eventRecord => new DomainEventEntry(
|
||||||
|
entity,
|
||||||
|
eventRecord.EventData,
|
||||||
|
eventRecord.EventOrder
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
generatesDomainEventsEntity.ClearLocalEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.ToArray();
|
||||||
|
if (distributedEvents != null && distributedEvents.Any())
|
||||||
|
{
|
||||||
|
eventReport.DistributedEvents.AddRange(
|
||||||
|
distributedEvents.Select(
|
||||||
|
eventRecord => new DomainEventEntry(
|
||||||
|
entity,
|
||||||
|
eventRecord.EventData,
|
||||||
|
eventRecord.EventOrder)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
generatesDomainEventsEntity.ClearDistributedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发布领域事件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="changeReport"></param>
|
||||||
|
private void PublishEntityEvents(EntityEventReport changeReport)
|
||||||
|
{
|
||||||
|
foreach (var localEvent in changeReport.DomainEvents)
|
||||||
|
{
|
||||||
|
UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
|
||||||
|
new UnitOfWorkEventRecord(localEvent.EventData.GetType(), localEvent.EventData, localEvent.EventOrder)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var distributedEvent in changeReport.DistributedEvents)
|
||||||
|
{
|
||||||
|
UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
|
||||||
|
new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(), distributedEvent.EventData, distributedEvent.EventOrder)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.SqlSugarCore
|
||||||
|
{
|
||||||
|
public static class SqlSugarCoreExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 新增db对象,可支持多个
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="service"></param>
|
||||||
|
/// <param name="serviceLifetime"></param>
|
||||||
|
/// <typeparam name="TDbContext"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IServiceCollection AddYiDbContext<TDbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where TDbContext : class, ISqlSugarDbContextDependencies
|
||||||
|
{
|
||||||
|
service.AddTransient<ISqlSugarDbContextDependencies, TDbContext>();
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新增db对象,可支持多个
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="service"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <typeparam name="TDbContext"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IServiceCollection AddYiDbContext<TDbContext>(this IServiceCollection service, Action<DbConnOptions> options) where TDbContext : class, ISqlSugarDbContextDependencies
|
||||||
|
{
|
||||||
|
service.Configure<DbConnOptions>(options.Invoke);
|
||||||
|
service.AddYiDbContext<TDbContext>();
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.Data;
|
|
||||||
using Volo.Abp.DependencyInjection;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore
|
|
||||||
{
|
|
||||||
|
|
||||||
public class SqlSugarDbConnectionCreator: ISqlSugarDbConnectionCreator,ITransientDependency
|
|
||||||
{
|
|
||||||
public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options)
|
|
||||||
{
|
|
||||||
Options = options.Value;
|
|
||||||
}
|
|
||||||
public DbConnOptions Options { get; }
|
|
||||||
|
|
||||||
public void SetDbAop(ISqlSugarClient currentDb)
|
|
||||||
{
|
|
||||||
currentDb.Aop.OnLogExecuting = this.OnLogExecuting;
|
|
||||||
currentDb.Aop.OnLogExecuted = this.OnLogExecuted;
|
|
||||||
currentDb.Aop.DataExecuting = this.DataExecuting;
|
|
||||||
currentDb.Aop.DataExecuted = this.DataExecuted;
|
|
||||||
OnSqlSugarClientConfig(currentDb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ConnectionConfig Build(Action<ConnectionConfig>? action=null)
|
|
||||||
{
|
|
||||||
var dbConnOptions = Options;
|
|
||||||
#region 组装options
|
|
||||||
if (dbConnOptions.DbType is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("DbType配置为空");
|
|
||||||
}
|
|
||||||
var slavaConFig = new List<SlaveConnectionConfig>();
|
|
||||||
if (dbConnOptions.EnabledReadWrite)
|
|
||||||
{
|
|
||||||
if (dbConnOptions.ReadUrl is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("读写分离为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
var readCon = dbConnOptions.ReadUrl;
|
|
||||||
|
|
||||||
readCon.ForEach(s =>
|
|
||||||
{
|
|
||||||
//如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接
|
|
||||||
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 组装连接config
|
|
||||||
var connectionConfig = new ConnectionConfig()
|
|
||||||
{
|
|
||||||
ConfigId= ConnectionStrings.DefaultConnectionStringName,
|
|
||||||
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
|
|
||||||
ConnectionString = dbConnOptions.Url,
|
|
||||||
IsAutoCloseConnection = true,
|
|
||||||
SlaveConnectionConfigs = slavaConFig,
|
|
||||||
//设置codefirst非空值判断
|
|
||||||
ConfigureExternalServices = new ConfigureExternalServices
|
|
||||||
{
|
|
||||||
// 处理表
|
|
||||||
EntityNameService = (type, entity) =>
|
|
||||||
{
|
|
||||||
if (dbConnOptions.EnableUnderLine && !entity.DbTableName.Contains('_'))
|
|
||||||
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);// 驼峰转下划线
|
|
||||||
},
|
|
||||||
EntityService = (c, p) =>
|
|
||||||
{
|
|
||||||
if (new NullabilityInfoContext()
|
|
||||||
.Create(c).WriteState is NullabilityState.Nullable)
|
|
||||||
{
|
|
||||||
p.IsNullable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dbConnOptions.EnableUnderLine && !p.IsIgnore && !p.DbColumnName.Contains('_'))
|
|
||||||
p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName);// 驼峰转下划线
|
|
||||||
|
|
||||||
EntityService(c, p);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//这里多租户有个坑,无效的
|
|
||||||
AopEvents = new AopEvents
|
|
||||||
{
|
|
||||||
DataExecuted = DataExecuted,
|
|
||||||
DataExecuting = DataExecuting,
|
|
||||||
OnLogExecuted = OnLogExecuted,
|
|
||||||
OnLogExecuting = OnLogExecuting
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
if (action is not null)
|
|
||||||
{
|
|
||||||
action.Invoke(connectionConfig);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return connectionConfig;
|
|
||||||
}
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }
|
|
||||||
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<object, DataAfterModel> DataExecuted { get; set; }
|
|
||||||
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<object, DataFilterModel> DataExecuting { get; set; }
|
|
||||||
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<string, SugarParameter[]> OnLogExecuting { get; set; }
|
|
||||||
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<string, SugarParameter[]> OnLogExecuted { get; set; }
|
|
||||||
|
|
||||||
[DisablePropertyInjection]
|
|
||||||
public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,362 +1,49 @@
|
|||||||
using System.Collections;
|
using System.Reflection;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Volo.Abp.Auditing;
|
|
||||||
using Volo.Abp.Data;
|
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities;
|
|
||||||
using Volo.Abp.Domain.Entities.Events;
|
|
||||||
using Volo.Abp.Guids;
|
|
||||||
using Volo.Abp.MultiTenancy;
|
|
||||||
using Volo.Abp.Users;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
using Check = Volo.Abp.Check;
|
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore
|
namespace Yi.Framework.SqlSugarCore;
|
||||||
|
|
||||||
|
public abstract class SqlSugarDbContext : ISqlSugarDbContextDependencies
|
||||||
{
|
{
|
||||||
public class SqlSugarDbContext : ISqlSugarDbContext
|
protected IAbpLazyServiceProvider LazyServiceProvider { get; }
|
||||||
|
|
||||||
|
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
||||||
{
|
{
|
||||||
/// <summary>
|
this.LazyServiceProvider = lazyServiceProvider;
|
||||||
/// SqlSugar 客户端
|
|
||||||
/// </summary>
|
|
||||||
public ISqlSugarClient SqlSugarClient { get; private set; }
|
|
||||||
|
|
||||||
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
|
||||||
private IAbpLazyServiceProvider LazyServiceProvider { get; }
|
|
||||||
|
|
||||||
private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
|
|
||||||
private ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
|
|
||||||
private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
|
||||||
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
|
||||||
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
|
|
||||||
|
|
||||||
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
|
|
||||||
|
|
||||||
private IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
|
|
||||||
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
|
||||||
|
|
||||||
private ISerializeService SerializeService=> LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
|
|
||||||
|
|
||||||
public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient)
|
|
||||||
{
|
|
||||||
SqlSugarClient = sqlSugarClient;
|
|
||||||
}
|
|
||||||
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
|
||||||
{
|
|
||||||
LazyServiceProvider = lazyServiceProvider;
|
|
||||||
var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>();
|
|
||||||
connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig;
|
|
||||||
connectionCreator.EntityService = EntityService;
|
|
||||||
connectionCreator.DataExecuting = DataExecuting;
|
|
||||||
connectionCreator.DataExecuted = DataExecuted;
|
|
||||||
connectionCreator.OnLogExecuting = OnLogExecuting;
|
|
||||||
connectionCreator.OnLogExecuted = OnLogExecuted;
|
|
||||||
SqlSugarClient = new SqlSugarClient(connectionCreator.Build(action: options =>
|
|
||||||
{
|
|
||||||
options.ConnectionString = GetCurrentConnectionString();
|
|
||||||
options.DbType = GetCurrentDbType();
|
|
||||||
}));
|
|
||||||
//统一使用aop处理
|
|
||||||
connectionCreator.SetDbAop(SqlSugarClient);
|
|
||||||
//替换默认序列化器
|
|
||||||
SqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SerializeService = SerializeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// db切换多库支持
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected virtual string GetCurrentConnectionString()
|
|
||||||
{
|
|
||||||
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
|
|
||||||
var connectionString = connectionStringResolver.ResolveAsync().ConfigureAwait(false).GetAwaiter().GetResult();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(connectionString))
|
|
||||||
{
|
|
||||||
Check.NotNull(Options.Url, "dbUrl未配置");
|
|
||||||
}
|
|
||||||
return connectionString!;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual DbType GetCurrentDbType()
|
|
||||||
{
|
|
||||||
if (CurrentTenant.Name is not null)
|
|
||||||
{
|
|
||||||
var dbTypeFromTenantName = GetDbTypeFromTenantName(CurrentTenant.Name);
|
|
||||||
if (dbTypeFromTenantName is not null)
|
|
||||||
{
|
|
||||||
return dbTypeFromTenantName.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Check.NotNull(Options.DbType, "默认DbType未配置!");
|
|
||||||
return Options.DbType!.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
//根据租户name进行匹配db类型: Test_Sqlite,[来自AI]
|
|
||||||
private DbType? GetDbTypeFromTenantName(string name)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查找下划线的位置
|
|
||||||
int underscoreIndex = name.LastIndexOf('_');
|
|
||||||
|
|
||||||
if (underscoreIndex == -1 || underscoreIndex == name.Length - 1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取 枚举 部分
|
|
||||||
string enumString = name.Substring(underscoreIndex + 1);
|
|
||||||
|
|
||||||
// 尝试将 尾缀 转换为枚举
|
|
||||||
if (Enum.TryParse<DbType>(enumString, out DbType result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 条件不满足时返回 null
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 上下文对象扩展
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sqlSugarClient"></param>
|
|
||||||
protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
|
||||||
{
|
|
||||||
//需自定义扩展
|
|
||||||
if (IsSoftDeleteFilterEnabled)
|
|
||||||
{
|
|
||||||
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
|
|
||||||
}
|
|
||||||
if (IsMultiTenantFilterEnabled)
|
|
||||||
{
|
|
||||||
//表达式里只能有具体值,不能运算
|
|
||||||
var expressionCurrentTenant = CurrentTenant.Id ?? null;
|
|
||||||
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == expressionCurrentTenant);
|
|
||||||
}
|
|
||||||
CustomDataFilter(sqlSugarClient);
|
|
||||||
}
|
|
||||||
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="oldValue"></param>
|
|
||||||
/// <param name="entityInfo"></param>
|
|
||||||
protected virtual void DataExecuting(object oldValue, DataFilterModel entityInfo)
|
|
||||||
{
|
|
||||||
//审计日志
|
|
||||||
switch (entityInfo.OperationType)
|
|
||||||
{
|
|
||||||
case DataFilterType.UpdateByObject:
|
|
||||||
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
|
|
||||||
{
|
|
||||||
if (!DateTime.MinValue.Equals(oldValue))
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(DateTime.Now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
|
|
||||||
{
|
|
||||||
if (CurrentUser.Id != null)
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(CurrentUser.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DataFilterType.InsertByObject:
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
|
|
||||||
{
|
|
||||||
//主键为空或者为默认最小值
|
|
||||||
if (Guid.Empty.Equals(oldValue))
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(GuidGenerator.Create());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
|
|
||||||
{
|
|
||||||
//为空或者为默认最小值
|
|
||||||
if (DateTime.MinValue.Equals(oldValue))
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(DateTime.Now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
|
|
||||||
{
|
|
||||||
if (CurrentUser.Id is not null)
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(CurrentUser.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
|
|
||||||
{
|
|
||||||
if (CurrentTenant.Id is not null)
|
|
||||||
{
|
|
||||||
entityInfo.SetValue(CurrentTenant.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//领域事件
|
|
||||||
switch (entityInfo.OperationType)
|
|
||||||
{
|
|
||||||
case DataFilterType.InsertByObject:
|
|
||||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
|
||||||
{
|
|
||||||
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DataFilterType.UpdateByObject:
|
|
||||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
|
||||||
{
|
|
||||||
//软删除,发布的是删除事件
|
|
||||||
if (entityInfo.EntityValue is ISoftDelete softDelete)
|
|
||||||
{
|
|
||||||
if (softDelete.IsDeleted == true)
|
|
||||||
{
|
|
||||||
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DataFilterType.DeleteByObject:
|
|
||||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
|
||||||
{
|
|
||||||
//这里sqlsugar有个特殊,删除会返回批量的结果
|
|
||||||
if (entityInfo.EntityValue is IEnumerable entityValues)
|
|
||||||
{
|
|
||||||
foreach (var entityValue in entityValues)
|
|
||||||
{
|
|
||||||
|
|
||||||
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql"></param>
|
|
||||||
/// <param name="pars"></param>
|
|
||||||
protected virtual void OnLogExecuting(string sql, SugarParameter[] pars)
|
|
||||||
{
|
|
||||||
if (Options.EnabledSqlLog)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.AppendLine("==========Yi-SQL执行:==========");
|
|
||||||
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
|
|
||||||
sb.AppendLine("===============================");
|
|
||||||
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql"></param>
|
|
||||||
/// <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>
|
|
||||||
/// 实体配置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property"></param>
|
|
||||||
/// <param name="column"></param>
|
|
||||||
protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column)
|
|
||||||
{
|
|
||||||
if (property.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新
|
|
||||||
{
|
|
||||||
// column.IsOnlyIgnoreInsert = true;
|
|
||||||
// column.IsOnlyIgnoreUpdate = true;
|
|
||||||
column.IsEnableUpdateVersionValidation = true;
|
|
||||||
}
|
|
||||||
if (property.PropertyType == typeof(ExtraPropertyDictionary))
|
|
||||||
{
|
|
||||||
column.IsIgnore = true;
|
|
||||||
}
|
|
||||||
if (property.Name == nameof(Entity<object>.Id))
|
|
||||||
{
|
|
||||||
column.IsPrimarykey = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BackupDataBase()
|
|
||||||
{
|
|
||||||
string directoryName = "database_backup";
|
|
||||||
string fileName = DateTime.Now.ToString($"yyyyMMdd_HHmmss") + $"_{SqlSugarClient.Ado.Connection.Database}";
|
|
||||||
if (!Directory.Exists(directoryName))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(directoryName);
|
|
||||||
}
|
|
||||||
switch (Options.DbType)
|
|
||||||
{
|
|
||||||
case DbType.MySql:
|
|
||||||
//MySql
|
|
||||||
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.sql");//mysql 只支持.net core
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case DbType.Sqlite:
|
|
||||||
//Sqlite
|
|
||||||
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db"); //sqlite 只支持.net core
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case DbType.SqlServer:
|
|
||||||
//SqlServer
|
|
||||||
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.bak"/*服务器路径*/);//第一个参数库名
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("其他数据库备份未实现");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
protected ISqlSugarClient SqlSugarClient { get;private set; }
|
||||||
|
public int ExecutionOrder => 0;
|
||||||
|
|
||||||
|
public void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
SqlSugarClient = sqlSugarClient;
|
||||||
|
CustomDataFilter(sqlSugarClient);
|
||||||
|
}
|
||||||
|
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void DataExecuting(object oldValue, DataFilterModel entityInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Data;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
using Volo.Abp.Threading;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
using Check = Volo.Abp.Check;
|
||||||
|
|
||||||
|
namespace Yi.Framework.SqlSugarCore
|
||||||
|
{
|
||||||
|
public class SqlSugarDbContextFactory : ISqlSugarDbContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// SqlSugar 客户端
|
||||||
|
/// </summary>
|
||||||
|
public ISqlSugarClient SqlSugarClient { get; private set; }
|
||||||
|
|
||||||
|
private IAbpLazyServiceProvider LazyServiceProvider { get; }
|
||||||
|
|
||||||
|
private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||||
|
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||||
|
|
||||||
|
private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
|
||||||
|
|
||||||
|
private IEnumerable<ISqlSugarDbContextDependencies> SqlSugarDbContextDependencies =>
|
||||||
|
LazyServiceProvider.LazyGetRequiredService<IEnumerable<ISqlSugarDbContextDependencies>>();
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<string, ConnectionConfig> ConnectionConfigCache = new();
|
||||||
|
|
||||||
|
public SqlSugarDbContextFactory(IAbpLazyServiceProvider lazyServiceProvider)
|
||||||
|
{
|
||||||
|
LazyServiceProvider = lazyServiceProvider;
|
||||||
|
|
||||||
|
var connectionString = GetCurrentConnectionString();
|
||||||
|
|
||||||
|
var connectionConfig =BuildConnectionConfig(action: options =>
|
||||||
|
{
|
||||||
|
options.ConnectionString = connectionString;
|
||||||
|
options.DbType = GetCurrentDbType();
|
||||||
|
});
|
||||||
|
// var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
|
||||||
|
// BuildConnectionConfig(action: options =>
|
||||||
|
// {
|
||||||
|
// options.ConnectionString = connectionString;
|
||||||
|
// options.DbType = GetCurrentDbType();
|
||||||
|
// }));
|
||||||
|
SqlSugarClient = new SqlSugarClient(connectionConfig);
|
||||||
|
//生命周期,以下都可以直接使用sqlsugardb了
|
||||||
|
|
||||||
|
// Aop及多租户连接字符串和类型,需要单独设置
|
||||||
|
// Aop操作不能进行缓存
|
||||||
|
SetDbAop(SqlSugarClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建Aop-sqlsugaraop在多租户模式中,需单独设置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sqlSugarClient"></param>
|
||||||
|
protected virtual void SetDbAop(ISqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
//替换默认序列化器
|
||||||
|
sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SerializeService = SerializeService;
|
||||||
|
|
||||||
|
//将所有,ISqlSugarDbContextDependencies进行累加
|
||||||
|
Action<string, SugarParameter[]> onLogExecuting = null;
|
||||||
|
Action<string, SugarParameter[]> onLogExecuted = null;
|
||||||
|
Action<object, DataFilterModel> dataExecuting = null;
|
||||||
|
Action<object, DataAfterModel> dataExecuted = null;
|
||||||
|
Action<ISqlSugarClient> onSqlSugarClientConfig = null;
|
||||||
|
|
||||||
|
foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder))
|
||||||
|
{
|
||||||
|
onLogExecuting += dependency.OnLogExecuting;
|
||||||
|
onLogExecuted += dependency.OnLogExecuted;
|
||||||
|
dataExecuting += dependency.DataExecuting;
|
||||||
|
dataExecuted += dependency.DataExecuted;
|
||||||
|
|
||||||
|
onSqlSugarClientConfig += dependency.OnSqlSugarClientConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
//最先存放db操作
|
||||||
|
onSqlSugarClientConfig(sqlSugarClient);
|
||||||
|
|
||||||
|
sqlSugarClient.Aop.OnLogExecuting =onLogExecuting;
|
||||||
|
sqlSugarClient.Aop.OnLogExecuted = onLogExecuted;
|
||||||
|
|
||||||
|
sqlSugarClient.Aop.DataExecuting =dataExecuting;
|
||||||
|
sqlSugarClient.Aop.DataExecuted =dataExecuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建连接配置
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentException"></exception>
|
||||||
|
protected virtual ConnectionConfig BuildConnectionConfig(Action<ConnectionConfig>? action = null)
|
||||||
|
{
|
||||||
|
var dbConnOptions = Options;
|
||||||
|
|
||||||
|
#region 组装options
|
||||||
|
|
||||||
|
if (dbConnOptions.DbType is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("DbType配置为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
var slavaConFig = new List<SlaveConnectionConfig>();
|
||||||
|
if (dbConnOptions.EnabledReadWrite)
|
||||||
|
{
|
||||||
|
if (dbConnOptions.ReadUrl is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("读写分离为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
var readCon = dbConnOptions.ReadUrl;
|
||||||
|
|
||||||
|
readCon.ForEach(s =>
|
||||||
|
{
|
||||||
|
//如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接
|
||||||
|
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 组装连接config
|
||||||
|
|
||||||
|
var connectionConfig = new ConnectionConfig()
|
||||||
|
{
|
||||||
|
ConfigId = ConnectionStrings.DefaultConnectionStringName,
|
||||||
|
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
|
||||||
|
ConnectionString = dbConnOptions.Url,
|
||||||
|
IsAutoCloseConnection = true,
|
||||||
|
SlaveConnectionConfigs = slavaConFig,
|
||||||
|
//设置codefirst非空值判断
|
||||||
|
ConfigureExternalServices = new ConfigureExternalServices
|
||||||
|
{
|
||||||
|
// 处理表
|
||||||
|
EntityNameService = (type, entity) =>
|
||||||
|
{
|
||||||
|
if (dbConnOptions.EnableUnderLine && !entity.DbTableName.Contains('_'))
|
||||||
|
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); // 驼峰转下划线
|
||||||
|
},
|
||||||
|
EntityService = (c, p) =>
|
||||||
|
{
|
||||||
|
if (new NullabilityInfoContext()
|
||||||
|
.Create(c).WriteState is NullabilityState.Nullable)
|
||||||
|
{
|
||||||
|
p.IsNullable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbConnOptions.EnableUnderLine && !p.IsIgnore && !p.DbColumnName.Contains('_'))
|
||||||
|
p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName); // 驼峰转下划线
|
||||||
|
|
||||||
|
//将所有,ISqlSugarDbContextDependencies的EntityService进行累加
|
||||||
|
//额外的实体服务需要这里配置,
|
||||||
|
|
||||||
|
Action<PropertyInfo, EntityColumnInfo> entityService = null;
|
||||||
|
foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder))
|
||||||
|
{
|
||||||
|
entityService += dependency.EntityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityService(c, p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//这里多租户有个坑,这里配置是无效的
|
||||||
|
// AopEvents = new AopEvents
|
||||||
|
// {
|
||||||
|
// DataExecuted = DataExecuted,
|
||||||
|
// DataExecuting = DataExecuting,
|
||||||
|
// OnLogExecuted = OnLogExecuted,
|
||||||
|
// OnLogExecuting = OnLogExecuting
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (action is not null)
|
||||||
|
{
|
||||||
|
action.Invoke(connectionConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return connectionConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// db切换多库支持
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected virtual string GetCurrentConnectionString()
|
||||||
|
{
|
||||||
|
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
|
||||||
|
var connectionString =
|
||||||
|
AsyncHelper.RunSync(() => connectionStringResolver.ResolveAsync());
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(connectionString))
|
||||||
|
{
|
||||||
|
Check.NotNull(Options.Url, "dbUrl未配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectionString!;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual DbType GetCurrentDbType()
|
||||||
|
{
|
||||||
|
if (CurrentTenant.Name is not null)
|
||||||
|
{
|
||||||
|
var dbTypeFromTenantName = GetDbTypeFromTenantName(CurrentTenant.Name);
|
||||||
|
if (dbTypeFromTenantName is not null)
|
||||||
|
{
|
||||||
|
return dbTypeFromTenantName.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Check.NotNull(Options.DbType, "默认DbType未配置!");
|
||||||
|
return Options.DbType!.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//根据租户name进行匹配db类型: Test_Sqlite,[来自AI]
|
||||||
|
private DbType? GetDbTypeFromTenantName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找下划线的位置
|
||||||
|
int underscoreIndex = name.LastIndexOf('_');
|
||||||
|
|
||||||
|
if (underscoreIndex == -1 || underscoreIndex == name.Length - 1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 枚举 部分
|
||||||
|
string enumString = name.Substring(underscoreIndex + 1);
|
||||||
|
|
||||||
|
// 尝试将 尾缀 转换为枚举
|
||||||
|
if (Enum.TryParse<DbType>(enumString, out DbType result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 条件不满足时返回 null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void BackupDataBase()
|
||||||
|
{
|
||||||
|
string directoryName = "database_backup";
|
||||||
|
string fileName = DateTime.Now.ToString($"yyyyMMdd_HHmmss") + $"_{SqlSugarClient.Ado.Connection.Database}";
|
||||||
|
if (!Directory.Exists(directoryName))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Options.DbType)
|
||||||
|
{
|
||||||
|
case DbType.MySql:
|
||||||
|
//MySql
|
||||||
|
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
|
||||||
|
$"{Path.Combine(directoryName, fileName)}.sql"); //mysql 只支持.net core
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case DbType.Sqlite:
|
||||||
|
//Sqlite
|
||||||
|
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db"); //sqlite 只支持.net core
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case DbType.SqlServer:
|
||||||
|
//SqlServer
|
||||||
|
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
|
||||||
|
$"{Path.Combine(directoryName, fileName)}.bak" /*服务器路径*/); //第一个参数库名
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException("其他数据库备份未实现");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore
|
|
||||||
{
|
|
||||||
public static class SqlsugarCoreExtensions
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddYiDbContext<DbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where DbContext : class, ISqlSugarDbContext
|
|
||||||
{
|
|
||||||
service.Replace(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), serviceLifetime));
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
public static IServiceCollection TryAddYiDbContext<DbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where DbContext : class, ISqlSugarDbContext
|
|
||||||
{
|
|
||||||
service.TryAdd(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), serviceLifetime));
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static IServiceCollection AddYiDbContext<DbContext>(this IServiceCollection service, Action<DbConnOptions> options) where DbContext : class, ISqlSugarDbContext
|
|
||||||
{
|
|
||||||
|
|
||||||
service.Configure<DbConnOptions>(ops =>
|
|
||||||
{
|
|
||||||
options.Invoke(ops);
|
|
||||||
});
|
|
||||||
service.AddYiDbContext<DbContext>();
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,4 +17,4 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
DbContext = dbContext;
|
DbContext = dbContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,6 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
{
|
{
|
||||||
public class UnitOfWorkSqlsugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext> where TDbContext : ISqlSugarDbContext
|
public class UnitOfWorkSqlsugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext> where TDbContext : ISqlSugarDbContext
|
||||||
{
|
{
|
||||||
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
|
|
||||||
|
|
||||||
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
|
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
|
||||||
public IServiceProvider ServiceProvider { get; set; }
|
public IServiceProvider ServiceProvider { get; set; }
|
||||||
|
|
||||||
@@ -28,8 +26,7 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
IUnitOfWorkManager unitOfWorkManager,
|
IUnitOfWorkManager unitOfWorkManager,
|
||||||
IConnectionStringResolver connectionStringResolver,
|
IConnectionStringResolver connectionStringResolver,
|
||||||
ICancellationTokenProvider cancellationTokenProvider,
|
ICancellationTokenProvider cancellationTokenProvider,
|
||||||
ICurrentTenant currentTenant,
|
ICurrentTenant currentTenant
|
||||||
ISqlSugarDbConnectionCreator dbConnectionCreator
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UnitOfWorkManager = unitOfWorkManager;
|
UnitOfWorkManager = unitOfWorkManager;
|
||||||
@@ -37,10 +34,8 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
CancellationTokenProvider = cancellationTokenProvider;
|
CancellationTokenProvider = cancellationTokenProvider;
|
||||||
CurrentTenant = currentTenant;
|
CurrentTenant = currentTenant;
|
||||||
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
|
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
|
||||||
_dbConnectionCreator = dbConnectionCreator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//private static object _databaseApiLock = new object();
|
|
||||||
public virtual async Task<TDbContext> GetDbContextAsync()
|
public virtual async Task<TDbContext> GetDbContextAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -52,19 +47,16 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
|||||||
|
|
||||||
|
|
||||||
var unitOfWork = UnitOfWorkManager.Current;
|
var unitOfWork = UnitOfWorkManager.Current;
|
||||||
if (unitOfWork == null /*|| unitOfWork.Options.IsTransactional == false*/)
|
if (unitOfWork == null )
|
||||||
{
|
{
|
||||||
var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
//var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
||||||
//提高体验,取消工作单元强制性
|
|
||||||
//throw new AbpException("A DbContext can only be created inside a unit of work!");
|
|
||||||
//如果不启用工作单元,创建一个新的db,不开启事务即可
|
//如果不启用工作单元,创建一个新的db,不开启事务即可
|
||||||
return dbContext;
|
//return dbContext;
|
||||||
|
|
||||||
|
//2024-11-30,改回强制性使用工作单元,否则容易造成歧义
|
||||||
|
throw new AbpException("DbContext 只能在工作单元内工作,当前DbContext没有工作单元,如需创建新线程并发操作,请手动创建工作单元");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//尝试当前工作单元获取db
|
//尝试当前工作单元获取db
|
||||||
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Volo.Abp;
|
|
||||||
using Volo.Abp.Auditing;
|
|
||||||
using Volo.Abp.Data;
|
using Volo.Abp.Data;
|
||||||
using Volo.Abp.Domain;
|
using Volo.Abp.Domain;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
using Volo.Abp.Modularity;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
using Yi.Framework.SqlSugarCore.Repositories;
|
using Yi.Framework.SqlSugarCore.Repositories;
|
||||||
using Yi.Framework.SqlSugarCore.Uow;
|
using Yi.Framework.SqlSugarCore.Uow;
|
||||||
@@ -28,7 +25,7 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
var section = configuration.GetSection("DbConnOptions");
|
var section = configuration.GetSection("DbConnOptions");
|
||||||
Configure<DbConnOptions>(section);
|
Configure<DbConnOptions>(section);
|
||||||
|
|
||||||
service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContext>();
|
service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContextFactory>();
|
||||||
|
|
||||||
//不开放sqlsugarClient
|
//不开放sqlsugarClient
|
||||||
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
|
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
|
||||||
@@ -47,6 +44,7 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
//将默认db传递给abp连接字符串模块
|
//将默认db传递给abp连接字符串模块
|
||||||
Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; });
|
Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; });
|
||||||
|
|
||||||
|
context.Services.AddYiDbContext<DefaultSqlSugarDbContext>();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +70,6 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
|
|
||||||
|
|
||||||
logger.LogInformation(sb.ToString());
|
logger.LogInformation(sb.ToString());
|
||||||
//Todo:准备支持多租户种子数据及CodeFirst
|
|
||||||
|
|
||||||
if (options.EnabledCodeFirst)
|
if (options.EnabledCodeFirst)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class AuditingStore : IAuditingStore, ITransientDependency
|
|||||||
protected IUnitOfWorkManager UnitOfWorkManager { get; }
|
protected IUnitOfWorkManager UnitOfWorkManager { get; }
|
||||||
protected AbpAuditingOptions Options { get; }
|
protected AbpAuditingOptions Options { get; }
|
||||||
protected IAuditLogInfoToAuditLogConverter Converter { get; }
|
protected IAuditLogInfoToAuditLogConverter Converter { get; }
|
||||||
|
|
||||||
public AuditingStore(
|
public AuditingStore(
|
||||||
IAuditLogRepository auditLogRepository,
|
IAuditLogRepository auditLogRepository,
|
||||||
IUnitOfWorkManager unitOfWorkManager,
|
IUnitOfWorkManager unitOfWorkManager,
|
||||||
@@ -52,10 +53,10 @@ public class AuditingStore : IAuditingStore, ITransientDependency
|
|||||||
protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
|
protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Yi-请求追踪:" + JsonHelper.ObjToStr(auditInfo, "yyyy-MM-dd HH:mm:ss"));
|
Logger.LogDebug("Yi-请求追踪:" + JsonHelper.ObjToStr(auditInfo, "yyyy-MM-dd HH:mm:ss"));
|
||||||
using (var uow = UnitOfWorkManager.Begin(true))
|
using (var uow = UnitOfWorkManager.Begin())
|
||||||
{
|
{
|
||||||
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
|
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ public class AuditLogActionEntity : Entity<Guid>, IMultiTenant
|
|||||||
|
|
||||||
public virtual string? MethodName { get; protected set; }
|
public virtual string? MethodName { get; protected set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||||
public virtual string? Parameters { get; protected set; }
|
public virtual string? Parameters { get; protected set; }
|
||||||
|
|
||||||
public virtual DateTime? ExecutionTime { get; protected set; }
|
public virtual DateTime? ExecutionTime { get; protected set; }
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ namespace Yi.Framework.AuditLogging.Domain.Entities
|
|||||||
|
|
||||||
public virtual string? CorrelationId { get; set; }
|
public virtual string? CorrelationId { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(Length = 2000)]
|
||||||
public virtual string? BrowserInfo { get; protected set; }
|
public virtual string? BrowserInfo { get; protected set; }
|
||||||
|
|
||||||
public virtual string? HttpMethod { get; protected set; }
|
public virtual string? HttpMethod { get; protected set; }
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using FreeRedis;
|
using FreeRedis;
|
||||||
|
using Hangfire;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Volo.Abp.Caching;
|
using Volo.Abp.Caching;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities;
|
using Volo.Abp.Domain.Entities;
|
||||||
@@ -15,23 +15,27 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
|||||||
|
|
||||||
namespace Yi.Framework.Bbs.Application.Jobs;
|
namespace Yi.Framework.Bbs.Application.Jobs;
|
||||||
|
|
||||||
public class AccessLogCacheJob : QuartzBackgroundWorkerBase
|
public class AccessLogCacheJob : HangfireBackgroundWorkerBase
|
||||||
{
|
{
|
||||||
private readonly ILocalEventBus _localEventBus;
|
private readonly ILocalEventBus _localEventBus;
|
||||||
|
|
||||||
public AccessLogCacheJob(ILocalEventBus localEventBus)
|
public AccessLogCacheJob(ILocalEventBus localEventBus)
|
||||||
{
|
{
|
||||||
_localEventBus = localEventBus;
|
_localEventBus = localEventBus;
|
||||||
JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob))
|
RecurringJobId = "访问日志写入缓存";
|
||||||
.Build();
|
//每10秒执行一次,将本地缓存转入redis,防止丢数据
|
||||||
|
CronExpression = "*/10 * * * * *";
|
||||||
|
//
|
||||||
|
// JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob))
|
||||||
|
// .Build();
|
||||||
|
|
||||||
//每10秒执行一次,将本地缓存转入redis,防止丢数据
|
//每10秒执行一次,将本地缓存转入redis,防止丢数据
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob))
|
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob))
|
||||||
.WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; })
|
// .WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; })
|
||||||
.Build();
|
// .Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
await _localEventBus.PublishAsync(new AccessLogResetArgs());
|
await _localEventBus.PublishAsync(new AccessLogResetArgs());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using FreeRedis;
|
using FreeRedis;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Volo.Abp.Caching;
|
using Volo.Abp.Caching;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities;
|
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Caches;
|
using Yi.Framework.Bbs.Domain.Shared.Caches;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
@@ -13,7 +11,7 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
|||||||
|
|
||||||
namespace Yi.Framework.Bbs.Application.Jobs;
|
namespace Yi.Framework.Bbs.Application.Jobs;
|
||||||
|
|
||||||
public class AccessLogStoreJob : QuartzBackgroundWorkerBase
|
public class AccessLogStoreJob : HangfireBackgroundWorkerBase
|
||||||
{
|
{
|
||||||
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
|
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
|
||||||
|
|
||||||
@@ -45,18 +43,23 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase
|
|||||||
public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository)
|
public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
|
RecurringJobId = "访问日志写入数据库";
|
||||||
//每分钟执行一次
|
//每分钟执行一次
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob))
|
CronExpression = "0 * * * * ?";
|
||||||
.WithCronSchedule("0 * * * * ?")
|
// JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
|
||||||
.Build();
|
// .Build();
|
||||||
|
// //每分钟执行一次
|
||||||
|
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob))
|
||||||
|
// .WithCronSchedule("0 * * * * ?")
|
||||||
|
// .Build();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
if (EnableRedisCache)
|
if (EnableRedisCache)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Yi.Framework.Bbs.Domain.Managers;
|
using Yi.Framework.Bbs.Domain.Managers;
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Application.Jobs;
|
namespace Yi.Framework.Bbs.Application.Jobs;
|
||||||
@@ -7,20 +6,25 @@ namespace Yi.Framework.Bbs.Application.Jobs;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 每日任务job
|
/// 每日任务job
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AssignmentExpireTimeOutJob : QuartzBackgroundWorkerBase
|
public class AssignmentExpireTimeOutJob : HangfireBackgroundWorkerBase
|
||||||
{
|
{
|
||||||
private readonly AssignmentManager _assignmentManager;
|
private readonly AssignmentManager _assignmentManager;
|
||||||
|
|
||||||
public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager)
|
public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager)
|
||||||
{
|
{
|
||||||
_assignmentManager = assignmentManager;
|
_assignmentManager = assignmentManager;
|
||||||
JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build();
|
|
||||||
//每个小时整点执行一次
|
RecurringJobId = "每日任务系统超时检测";
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?")
|
//每分钟执行一次
|
||||||
.Build();
|
CronExpression = "0 * * * * ?";
|
||||||
|
//
|
||||||
|
// JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build();
|
||||||
|
// //每个小时整点执行一次
|
||||||
|
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?")
|
||||||
|
// .Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
await _assignmentManager.ExpireTimeoutAsync();
|
await _assignmentManager.ExpireTimeoutAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
using Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Yi.Framework.Bbs.Domain.Managers;
|
using Yi.Framework.Bbs.Domain.Managers;
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Application.Jobs
|
namespace Yi.Framework.Bbs.Application.Jobs
|
||||||
{
|
{
|
||||||
public class InterestRecordsJob : QuartzBackgroundWorkerBase
|
public class InterestRecordsJob : HangfireBackgroundWorkerBase
|
||||||
{
|
{
|
||||||
private BankManager _bankManager;
|
private BankManager _bankManager;
|
||||||
public InterestRecordsJob(BankManager bankManager)
|
public InterestRecordsJob(BankManager bankManager)
|
||||||
{
|
{
|
||||||
_bankManager = bankManager;
|
_bankManager = bankManager;
|
||||||
JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
|
|
||||||
|
RecurringJobId = "银行利息积分刷新";
|
||||||
//每个小时整点执行一次
|
//每个小时整点执行一次
|
||||||
|
CronExpression = "0 0 * * * ?";
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
|
|
||||||
|
// JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
|
||||||
|
//
|
||||||
|
// //每个小时整点执行一次
|
||||||
|
//
|
||||||
|
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
|
||||||
|
|
||||||
//测试
|
//测试
|
||||||
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob))
|
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob))
|
||||||
@@ -23,7 +27,8 @@ namespace Yi.Framework.Bbs.Application.Jobs
|
|||||||
// .RepeatForever())
|
// .RepeatForever())
|
||||||
//.Build();
|
//.Build();
|
||||||
}
|
}
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
|
||||||
|
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
//创建一个记录,莫得了
|
//创建一个记录,莫得了
|
||||||
await _bankManager.GetCurrentInterestRate();
|
await _bankManager.GetCurrentInterestRate();
|
||||||
|
|||||||
@@ -110,7 +110,9 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
|
|||||||
)
|
)
|
||||||
.ToPageListAsync(pageIndex, input.MaxResultCount, total);
|
.ToPageListAsync(pageIndex, input.MaxResultCount, total);
|
||||||
|
|
||||||
output.ForEach(x => { x.LevelName = _bbsUserManager._levelCacheDic[x.Level].Name; });
|
var levelCache = await _bbsUserManager.GetLevelCacheMapAsync();
|
||||||
|
|
||||||
|
output.ForEach(x => { x.LevelName = levelCache[x.Level].Name; });
|
||||||
return new PagedResultDto<MoneyTopUserDto>
|
return new PagedResultDto<MoneyTopUserDto>
|
||||||
{
|
{
|
||||||
Items = output,
|
Items = output,
|
||||||
|
|||||||
@@ -27,13 +27,19 @@ namespace Yi.Framework.Bbs.Application.Services
|
|||||||
var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId);
|
var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId);
|
||||||
if (userEntity == null)
|
if (userEntity == null)
|
||||||
{
|
{
|
||||||
throw new Volo.Abp.UserFriendlyException("该用户不存在");
|
throw new UserFriendlyException("该用户不存在");
|
||||||
}
|
}
|
||||||
userId= userEntity.Id;
|
userId= userEntity.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var output =await _bbsUserManager.GetBbsUserInfoAsync(userId);
|
var output =await _bbsUserManager.GetBbsUserInfoAsync(userId);
|
||||||
|
|
||||||
|
//不是自己
|
||||||
|
if (CurrentUser.Id != output.Id)
|
||||||
|
{
|
||||||
|
output.Phone = null;
|
||||||
|
output.Email=null;
|
||||||
|
}
|
||||||
return output!;
|
return output!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
|
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input.Content)|| input.Content=="<p><br></p>")
|
||||||
|
{
|
||||||
|
throw new UserFriendlyException("评论不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
|
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
|
||||||
if (discuess is null)
|
if (discuess is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -158,10 +158,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
//查询完主题之后,要过滤一下私有的主题信息
|
//查询完主题之后,要过滤一下私有的主题信息
|
||||||
items.ApplyPermissionTypeFilter(CurrentUser.Id ?? Guid.Empty);
|
items.ApplyPermissionTypeFilter(CurrentUser.Id ?? Guid.Empty);
|
||||||
|
|
||||||
|
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
|
||||||
//等级、是否点赞赋值
|
//等级、是否点赞赋值
|
||||||
items?.ForEach(x =>
|
items?.ForEach(x =>
|
||||||
{
|
{
|
||||||
x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name;
|
x.User.LevelName = levelCacheDic[x.User.Level].Name;
|
||||||
if (CurrentUser.Id is not null)
|
if (CurrentUser.Id is not null)
|
||||||
{
|
{
|
||||||
//默认fasle
|
//默认fasle
|
||||||
@@ -212,7 +213,8 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
}
|
}
|
||||||
}, true)
|
}, true)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
output?.ForEach(x => x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name);
|
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
|
||||||
|
output?.ForEach(x => x.User.LevelName = levelCacheDic[x.User.Level].Name);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Yi.Framework.Bbs.Application.Services.Integral
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 大转盘
|
/// 大转盘
|
||||||
/// Todo: 可放入领域层
|
/// Todo: 可放入领域层,但是太简单了,不重要
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[Authorize]
|
[Authorize]
|
||||||
@@ -32,13 +32,7 @@ namespace Yi.Framework.Bbs.Application.Services.Integral
|
|||||||
int[] values = new int[10] { 0, 10, 30, 50, 60, 80, 90, 100, 200, 666 };
|
int[] values = new int[10] { 0, 10, 30, 50, 60, 80, 90, 100, 200, 666 };
|
||||||
var index = GetWheelIndex();
|
var index = GetWheelIndex();
|
||||||
var value = values[index] - 50;
|
var value = values[index] - 50;
|
||||||
|
|
||||||
////不存在负数钱钱
|
|
||||||
//if (value < 0)
|
|
||||||
//{
|
|
||||||
// value = 0;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//修改钱钱,如果钱钱不足,直接会丢出去,那本次抽奖将无效
|
//修改钱钱,如果钱钱不足,直接会丢出去,那本次抽奖将无效
|
||||||
await _localEventBus.PublishAsync(new MoneyChangeEventArgs { UserId = CurrentUser.Id!.Value, Number = value }, false);
|
await _localEventBus.PublishAsync(new MoneyChangeEventArgs { UserId = CurrentUser.Id!.Value, Number = value }, false);
|
||||||
|
|
||||||
@@ -47,7 +41,7 @@ namespace Yi.Framework.Bbs.Application.Services.Integral
|
|||||||
|
|
||||||
private int GetWheelIndex()
|
private int GetWheelIndex()
|
||||||
{
|
{
|
||||||
int[] probabilities = { 30, 40, 30, 15, 15, 10, 4, 3, 2, 1 };
|
int[] probabilities = {5 , 30, 40, 30, 20, 10, 4, 3, 2, 1 };
|
||||||
|
|
||||||
int total = 0;
|
int total = 0;
|
||||||
foreach (var prob in probabilities)
|
foreach (var prob in probabilities)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
|
|
||||||
|
public enum GoodsTypeEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 申请类型
|
||||||
|
/// </summary>
|
||||||
|
Apply
|
||||||
|
}
|
||||||
@@ -19,5 +19,10 @@ namespace Yi.Framework.Bbs.Domain.Shared.Enums
|
|||||||
/// 广播
|
/// 广播
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Broadcast,
|
Broadcast,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 钱钱
|
||||||
|
/// </summary>
|
||||||
|
Money
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ namespace Yi.Framework.Bbs.Domain.Shared.Etos
|
|||||||
Message = message;
|
Message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BbsNoticeEventArgs( NoticeTypeEnum noticeType, Guid acceptUserId, string message)
|
||||||
|
{
|
||||||
|
NoticeType = noticeType;
|
||||||
|
AcceptUserId = acceptUserId;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送广播
|
/// 发送广播
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Yi.Framework.Bbs.Domain.Entities.Forum
|
|||||||
public override Guid Id { get; protected set; }
|
public override Guid Id { get; protected set; }
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
[SugarColumn(Length = 500)]
|
[SugarColumn(Length = 2000)]
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
|
||||||
public Guid DiscussId { get; set; }
|
public Guid DiscussId { get; set; }
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Auditing;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.Entities.Shop;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 商品定义表
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable("BbsGoods")]
|
||||||
|
public class BbsGoodsAggregateRoot: AggregateRoot<Guid>, IHasCreationTime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 上架时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 商品类型
|
||||||
|
/// </summary>
|
||||||
|
public GoodsTypeEnum GoodsType{ get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下架时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? EndTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 商品名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每人限购数量
|
||||||
|
/// </summary>
|
||||||
|
public int LimitNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前库存数量
|
||||||
|
/// </summary>
|
||||||
|
public int StockNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 商品图片url
|
||||||
|
/// </summary>
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述
|
||||||
|
/// </summary>
|
||||||
|
public string Describe { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编号
|
||||||
|
/// </summary>
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所需钱钱
|
||||||
|
/// </summary>
|
||||||
|
public decimal NeedMoney { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所需价值
|
||||||
|
/// </summary>
|
||||||
|
public decimal NeedValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所需积分
|
||||||
|
/// </summary>
|
||||||
|
public decimal NeedPoints { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Auditing;
|
||||||
|
using Volo.Abp.Domain.Entities;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.Entities.Shop;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 商品申请记录表
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable("BbsGoodsApply")]
|
||||||
|
public class BbsGoodsApplyAggregateRoot: AggregateRoot<Guid>, IHasCreationTime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 商品id
|
||||||
|
/// </summary>
|
||||||
|
public Guid GoodsId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 申请时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 申请人用户id
|
||||||
|
/// </summary>
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 联系方式
|
||||||
|
/// </summary>
|
||||||
|
public string ContactInformation { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Yi.Framework.Bbs.Domain.Entities.Shop.ValueObjects;
|
||||||
|
|
||||||
|
public class ShippingAddress
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,23 +25,40 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
}
|
}
|
||||||
public async Task HandleEventAsync(BbsNoticeEventArgs eventData)
|
public async Task HandleEventAsync(BbsNoticeEventArgs eventData)
|
||||||
{
|
{
|
||||||
//离线存储
|
|
||||||
var entity= await _repository.InsertReturnEntityAsync(new BbsNoticeAggregateRoot(eventData.NoticeType, eventData.Message, eventData.AcceptUserId));
|
|
||||||
switch (eventData.NoticeType)
|
//是否需要离线存储
|
||||||
|
bool isStore = true;
|
||||||
|
var now = DateTime.Now;
|
||||||
|
switch (eventData.NoticeType)
|
||||||
{
|
{
|
||||||
case Shared.Enums.NoticeTypeEnum.Personal:
|
case Shared.Enums.NoticeTypeEnum.Personal:
|
||||||
if (BbsNoticeHub.HubUserModels.TryGetValue(eventData.AcceptUserId.ToString(), out var hubUserModel))
|
if (BbsNoticeHub.HubUserModels.TryGetValue(eventData.AcceptUserId.ToString(), out var hubUserModel))
|
||||||
{
|
{
|
||||||
_hubContext.Clients.Client(hubUserModel.ConnnectionId).SendAsync(NoticeTypeEnum.Personal.ToString(), eventData.Message,entity.CreationTime);
|
_hubContext.Clients.Client(hubUserModel.ConnnectionId).SendAsync(NoticeTypeEnum.Personal.ToString(), eventData.Message,now);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Shared.Enums.NoticeTypeEnum.Broadcast:
|
case Shared.Enums.NoticeTypeEnum.Broadcast:
|
||||||
_hubContext.Clients.All.SendAsync(NoticeTypeEnum.Broadcast.ToString(), eventData.Message);
|
_hubContext.Clients.All.SendAsync(NoticeTypeEnum.Broadcast.ToString(), eventData.Message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Shared.Enums.NoticeTypeEnum.Money:
|
||||||
|
if (BbsNoticeHub.HubUserModels.TryGetValue(eventData.AcceptUserId.ToString(), out var hubUserModel2))
|
||||||
|
{
|
||||||
|
_hubContext.Clients.Client(hubUserModel2.ConnnectionId).SendAsync(NoticeTypeEnum.Money.ToString(), eventData.Message,now);
|
||||||
|
}
|
||||||
|
|
||||||
|
isStore = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isStore)
|
||||||
|
{ //离线存储
|
||||||
|
var entity= await _repository.InsertReturnEntityAsync(new BbsNoticeAggregateRoot(eventData.NoticeType, eventData.Message, eventData.AcceptUserId){CreationTime = now});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.EventBus;
|
using Volo.Abp.EventBus;
|
||||||
|
using Volo.Abp.EventBus.Local;
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Consts;
|
using Yi.Framework.Bbs.Domain.Shared.Consts;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
@@ -11,9 +13,11 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
public class MoneyChangeEventHandler : ILocalEventHandler<MoneyChangeEventArgs>, ITransientDependency
|
public class MoneyChangeEventHandler : ILocalEventHandler<MoneyChangeEventArgs>, ITransientDependency
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userInfoRepository;
|
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userInfoRepository;
|
||||||
public MoneyChangeEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userInfoRepository)
|
private ILocalEventBus _localEventBus;
|
||||||
|
public MoneyChangeEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userInfoRepository, ILocalEventBus localEventBus)
|
||||||
{
|
{
|
||||||
_userInfoRepository = userInfoRepository;
|
_userInfoRepository = userInfoRepository;
|
||||||
|
_localEventBus = localEventBus;
|
||||||
}
|
}
|
||||||
public async Task HandleEventAsync(MoneyChangeEventArgs eventData)
|
public async Task HandleEventAsync(MoneyChangeEventArgs eventData)
|
||||||
{
|
{
|
||||||
@@ -28,6 +32,9 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
await _userInfoRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
await _userInfoRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
||||||
.SetColumns(it => it.Money == it.Money + eventData.Number)
|
.SetColumns(it => it.Money == it.Money + eventData.Number)
|
||||||
.Where(x => x.UserId == eventData.UserId).ExecuteCommandAsync();
|
.Where(x => x.UserId == eventData.UserId).ExecuteCommandAsync();
|
||||||
|
|
||||||
|
|
||||||
|
await _localEventBus.PublishAsync(new BbsNoticeEventArgs(NoticeTypeEnum.Money, eventData.UserId,eventData.Number.ToString()), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Volo.Abp.Domain.Services;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.Managers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// bbs商品领域
|
||||||
|
/// </summary>
|
||||||
|
public class BbsShopManager: DomainService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
|||||||
{
|
{
|
||||||
public ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
public ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
||||||
public ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserInfoRepository;
|
public ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserInfoRepository;
|
||||||
public Dictionary<int, LevelCacheItem> _levelCacheDic;
|
// public Dictionary<int, LevelCacheItem> _levelCacheDic;
|
||||||
|
private LevelManager _levelManager;
|
||||||
|
|
||||||
public BbsUserManager(ISqlSugarRepository<UserAggregateRoot> userRepository,
|
public BbsUserManager(ISqlSugarRepository<UserAggregateRoot> userRepository,
|
||||||
ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserInfoRepository,
|
ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserInfoRepository,
|
||||||
@@ -23,7 +24,12 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
|||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_bbsUserInfoRepository = bbsUserInfoRepository;
|
_bbsUserInfoRepository = bbsUserInfoRepository;
|
||||||
_levelCacheDic = levelManager.GetCacheMapAsync().Result;
|
_levelManager = levelManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<int, LevelCacheItem>> GetLevelCacheMapAsync()
|
||||||
|
{
|
||||||
|
return await _levelManager.GetCacheMapAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<BbsUserInfoDto?> GetBbsUserInfoAsync(Guid userId)
|
public async Task<BbsUserInfoDto?> GetBbsUserInfoAsync(Guid userId)
|
||||||
@@ -44,7 +50,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
|||||||
}, true)
|
}, true)
|
||||||
.FirstAsync(user => user.Id == userId);
|
.FirstAsync(user => user.Id == userId);
|
||||||
|
|
||||||
userInfo.LevelName = _levelCacheDic[userInfo.Level].Name;
|
var levelCacheDic= await GetLevelCacheMapAsync();
|
||||||
|
userInfo.LevelName = levelCacheDic[userInfo.Level].Name;
|
||||||
return userInfo;
|
return userInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +73,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
|||||||
DiscussNumber = info.DiscussNumber
|
DiscussNumber = info.DiscussNumber
|
||||||
}, true)
|
}, true)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
userInfos?.ForEach(userInfo => userInfo.LevelName = _levelCacheDic[userInfo.Level].Name);
|
var levelCacheDic= await GetLevelCacheMapAsync();
|
||||||
|
userInfos?.ForEach(userInfo => userInfo.LevelName =levelCacheDic[userInfo.Level].Name);
|
||||||
|
|
||||||
return userInfos ?? new List<BbsUserInfoDto>();
|
return userInfos ?? new List<BbsUserInfoDto>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,12 @@ namespace Yi.Framework.ChatHub.Domain.Managers
|
|||||||
public async Task<ChatOnlineUserCacheItem?> GetUserAsync(Guid userId)
|
public async Task<ChatOnlineUserCacheItem?> GetUserAsync(Guid userId)
|
||||||
{
|
{
|
||||||
var key = new ChatOnlineUserCacheKey(CacheKeyPrefix);
|
var key = new ChatOnlineUserCacheKey(CacheKeyPrefix);
|
||||||
var cacheUser = System.Text.Json.JsonSerializer.Deserialize<ChatOnlineUserCacheItem>(await RedisClient.HGetAsync(key.GetKey(), key.GetField(userId)));
|
var cacheUserOrNull= await RedisClient.HGetAsync(key.GetKey(), key.GetField(userId));
|
||||||
|
if (cacheUserOrNull is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var cacheUser = System.Text.Json.JsonSerializer.Deserialize<ChatOnlineUserCacheItem>(cacheUserOrNull);
|
||||||
return cacheUser;
|
return cacheUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
{
|
{
|
||||||
public string Phone { get; set; }
|
public string Phone { get; set; }
|
||||||
|
|
||||||
public string? Uuid { get; set; }
|
public string Uuid { get; set; }
|
||||||
|
|
||||||
public string? Code { get; set; }
|
public string Code { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DictionaryCreateInputVo
|
public class DictionaryCreateInputVo
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
public string? ListClass { get; set; }
|
public string? ListClass { get; set; }
|
||||||
public string? CssClass { get; set; }
|
public string? CssClass { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryGetListOutputDto : EntityDto<Guid>
|
public class DictionaryGetListOutputDto : EntityDto<Guid>
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public DateTime CreationTime { get; set; } = DateTime.Now;
|
public DateTime CreationTime { get; set; } = DateTime.Now;
|
||||||
public Guid? CreatorId { get; set; }
|
public Guid? CreatorId { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryGetOutputDto : EntityDto<Guid>
|
public class DictionaryGetOutputDto : EntityDto<Guid>
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public DateTime CreationTime { get; set; } = DateTime.Now;
|
public DateTime CreationTime { get; set; } = DateTime.Now;
|
||||||
public Guid? CreatorId { get; set; }
|
public Guid? CreatorId { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary
|
|||||||
{
|
{
|
||||||
public class DictionaryUpdateInputVo
|
public class DictionaryUpdateInputVo
|
||||||
{
|
{
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
public string? ListClass { get; set; }
|
public string? ListClass { get; set; }
|
||||||
public string? CssClass { get; set; }
|
public string? CssClass { get; set; }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Post
|
|||||||
public class PostUpdateInputVo
|
public class PostUpdateInputVo
|
||||||
{
|
{
|
||||||
public bool? State { get; set; }
|
public bool? State { get; set; }
|
||||||
|
public int OrderNum { get; set; }
|
||||||
public string PostCode { get; set; }
|
public string PostCode { get; set; }
|
||||||
public string PostName { get; set; }
|
public string PostName { get; set; }
|
||||||
public string? Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|||||||
@@ -6,16 +6,14 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Quartz.Logging;
|
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
using Yi.Framework.Rbac.Domain.Shared.Options;
|
using Yi.Framework.Rbac.Domain.Shared.Options;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
namespace Yi.Framework.Rbac.Application.Jobs
|
namespace Yi.Framework.Rbac.Application.Jobs
|
||||||
{
|
{
|
||||||
public class BackupDataBaseJob : QuartzBackgroundWorkerBase
|
public class BackupDataBaseJob: HangfireBackgroundWorkerBase
|
||||||
{
|
{
|
||||||
private ISqlSugarDbContext _dbContext;
|
private ISqlSugarDbContext _dbContext;
|
||||||
private IOptions<RbacOptions> _options;
|
private IOptions<RbacOptions> _options;
|
||||||
@@ -24,13 +22,12 @@ namespace Yi.Framework.Rbac.Application.Jobs
|
|||||||
|
|
||||||
_options = options;
|
_options = options;
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
JobDetail = JobBuilder.Create<BackupDataBaseJob>().WithIdentity(nameof(BackupDataBaseJob)).Build();
|
|
||||||
|
RecurringJobId = "数据库备份";
|
||||||
//每天00点与24点进行备份
|
//每天00点与24点进行备份
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithCronSchedule("0 0 0,12 * * ? ").Build();
|
CronExpression = "0 0 0,12 * * ? ";
|
||||||
//Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build();
|
|
||||||
}
|
}
|
||||||
public override Task Execute(IJobExecutionContext context)
|
public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||||
{
|
{
|
||||||
if (_options.Value.EnableDataBaseBackup)
|
if (_options.Value.EnableDataBaseBackup)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -355,13 +355,13 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3RuoYiRouterBuild();
|
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Ruoyi).ToList()).Vue3RuoYiRouterBuild();
|
||||||
}
|
}
|
||||||
else if (routerType == "pure")
|
else if (routerType == "pure")
|
||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3PureRouterBuild();
|
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Pure).ToList()).Vue3PureRouterBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ namespace Yi.Framework.Rbac.Application.Services.Authentication
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AuthService : YiCrudAppService<AuthAggregateRoot, AuthOutputDto, Guid, AuthGetListInput>
|
public class AuthService : YiCrudAppService<AuthAggregateRoot, AuthOutputDto, Guid, AuthGetListInput>
|
||||||
{
|
{
|
||||||
private HttpContext HttpContext { get; set; }
|
private HttpContext? HttpContext { get; set; }
|
||||||
private ILogger<AuthService> _logger;
|
private ILogger<AuthService> _logger;
|
||||||
private ISqlSugarRepository<AuthAggregateRoot, Guid> _repository;
|
private ISqlSugarRepository<AuthAggregateRoot, Guid> _repository;
|
||||||
private IAccountManager _accountManager;
|
private IAccountManager _accountManager;
|
||||||
public AuthService(IAccountManager accountManager, IHttpContextAccessor httpContextAccessor, ILogger<AuthService> logger, ISqlSugarRepository<AuthAggregateRoot, Guid> repository) : base(repository)
|
public AuthService(IAccountManager accountManager, IHttpContextAccessor httpContextAccessor, ILogger<AuthService> logger, ISqlSugarRepository<AuthAggregateRoot, Guid> repository) : base(repository)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
HttpContext = httpContextAccessor.HttpContext ?? throw new ApplicationException("未注册Http");
|
//可能为空
|
||||||
|
HttpContext = httpContextAccessor.HttpContext;
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
}
|
}
|
||||||
@@ -79,6 +80,10 @@ namespace Yi.Framework.Rbac.Application.Services.Authentication
|
|||||||
|
|
||||||
private async Task<(string, string)> GetOpenIdAndNameAsync(string scheme)
|
private async Task<(string, string)> GetOpenIdAndNameAsync(string scheme)
|
||||||
{
|
{
|
||||||
|
if (HttpContext is null)
|
||||||
|
{
|
||||||
|
throw new AggregateException("HttpContext 参数为空");
|
||||||
|
}
|
||||||
var authenticateResult = await HttpContext.AuthenticateAsync(scheme);
|
var authenticateResult = await HttpContext.AuthenticateAsync(scheme);
|
||||||
if (!authenticateResult.Succeeded)
|
if (!authenticateResult.Succeeded)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Yi.Framework.Ddd.Application;
|
|||||||
using Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary;
|
using Yi.Framework.Rbac.Application.Contracts.Dtos.Dictionary;
|
||||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||||
using Yi.Framework.Rbac.Domain.Entities;
|
using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.Rbac.Domain.Shared.Consts;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
|
||||||
@@ -15,29 +14,27 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary服务实现
|
/// Dictionary服务实现
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DictionaryService : YiCrudAppService<DictionaryEntity, DictionaryGetOutputDto,
|
public class DictionaryService : YiCrudAppService<DictionaryEntity, DictionaryGetOutputDto, DictionaryGetListOutputDto, Guid, DictionaryGetListInputVo, DictionaryCreateInputVo, DictionaryUpdateInputVo>,
|
||||||
DictionaryGetListOutputDto, Guid, DictionaryGetListInputVo, DictionaryCreateInputVo,
|
IDictionaryService
|
||||||
DictionaryUpdateInputVo>,
|
|
||||||
IDictionaryService
|
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<DictionaryEntity, Guid> _repository;
|
private ISqlSugarRepository<DictionaryEntity, Guid> _repository;
|
||||||
|
|
||||||
public DictionaryService(ISqlSugarRepository<DictionaryEntity, Guid> repository) : base(repository)
|
public DictionaryService(ISqlSugarRepository<DictionaryEntity, Guid> repository) : base(repository)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository= repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询
|
/// 查询
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override async Task<PagedResultDto<DictionaryGetListOutputDto>> GetListAsync(
|
|
||||||
DictionaryGetListInputVo input)
|
public override async Task<PagedResultDto<DictionaryGetListOutputDto>> GetListAsync(DictionaryGetListInputVo input)
|
||||||
{
|
{
|
||||||
RefAsync<int> total = 0;
|
RefAsync<int> total = 0;
|
||||||
var entities = await _repository._DbQueryable
|
var entities = await _repository._DbQueryable
|
||||||
.WhereIF(input.DictType is not null, x => x.DictType == input.DictType)
|
.WhereIF(input.DictType is not null, x => x.DictType == input.DictType)
|
||||||
.WhereIF(input.DictLabel is not null, x => x.DictLabel!.Contains(input.DictLabel!))
|
.WhereIF(input.DictLabel is not null, x => x.DictLabel!.Contains(input.DictLabel!))
|
||||||
.WhereIF(input.State is not null, x => x.State == input.State)
|
.WhereIF(input.State is not null, x => x.State == input.State)
|
||||||
|
.OrderByDescending(x => x.OrderNum)
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<DictionaryGetListOutputDto>
|
return new PagedResultDto<DictionaryGetListOutputDto>
|
||||||
{
|
{
|
||||||
@@ -60,4 +57,4 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
|||||||
{
|
{
|
||||||
private ILogger<OnlineService> _logger;
|
private ILogger<OnlineService> _logger;
|
||||||
private IHubContext<OnlineHub> _hub;
|
private IHubContext<OnlineHub> _hub;
|
||||||
|
|
||||||
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineHub> hub)
|
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineHub> hub)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -26,18 +27,21 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<PagedResultDto<OnlineUserModel>> GetListAsync([FromQuery] OnlineUserModel online)
|
public Task<PagedResultDto<OnlineUserModel>> GetListAsync([FromQuery] OnlineUserModel online)
|
||||||
{
|
{
|
||||||
var data = OnlineHub.clientUsers;
|
var data = OnlineHub.ClientUsersDic;
|
||||||
IEnumerable<OnlineUserModel> dataWhere = data.AsEnumerable();
|
IEnumerable<OnlineUserModel> dataWhere = data.Values.AsEnumerable();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(online.Ipaddr))
|
if (!string.IsNullOrEmpty(online.Ipaddr))
|
||||||
{
|
{
|
||||||
dataWhere = dataWhere.Where((u) => u.Ipaddr!.Contains(online.Ipaddr));
|
dataWhere = dataWhere.Where((u) => u.Ipaddr!.Contains(online.Ipaddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(online.UserName))
|
if (!string.IsNullOrEmpty(online.UserName))
|
||||||
{
|
{
|
||||||
dataWhere = dataWhere.Where((u) => u.UserName!.Contains(online.UserName));
|
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,13 +54,14 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
|||||||
[Route("online/{connnectionId}")]
|
[Route("online/{connnectionId}")]
|
||||||
public async Task<bool> ForceOut(string connnectionId)
|
public async Task<bool> ForceOut(string connnectionId)
|
||||||
{
|
{
|
||||||
if (OnlineHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId))
|
if (OnlineHub.ClientUsersDic.ContainsKey(connnectionId))
|
||||||
{
|
{
|
||||||
//前端接受到这个事件后,触发前端自动退出
|
//前端接受到这个事件后,触发前端自动退出
|
||||||
await _hub.Clients.Client(connnectionId).SendAsync("forceOut", "你已被强制退出!");
|
await _hub.Clients.Client(connnectionId).SendAsync("forceOut", "你已被强制退出!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using Mapster;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl.Matchers;
|
|
||||||
using Volo.Abp;
|
|
||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
using Volo.Abp.Application.Services;
|
|
||||||
using Volo.Abp.Timing;
|
|
||||||
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.Monitor
|
|
||||||
{
|
|
||||||
public class TaskService : ApplicationService, ITaskService
|
|
||||||
{
|
|
||||||
private readonly ISchedulerFactory _schedulerFactory;
|
|
||||||
private readonly IClock _clock;
|
|
||||||
public TaskService(ISchedulerFactory schedulerFactory, IClock clock)
|
|
||||||
{
|
|
||||||
_clock = clock;
|
|
||||||
_schedulerFactory = schedulerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单查job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="jobId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("task/{jobId}")]
|
|
||||||
public async Task<TaskGetOutput> GetAsync([FromRoute] string jobId)
|
|
||||||
{
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
|
|
||||||
var jobDetail = await scheduler.GetJobDetail(new JobKey(jobId));
|
|
||||||
var trigger = (await scheduler.GetTriggersOfJob(new JobKey(jobId))).First();
|
|
||||||
//状态
|
|
||||||
var state = await scheduler.GetTriggerState(trigger.Key);
|
|
||||||
|
|
||||||
|
|
||||||
var output = new TaskGetOutput
|
|
||||||
{
|
|
||||||
JobId = jobDetail.Key.Name,
|
|
||||||
GroupName = jobDetail.Key.Group,
|
|
||||||
JobType = jobDetail.JobType.Name,
|
|
||||||
Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap),
|
|
||||||
Concurrent = !jobDetail.ConcurrentExecutionDisallowed,
|
|
||||||
Description = jobDetail.Description,
|
|
||||||
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()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (trigger is ISimpleTrigger simple)
|
|
||||||
{
|
|
||||||
output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟";
|
|
||||||
output.Type = JobTypeEnum.Millisecond;
|
|
||||||
output.Millisecond = simple.RepeatInterval.TotalMilliseconds;
|
|
||||||
}
|
|
||||||
else if (trigger is ICronTrigger cron)
|
|
||||||
{
|
|
||||||
output.TriggerArgs = cron.CronExpressionString!;
|
|
||||||
output.Type = JobTypeEnum.Cron;
|
|
||||||
output.Cron = cron.CronExpressionString;
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 多查job
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<PagedResultDto<TaskGetListOutput>> GetListAsync([FromQuery] TaskGetListInput input)
|
|
||||||
{
|
|
||||||
var items = new List<TaskGetOutput>();
|
|
||||||
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
|
|
||||||
var groups = await scheduler.GetJobGroupNames();
|
|
||||||
|
|
||||||
foreach (var groupName in groups)
|
|
||||||
{
|
|
||||||
foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)))
|
|
||||||
{
|
|
||||||
string jobName = jobKey.Name;
|
|
||||||
string jobGroup = jobKey.Group;
|
|
||||||
var triggers = (await scheduler.GetTriggersOfJob(jobKey)).First();
|
|
||||||
items.Add(await GetAsync(jobName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var output = items.Skip((input.SkipCount - 1) * input.MaxResultCount).Take(input.MaxResultCount)
|
|
||||||
.OrderByDescending(x => x.LastRunTime)
|
|
||||||
.ToList();
|
|
||||||
return new PagedResultDto<TaskGetListOutput>(items.Count(), output.Adapt<List<TaskGetListOutput>>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task CreateAsync(TaskCreateInput input)
|
|
||||||
{
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
|
|
||||||
//设置启动时执行一次,然后最大只执行一次
|
|
||||||
|
|
||||||
|
|
||||||
//jobBuilder
|
|
||||||
var jobClassType = Assembly.Load(input.AssemblyName).GetTypes().Where(x => x.Name == input.JobType).FirstOrDefault();
|
|
||||||
|
|
||||||
if (jobClassType is null)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException($"程序集:{input.AssemblyName},{input.JobType} 不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
var jobBuilder = JobBuilder.Create(jobClassType).WithIdentity(new JobKey(input.JobId, input.GroupName))
|
|
||||||
.WithDescription(input.Description);
|
|
||||||
if (!input.Concurrent)
|
|
||||||
{
|
|
||||||
jobBuilder.DisallowConcurrentExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
//triggerBuilder
|
|
||||||
TriggerBuilder triggerBuilder = null;
|
|
||||||
switch (input.Type)
|
|
||||||
{
|
|
||||||
case JobTypeEnum.Cron:
|
|
||||||
triggerBuilder =
|
|
||||||
TriggerBuilder.Create()
|
|
||||||
.WithCronSchedule(input.Cron);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
case JobTypeEnum.Millisecond:
|
|
||||||
triggerBuilder =
|
|
||||||
TriggerBuilder.Create().StartNow()
|
|
||||||
.WithSimpleSchedule(x => x
|
|
||||||
.WithInterval(TimeSpan.FromMilliseconds(input.Millisecond ?? 10000))
|
|
||||||
.RepeatForever()
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//作业计划,单个jobBuilder与多个triggerBuilder组合
|
|
||||||
await scheduler.ScheduleJob(jobBuilder.Build(), triggerBuilder.Build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除job
|
|
||||||
/// </summary>
|
|
||||||
/// <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());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 暂停job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="jobId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPut]
|
|
||||||
public async Task PauseAsync(string jobId)
|
|
||||||
{
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
await scheduler.PauseJob(new JobKey(jobId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="jobId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPut]
|
|
||||||
public async Task StartAsync(string jobId)
|
|
||||||
{
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
await scheduler.ResumeJob(new JobKey(jobId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <param name="input"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task UpdateAsync(string id, TaskUpdateInput input)
|
|
||||||
{
|
|
||||||
await DeleteAsync(new List<string>() { id });
|
|
||||||
await CreateAsync(input.Adapt<TaskCreateInput>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("task/run-once/{id}")]
|
|
||||||
public async Task RunOnceAsync([FromRoute] string id)
|
|
||||||
{
|
|
||||||
var scheduler = await _schedulerFactory.GetScheduler();
|
|
||||||
var jobDetail = await scheduler.GetJobDetail(new JobKey(id));
|
|
||||||
|
|
||||||
var jobBuilder = JobBuilder.Create(jobDetail.JobType).WithIdentity(new JobKey(Guid.NewGuid().ToString()));
|
|
||||||
//设置启动时执行一次,然后最大只执行一次
|
|
||||||
var trigger = TriggerBuilder.Create().WithIdentity(Guid.NewGuid().ToString()).StartNow()
|
|
||||||
.WithSimpleSchedule(x => x
|
|
||||||
.WithIntervalInHours(1)
|
|
||||||
.WithRepeatCount(1))
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
await scheduler.ScheduleJob(jobBuilder.Build(), trigger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,7 @@ namespace Yi.Framework.Rbac.Application.Services.System
|
|||||||
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.PostName),
|
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.PostName),
|
||||||
x => x.PostName.Contains(input.PostName!))
|
x => x.PostName.Contains(input.PostName!))
|
||||||
.WhereIF(input.State is not null, x => x.State == input.State)
|
.WhereIF(input.State is not null, x => x.State == input.State)
|
||||||
|
.OrderByDescending(x => x.OrderNum)
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
return new PagedResultDto<PostGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
return new PagedResultDto<PostGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using System.Collections.Concurrent;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -13,53 +14,54 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs
|
|||||||
//[Authorize]
|
//[Authorize]
|
||||||
public class OnlineHub : AbpHub
|
public class OnlineHub : AbpHub
|
||||||
{
|
{
|
||||||
public static readonly List<OnlineUserModel> clientUsers = new();
|
public static ConcurrentDictionary<string, OnlineUserModel> ClientUsersDic { get; set; } = new();
|
||||||
private readonly static object objLock = new object();
|
|
||||||
|
|
||||||
private HttpContext? _httpContext;
|
private readonly HttpContext? _httpContext;
|
||||||
private ILogger<OnlineHub> _logger => LoggerFactory.CreateLogger<OnlineHub>();
|
private ILogger<OnlineHub> _logger => LoggerFactory.CreateLogger<OnlineHub>();
|
||||||
|
|
||||||
public OnlineHub(IHttpContextAccessor httpContextAccessor)
|
public OnlineHub(IHttpContextAccessor httpContextAccessor)
|
||||||
{
|
{
|
||||||
_httpContext = httpContextAccessor?.HttpContext;
|
_httpContext = httpContextAccessor?.HttpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成功连接
|
/// 成功连接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override Task OnConnectedAsync()
|
public override Task OnConnectedAsync()
|
||||||
{
|
{
|
||||||
lock (objLock)
|
if (_httpContext is null)
|
||||||
{
|
{
|
||||||
var name = CurrentUser.UserName;
|
return Task.CompletedTask;
|
||||||
var loginUser = new LoginLogAggregateRoot().GetInfoByHttpContext(_httpContext);
|
|
||||||
|
|
||||||
OnlineUserModel user = new(Context.ConnectionId)
|
|
||||||
{
|
|
||||||
Browser = loginUser?.Browser,
|
|
||||||
LoginLocation = loginUser?.LoginLocation,
|
|
||||||
Ipaddr = loginUser?.LoginIp,
|
|
||||||
LoginTime = DateTime.Now,
|
|
||||||
Os = loginUser?.Os,
|
|
||||||
UserName = name ?? "Null",
|
|
||||||
UserId = CurrentUser.Id ?? Guid.Empty
|
|
||||||
};
|
|
||||||
|
|
||||||
//已登录
|
|
||||||
if (CurrentUser.Id is not null)
|
|
||||||
{ //先移除之前的用户id,一个用户只能一个
|
|
||||||
clientUsers.RemoveAll(u => u.UserId == CurrentUser.Id);
|
|
||||||
_logger.LogInformation($"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{clientUsers.Count}个");
|
|
||||||
}
|
|
||||||
//全部移除之后,再进行添加
|
|
||||||
clientUsers.RemoveAll(u => u.ConnnectionId == Context.ConnectionId);
|
|
||||||
|
|
||||||
clientUsers.Add(user);
|
|
||||||
//当有人加入,向全部客户端发送当前总数
|
|
||||||
Clients.All.SendAsync("onlineNum", clientUsers.Count);
|
|
||||||
}
|
}
|
||||||
|
var name = CurrentUser.UserName;
|
||||||
|
var loginUser = new LoginLogAggregateRoot().GetInfoByHttpContext(_httpContext);
|
||||||
|
|
||||||
|
OnlineUserModel user = new(Context.ConnectionId)
|
||||||
|
{
|
||||||
|
Browser = loginUser?.Browser,
|
||||||
|
LoginLocation = loginUser?.LoginLocation,
|
||||||
|
Ipaddr = loginUser?.LoginIp,
|
||||||
|
LoginTime = DateTime.Now,
|
||||||
|
Os = loginUser?.Os,
|
||||||
|
UserName = name ?? "Null",
|
||||||
|
UserId = CurrentUser.Id ?? Guid.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
//已登录
|
||||||
|
if (CurrentUser.IsAuthenticated)
|
||||||
|
{
|
||||||
|
ClientUsersDic.RemoveAll(u => u.Value.UserId == CurrentUser.Id);
|
||||||
|
_logger.LogDebug(
|
||||||
|
$"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{ClientUsersDic.Count}个");
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientUsersDic.AddOrUpdate(Context.ConnectionId, user, (_, _) => user);
|
||||||
|
|
||||||
|
//当有人加入,向全部客户端发送当前总数
|
||||||
|
Clients.All.SendAsync("onlineNum", ClientUsersDic.Count);
|
||||||
|
|
||||||
return base.OnConnectedAsync();
|
return base.OnConnectedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,22 +71,17 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="exception"></param>
|
/// <param name="exception"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override Task OnDisconnectedAsync(Exception exception)
|
public override Task OnDisconnectedAsync(Exception? exception)
|
||||||
{
|
{
|
||||||
lock (objLock)
|
//已登录
|
||||||
|
if (CurrentUser.IsAuthenticated)
|
||||||
{
|
{
|
||||||
//已登录
|
ClientUsersDic.RemoveAll(u => u.Value.UserId == CurrentUser.Id);
|
||||||
if (CurrentUser.Id is not null)
|
_logger.LogDebug($"用户{CurrentUser?.UserName}离开了,当前已连接{ClientUsersDic.Count}个");
|
||||||
{
|
|
||||||
clientUsers.RemoveAll(u => u.UserId == CurrentUser.Id);
|
|
||||||
_logger.LogInformation($"用户{CurrentUser?.UserName}离开了,当前已连接{clientUsers.Count}个");
|
|
||||||
}
|
|
||||||
clientUsers.RemoveAll(u => u.ConnnectionId == Context.ConnectionId);
|
|
||||||
Clients.All.SendAsync("onlineNum", clientUsers.Count);
|
|
||||||
}
|
}
|
||||||
|
ClientUsersDic.Remove(Context.ConnectionId, out _);
|
||||||
|
Clients.All.SendAsync("onlineNum", ClientUsersDic.Count);
|
||||||
return base.OnDisconnectedAsync(exception);
|
return base.OnDisconnectedAsync(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,13 +10,15 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
|
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
|
||||||
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="$(AbpVersion)" />
|
<PackageReference Include="Volo.Abp.BackgroundJobs.Hangfire" Version="$(AbpVersion)" />
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
|
<ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
|
||||||
<ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
|
<ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" />
|
<ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Lazy.Captcha.Core.Generator;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.BackgroundWorkers;
|
using Volo.Abp.BackgroundWorkers;
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
using Yi.Framework.Ddd.Application;
|
using Yi.Framework.Ddd.Application;
|
||||||
using Yi.Framework.Rbac.Application.Contracts;
|
using Yi.Framework.Rbac.Application.Contracts;
|
||||||
@@ -15,8 +16,7 @@ namespace Yi.Framework.Rbac.Application
|
|||||||
typeof(YiFrameworkRbacDomainModule),
|
typeof(YiFrameworkRbacDomainModule),
|
||||||
|
|
||||||
|
|
||||||
typeof(YiFrameworkDddApplicationModule),
|
typeof(YiFrameworkDddApplicationModule)
|
||||||
typeof(AbpBackgroundWorkersQuartzModule)
|
|
||||||
)]
|
)]
|
||||||
public class YiFrameworkRbacApplicationModule : AbpModule
|
public class YiFrameworkRbacApplicationModule : AbpModule
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,10 @@ namespace Yi.Framework.Rbac.Application
|
|||||||
{
|
{
|
||||||
var service = context.Services;
|
var service = context.Services;
|
||||||
|
|
||||||
service.AddCaptcha();
|
service.AddCaptcha(options =>
|
||||||
|
{
|
||||||
|
options.CaptchaType = CaptchaType.ARITHMETIC;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace Yi.Framework.Rbac.Domain.Shared.Dtos
|
|||||||
public HashSet<RoleDto> Roles { get; set; } = new();
|
public HashSet<RoleDto> Roles { get; set; } = new();
|
||||||
public HashSet<MenuDto> Menus { get; set; } = new();
|
public HashSet<MenuDto> Menus { get; set; } = new();
|
||||||
|
|
||||||
public List<string> RoleCodes { get; set; } = new();
|
public HashSet<string> RoleCodes { get; set; } = new();
|
||||||
public List<string> PermissionCodes { get; set; } = new();
|
public HashSet<string> PermissionCodes { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserDto
|
public class UserDto
|
||||||
|
|||||||
@@ -217,8 +217,8 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dto.PermissionCodes?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
dto.PermissionCodes?.ToList()?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
||||||
dto.RoleCodes?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
dto.RoleCodes?.ToList()?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims;
|
return claims;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
|
|
||||||
public async Task SeedAsync(DataSeedContext context)
|
public async Task SeedAsync(DataSeedContext context)
|
||||||
{
|
{
|
||||||
if (!await _repository.IsAnyAsync(x => x.MenuName == "系统管理"&&x.MenuSource==MenuSourceEnum.Pure))
|
if (!await _repository.IsAnyAsync(x => x.MenuName == "系统管理" && x.MenuSource == MenuSourceEnum.Pure))
|
||||||
{
|
{
|
||||||
await _repository.InsertManyAsync(GetSeedData());
|
await _repository.InsertManyAsync(GetSeedData());
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
OrderNum = 100
|
OrderNum = 100
|
||||||
};
|
};
|
||||||
entities.Add(system);
|
entities.Add(system);
|
||||||
|
|
||||||
//系统监控
|
//系统监控
|
||||||
MenuAggregateRoot monitoring = new MenuAggregateRoot(_guidGenerator.Create())
|
MenuAggregateRoot monitoring = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
@@ -64,7 +64,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
};
|
};
|
||||||
entities.Add(online);
|
entities.Add(online);
|
||||||
|
|
||||||
|
|
||||||
//Yi框架
|
//Yi框架
|
||||||
MenuAggregateRoot guide = new MenuAggregateRoot(_guidGenerator.Create())
|
MenuAggregateRoot guide = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
Component = null
|
Component = null
|
||||||
};
|
};
|
||||||
entities.Add(guide);
|
entities.Add(guide);
|
||||||
|
|
||||||
//用户管理
|
//用户管理
|
||||||
MenuAggregateRoot user = new MenuAggregateRoot(_guidGenerator.Create())
|
MenuAggregateRoot user = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
@@ -141,7 +141,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
entities.Add(userRemove);
|
entities.Add(userRemove);
|
||||||
|
|
||||||
|
|
||||||
MenuAggregateRoot userResetPwd = new MenuAggregateRoot(_guidGenerator.Create())
|
MenuAggregateRoot userResetPwd = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
{
|
{
|
||||||
|
|
||||||
MenuName = "重置密码",
|
MenuName = "重置密码",
|
||||||
@@ -408,7 +408,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
IsDeleted = false
|
IsDeleted = false
|
||||||
};
|
};
|
||||||
entities.Add(postRemove);
|
entities.Add(postRemove);
|
||||||
|
|
||||||
|
|
||||||
//操作日志
|
//操作日志
|
||||||
MenuAggregateRoot operationLog = new MenuAggregateRoot(_guidGenerator.Create())
|
MenuAggregateRoot operationLog = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
@@ -491,10 +491,78 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds
|
|||||||
OrderNum = 100,
|
OrderNum = 100,
|
||||||
ParentId = loginLog.Id,
|
ParentId = loginLog.Id,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
|
|
||||||
};
|
};
|
||||||
entities.Add(loginLogRemove);
|
entities.Add(loginLogRemove);
|
||||||
|
|
||||||
|
//参数设置
|
||||||
|
MenuAggregateRoot config = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
{
|
||||||
|
|
||||||
|
MenuName = "参数设置",
|
||||||
|
PermissionCode = "system:config:list",
|
||||||
|
MenuType = MenuTypeEnum.Menu,
|
||||||
|
Router = "config",
|
||||||
|
IsShow = true,
|
||||||
|
IsLink = false,
|
||||||
|
IsCache = true,
|
||||||
|
Component = "/system/config/index",
|
||||||
|
MenuIcon = "ri:edit-box-line",
|
||||||
|
OrderNum = 94,
|
||||||
|
ParentId = system.Id,
|
||||||
|
IsDeleted = false
|
||||||
|
};
|
||||||
|
entities.Add(config);
|
||||||
|
|
||||||
|
MenuAggregateRoot configQuery = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
{
|
||||||
|
|
||||||
|
MenuName = "参数查询",
|
||||||
|
PermissionCode = "system:config:query",
|
||||||
|
MenuType = MenuTypeEnum.Component,
|
||||||
|
OrderNum = 100,
|
||||||
|
ParentId = config.Id,
|
||||||
|
IsDeleted = false
|
||||||
|
};
|
||||||
|
entities.Add(configQuery);
|
||||||
|
|
||||||
|
MenuAggregateRoot configAdd = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
{
|
||||||
|
|
||||||
|
MenuName = "参数新增",
|
||||||
|
PermissionCode = "system:config:add",
|
||||||
|
MenuType = MenuTypeEnum.Component,
|
||||||
|
OrderNum = 100,
|
||||||
|
ParentId = config.Id,
|
||||||
|
IsDeleted = false
|
||||||
|
};
|
||||||
|
entities.Add(configAdd);
|
||||||
|
|
||||||
|
MenuAggregateRoot configEdit = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
{
|
||||||
|
|
||||||
|
MenuName = "参数修改",
|
||||||
|
PermissionCode = "system:config:edit",
|
||||||
|
MenuType = MenuTypeEnum.Component,
|
||||||
|
OrderNum = 100,
|
||||||
|
ParentId = config.Id,
|
||||||
|
IsDeleted = false
|
||||||
|
};
|
||||||
|
entities.Add(configEdit);
|
||||||
|
|
||||||
|
MenuAggregateRoot configRemove = new MenuAggregateRoot(_guidGenerator.Create())
|
||||||
|
{
|
||||||
|
|
||||||
|
MenuName = "参数删除",
|
||||||
|
PermissionCode = "system:config:remove",
|
||||||
|
MenuType = MenuTypeEnum.Component,
|
||||||
|
OrderNum = 100,
|
||||||
|
ParentId = config.Id,
|
||||||
|
IsDeleted = false
|
||||||
|
};
|
||||||
|
entities.Add(configRemove);
|
||||||
|
|
||||||
|
|
||||||
//默认值
|
//默认值
|
||||||
entities.ForEach(m =>
|
entities.ForEach(m =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore
|
|||||||
{
|
{
|
||||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
{
|
{
|
||||||
context.Services.TryAddYiDbContext<YiRbacDbContext>();
|
context.Services.AddYiDbContext<YiRbacDbContext>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
using SqlSugar;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Data;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Users;
|
||||||
using Yi.Framework.Rbac.Domain.Authorization;
|
using Yi.Framework.Rbac.Domain.Authorization;
|
||||||
using Yi.Framework.Rbac.Domain.Entities;
|
using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.Rbac.Domain.Extensions;
|
using Yi.Framework.Rbac.Domain.Extensions;
|
||||||
@@ -11,22 +14,20 @@ namespace Yi.Framework.Rbac.SqlSugarCore
|
|||||||
{
|
{
|
||||||
public class YiRbacDbContext : SqlSugarDbContext
|
public class YiRbacDbContext : SqlSugarDbContext
|
||||||
{
|
{
|
||||||
public YiRbacDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
||||||
{
|
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
||||||
}
|
|
||||||
|
|
||||||
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||||
{
|
{
|
||||||
if (DataFilter.IsEnabled<IDataPermission>())
|
if (DataFilter.IsEnabled<IDataPermission>())
|
||||||
{
|
{
|
||||||
DataPermissionFilter(sqlSugarClient);
|
DataPermissionFilter(sqlSugarClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
base.CustomDataFilter(sqlSugarClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public YiRbacDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据权限过滤
|
/// 数据权限过滤
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -89,5 +90,6 @@ namespace Yi.Framework.Rbac.SqlSugarCore
|
|||||||
sqlSugarClient.QueryFilter.AddTableFilter(expUser.ToExpression());
|
sqlSugarClient.QueryFilter.AddTableFilter(expUser.ToExpression());
|
||||||
sqlSugarClient.QueryFilter.AddTableFilter(expRole.ToExpression());
|
sqlSugarClient.QueryFilter.AddTableFilter(expRole.ToExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Yi.Framework.TenantManagement.Domain.Shared
|
|
||||||
{
|
|
||||||
public class TenantConst
|
|
||||||
{
|
|
||||||
public static string TenantDbDefaultName = "Master";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Volo.Abp.TenantManagement.Domain.Shared" Version="8.0.0" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Volo.Abp.Modularity;
|
|
||||||
using Volo.Abp.TenantManagement;
|
|
||||||
|
|
||||||
namespace YiFrameworkTenantManagementDomain.Shared
|
|
||||||
{
|
|
||||||
[DependsOn(typeof(AbpTenantManagementDomainSharedModule))]
|
|
||||||
public class YiFrameworkTenantManagementDomainSharedModule : AbpModule
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application.Contracts\Yi.Framework.Ddd.Application.Contracts.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application.Contracts\Yi.Framework.Bbs.Application.Contracts.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Acme.BookStore.Domain.Shared.Enums;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Contracts.Dtos.Book
|
|
||||||
{
|
|
||||||
|
|
||||||
public class BookCreateUpdateDto
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
[StringLength(128)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
public BookTypeEnum Type { get; set; } = BookTypeEnum.Undefined;
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[DataType(DataType.Date)]
|
|
||||||
public DateTime PublishDate { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
public float Price { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using Acme.BookStore.Domain.Shared.Enums;
|
|
||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Contracts.Dtos.Book
|
|
||||||
{
|
|
||||||
public class BookDto : AuditedEntityDto<Guid>
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public BookTypeEnum Type { get; set; }
|
|
||||||
|
|
||||||
public DateTime PublishDate { get; set; }
|
|
||||||
|
|
||||||
public float Price { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using Acme.BookStore.Application.Contracts.Dtos.Book;
|
|
||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
using Yi.Framework.Ddd.Application.Contracts;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Contracts.IServices
|
|
||||||
{
|
|
||||||
public interface IBookAppService :
|
|
||||||
IYiCrudAppService< //Defines CRUD methods
|
|
||||||
BookDto, //Used to show books
|
|
||||||
Guid, //Primary key of the book entity
|
|
||||||
PagedAndSortedResultRequestDto, //Used for paging/sorting
|
|
||||||
BookCreateUpdateDto> //Used to create/update a book
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Volo.Abp.Modularity;
|
|
||||||
using Acme.BookStore.Domain.Shared;
|
|
||||||
using Yi.Framework.Bbs.Application.Contracts;
|
|
||||||
using Yi.Framework.Ddd.Application.Contracts;
|
|
||||||
using Yi.Framework.Rbac.Application.Contracts;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Contracts
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiAbpDomainSharedModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkRbacApplicationContractsModule),
|
|
||||||
typeof(YiFrameworkBbsApplicationContractsModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkDddApplicationContractsModule))]
|
|
||||||
public class YiAbpApplicationContractsModule:AbpModule
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.Application\Yi.Framework.Rbac.Application.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Jobs\" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using Quartz;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.BackgroundWorkers.Quartz;
|
|
||||||
using Volo.Abp.Domain.Repositories;
|
|
||||||
using Volo.Abp.Uow;
|
|
||||||
using Yi.Framework.Rbac.Domain.Entities;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Jobs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 定时任务
|
|
||||||
/// </summary>
|
|
||||||
public class TestJob : QuartzBackgroundWorkerBase
|
|
||||||
{
|
|
||||||
private ISqlSugarRepository<UserAggregateRoot> _repository;
|
|
||||||
public TestJob(ISqlSugarRepository<UserAggregateRoot> repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
JobDetail = JobBuilder.Create<TestJob>().WithIdentity(nameof(TestJob)).Build();
|
|
||||||
Trigger = TriggerBuilder.Create().WithIdentity(nameof(TestJob)).StartNow()
|
|
||||||
.WithSimpleSchedule(x => x
|
|
||||||
.WithIntervalInSeconds(1000 * 60)
|
|
||||||
.RepeatForever())
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
public override async Task Execute(IJobExecutionContext context)
|
|
||||||
{
|
|
||||||
//定时任务,非常简单
|
|
||||||
Console.WriteLine("你好,世界");
|
|
||||||
// var eneities= await _repository.GetListAsync();
|
|
||||||
//var entities= await _sqlSugarClient.Queryable<UserEntity>().ToListAsync();
|
|
||||||
//await Console.Out.WriteLineAsync(entities.Count().ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Acme.BookStore.Application.Contracts.Dtos.Book;
|
|
||||||
using Acme.BookStore.Application.Contracts.IServices;
|
|
||||||
using Acme.BookStore.Domain.Entities;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
using Yi.Framework.Ddd.Application;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Services
|
|
||||||
{
|
|
||||||
public class BookAppService :
|
|
||||||
YiCrudAppService<
|
|
||||||
BookAggregateRoot, //The Book entity
|
|
||||||
BookDto, //Used to show books
|
|
||||||
Guid, //Primary key of the book entity
|
|
||||||
PagedAndSortedResultRequestDto, //Used for paging/sorting
|
|
||||||
BookCreateUpdateDto>, //Used to create/update a book
|
|
||||||
IBookAppService //implement the IBookAppService
|
|
||||||
{
|
|
||||||
private ISqlSugarRepository<BookAggregateRoot, Guid> _repository;
|
|
||||||
public BookAppService(ISqlSugarRepository<BookAggregateRoot, Guid> repository)
|
|
||||||
: base(repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<PagedResultDto<BookDto>> GetListAsync(PagedAndSortedResultRequestDto input)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
RefAsync<int> total = 0;
|
|
||||||
|
|
||||||
//由于直接查询接口基本上都是有包含查询条件的,默认内置的查询接口将无法满足业务的需求,所以基本上多查询都是有进行重写的
|
|
||||||
var entities = await _repository._DbQueryable
|
|
||||||
//.WhereIF(!string.IsNullOrEmpty(input.ConfigKey), x => x.ConfigKey.Contains(input.ConfigKey!))
|
|
||||||
// .WhereIF(!string.IsNullOrEmpty(input.ConfigName), x => x.ConfigName!.Contains(input.ConfigName!))
|
|
||||||
// .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<BookDto>(total, await MapToGetListOutputDtosAsync(entities));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Volo.Abp.Application.Services;
|
|
||||||
using Volo.Abp.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application.Services
|
|
||||||
{
|
|
||||||
public class TestService : ApplicationService
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 你好世界
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public string GetHelloWorld(string? name)
|
|
||||||
{
|
|
||||||
return name ?? "HelloWord";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Volo.Abp.Modularity;
|
|
||||||
using Acme.BookStore.Application.Contracts;
|
|
||||||
using Acme.BookStore.Domain;
|
|
||||||
using Yi.Framework.Bbs.Application;
|
|
||||||
using Yi.Framework.Ddd.Application;
|
|
||||||
using Yi.Framework.Rbac.Application;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Application
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiAbpApplicationContractsModule),
|
|
||||||
typeof(YiAbpDomainModule),
|
|
||||||
|
|
||||||
|
|
||||||
typeof(YiFrameworkRbacApplicationModule),
|
|
||||||
typeof(YiFrameworkBbsApplicationModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkDddApplicationModule)
|
|
||||||
)]
|
|
||||||
public class YiAbpApplicationModule : AbpModule
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="$(AbpVersion)" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Domain.Shared\Yi.Framework.Bbs.Domain.Shared.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.Domain.Shared\Yi.Framework.Rbac.Domain.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Consts\" />
|
|
||||||
<Folder Include="Dtos\" />
|
|
||||||
<Folder Include="Etos\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Domain.Shared.Enums
|
|
||||||
{
|
|
||||||
public enum BookTypeEnum
|
|
||||||
{
|
|
||||||
Undefined,
|
|
||||||
Adventure,
|
|
||||||
Biography,
|
|
||||||
Dystopia,
|
|
||||||
Fantastic,
|
|
||||||
Horror,
|
|
||||||
Science,
|
|
||||||
ScienceFiction,
|
|
||||||
Poetry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Volo.Abp.Domain;
|
|
||||||
using Volo.Abp.Modularity;
|
|
||||||
using Yi.Framework.Bbs.Domain.Shared;
|
|
||||||
using Yi.Framework.Rbac.Domain.Shared;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Domain.Shared
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiFrameworkRbacDomainSharedModule),
|
|
||||||
typeof(YiFrameworkBbsDomainSharedModule),
|
|
||||||
|
|
||||||
typeof(AbpDddDomainSharedModule))]
|
|
||||||
public class YiAbpDomainSharedModule : AbpModule
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
|
|
||||||
<PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" />
|
|
||||||
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj" />
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Domain\Yi.Framework.Bbs.Domain.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Managers\" />
|
|
||||||
<Folder Include="Repositories\" />
|
|
||||||
<Folder Include="EventHandlers\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Acme.BookStore.Domain.Shared.Enums;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.Data;
|
|
||||||
using Volo.Abp.Domain.Entities.Auditing;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Domain.Entities
|
|
||||||
{
|
|
||||||
[SugarTable("Book")]
|
|
||||||
public class BookAggregateRoot : AuditedAggregateRoot<Guid>
|
|
||||||
{
|
|
||||||
[SugarColumn(IsPrimaryKey = true)]
|
|
||||||
public override Guid Id { get; protected set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public BookTypeEnum Type { get; set; }
|
|
||||||
|
|
||||||
public DateTime PublishDate { get; set; }
|
|
||||||
|
|
||||||
public float Price { get; set; }
|
|
||||||
|
|
||||||
[SugarColumn(IsIgnore = true)]
|
|
||||||
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Volo.Abp.Caching;
|
|
||||||
using Volo.Abp.Domain;
|
|
||||||
using Volo.Abp.Modularity;
|
|
||||||
using Acme.BookStore.Domain.Shared;
|
|
||||||
using Yi.Framework.Bbs.Domain;
|
|
||||||
using Yi.Framework.Mapster;
|
|
||||||
using Yi.Framework.Rbac.Domain;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Domain
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiAbpDomainSharedModule),
|
|
||||||
|
|
||||||
|
|
||||||
typeof(YiFrameworkRbacDomainModule),
|
|
||||||
typeof(YiFrameworkBbsDomainModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkMapsterModule),
|
|
||||||
typeof(AbpDddDomainModule),
|
|
||||||
typeof(AbpCachingModule)
|
|
||||||
)]
|
|
||||||
public class YiAbpDomainModule : AbpModule
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj" />
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.SqlSugarCore\Yi.Framework.Bbs.SqlSugarCore.csproj" />
|
|
||||||
<ProjectReference Include="..\..\module\rbac\Yi.Framework.Rbac.SqlSugarCore\Yi.Framework.Rbac.SqlSugarCore.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Repositories\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using Acme.BookStore.Domain.Entities;
|
|
||||||
using Acme.BookStore.Domain.Shared.Enums;
|
|
||||||
using Volo.Abp.Data;
|
|
||||||
using Volo.Abp.DependencyInjection;
|
|
||||||
using Volo.Abp.Guids;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.SqlSugarCore.DataSeeds
|
|
||||||
{
|
|
||||||
public class BookStoreDataSeed : IDataSeedContributor, ITransientDependency
|
|
||||||
{
|
|
||||||
private ISqlSugarRepository<BookAggregateRoot> _bookRepository;
|
|
||||||
private IGuidGenerator _guidGenerator;
|
|
||||||
public BookStoreDataSeed(ISqlSugarRepository<BookAggregateRoot> repository, IGuidGenerator guidGenerator)
|
|
||||||
{
|
|
||||||
_bookRepository = repository;
|
|
||||||
_guidGenerator = guidGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SeedAsync(DataSeedContext context)
|
|
||||||
{
|
|
||||||
if (!await _bookRepository.IsAnyAsync(x => true))
|
|
||||||
{
|
|
||||||
await _bookRepository.InsertAsync(
|
|
||||||
new BookAggregateRoot
|
|
||||||
{
|
|
||||||
Name = "1984",
|
|
||||||
Type = BookTypeEnum.Dystopia,
|
|
||||||
PublishDate = new DateTime(1949, 6, 8),
|
|
||||||
Price = 19.84f
|
|
||||||
},
|
|
||||||
autoSave: true
|
|
||||||
);
|
|
||||||
|
|
||||||
await _bookRepository.InsertAsync(
|
|
||||||
new BookAggregateRoot
|
|
||||||
{
|
|
||||||
Name = "The Hitchhiker's Guide to the Galaxy",
|
|
||||||
Type = BookTypeEnum.ScienceFiction,
|
|
||||||
PublishDate = new DateTime(1995, 9, 27),
|
|
||||||
Price = 42.0f
|
|
||||||
},
|
|
||||||
autoSave: true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Volo.Abp.Modularity;
|
|
||||||
using Acme.BookStore.Domain;
|
|
||||||
using Acme.BookStore.SqlSugarCore;
|
|
||||||
using Yi.Framework.Bbs.SqlSugarCore;
|
|
||||||
using Yi.Framework.Mapster;
|
|
||||||
using Yi.Framework.Rbac.SqlSugarCore;
|
|
||||||
using Yi.Framework.SqlSugarCore;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.SqlsugarCore
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiAbpDomainModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkRbacSqlSugarCoreModule),
|
|
||||||
typeof(YiFrameworkBbsSqlSugarCoreModule),
|
|
||||||
|
|
||||||
typeof(YiFrameworkMapsterModule),
|
|
||||||
typeof(YiFrameworkSqlSugarCoreModule)
|
|
||||||
)]
|
|
||||||
public class YiAbpSqlSugarCoreModule : AbpModule
|
|
||||||
{
|
|
||||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
|
||||||
{
|
|
||||||
context.Services.AddYiDbContext<YiDbContext>();
|
|
||||||
//默认不开放,可根据项目需要是否Db直接对外开放
|
|
||||||
//context.Services.AddTransient(x => x.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.DependencyInjection;
|
|
||||||
using Yi.Framework.Rbac.SqlSugarCore;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.SqlSugarCore
|
|
||||||
{
|
|
||||||
public class YiDbContext : YiRbacDbContext
|
|
||||||
{
|
|
||||||
public YiDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
<Import Project="..\..\common.props" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
|
||||||
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="$(AbpVersion)" />
|
|
||||||
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(AbpVersion)" />
|
|
||||||
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="$(AbpVersion)" />
|
|
||||||
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.AspNetCore.Authentication.OAuth\Yi.Framework.AspNetCore.Authentication.OAuth.csproj" />
|
|
||||||
<ProjectReference Include="..\..\framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.Application\Acme.BookStore.Application.csproj" />
|
|
||||||
<ProjectReference Include="..\Acme.BookStore.SqlSugarCore\Acme.BookStore.SqlSugarCore.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Update="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Update="wwwroot\icon\**">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Update="ip2region.db">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="database_backup\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using Serilog;
|
|
||||||
using Serilog.Events;
|
|
||||||
using Acme.BookStore.Web;
|
|
||||||
|
|
||||||
//创建日志,可使用{SourceContext}记录
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
|
||||||
.MinimumLevel.Debug()
|
|
||||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Error)
|
|
||||||
.MinimumLevel.Override("Quartz", LogEventLevel.Warning)
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug))
|
|
||||||
.WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Error))
|
|
||||||
.WriteTo.Async(c => c.Console(restrictedToMinimumLevel: LogEventLevel.Information))
|
|
||||||
.CreateLogger();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Log.Information("Yi框架-Abp.vNext,启动!");
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
builder.WebHost.UseUrls(builder.Configuration["App:SelfUrl"]);
|
|
||||||
builder.Host.UseAutofac();
|
|
||||||
builder.Host.UseSerilog();
|
|
||||||
await builder.Services.AddApplicationAsync<YiAbpWebModule>();
|
|
||||||
var app = builder.Build();
|
|
||||||
await app.InitializeApplicationAsync();
|
|
||||||
await app.RunAsync();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Fatal(ex, "Yi框架-Abp.vNext,爆炸!");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Log.CloseAndFlush();
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
|
||||||
"Acme.BookStore.Web": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "swagger",
|
|
||||||
"applicationUrl": "http://localhost:19001",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Cors;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
using Volo.Abp;
|
|
||||||
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Volo.Abp.AspNetCore.Mvc;
|
|
||||||
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
|
|
||||||
using Volo.Abp.AspNetCore.Serilog;
|
|
||||||
using Volo.Abp.Auditing;
|
|
||||||
using Volo.Abp.Autofac;
|
|
||||||
using Volo.Abp.Modularity;
|
|
||||||
using Volo.Abp.Swashbuckle;
|
|
||||||
using Acme.BookStore.Application;
|
|
||||||
using Acme.BookStore.SqlsugarCore;
|
|
||||||
using Yi.Framework.AspNetCore;
|
|
||||||
using Yi.Framework.AspNetCore.Authentication.OAuth;
|
|
||||||
using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
|
||||||
using Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
|
|
||||||
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder;
|
|
||||||
using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Yi.Framework.Bbs.Application;
|
|
||||||
using Yi.Framework.Rbac.Application;
|
|
||||||
using Yi.Framework.Rbac.Domain.Shared.Options;
|
|
||||||
|
|
||||||
namespace Acme.BookStore.Web
|
|
||||||
{
|
|
||||||
[DependsOn(
|
|
||||||
typeof(YiAbpSqlSugarCoreModule),
|
|
||||||
typeof(YiAbpApplicationModule),
|
|
||||||
|
|
||||||
|
|
||||||
typeof(AbpAspNetCoreMvcModule),
|
|
||||||
typeof(AbpAutofacModule),
|
|
||||||
typeof(AbpSwashbuckleModule),
|
|
||||||
typeof(AbpAspNetCoreSerilogModule),
|
|
||||||
typeof(AbpAuditingModule),
|
|
||||||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
|
|
||||||
typeof(YiFrameworkAspNetCoreModule),
|
|
||||||
typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule)
|
|
||||||
|
|
||||||
)]
|
|
||||||
public class YiAbpWebModule : AbpModule
|
|
||||||
{
|
|
||||||
private const string DefaultCorsPolicyName = "Default";
|
|
||||||
public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
|
|
||||||
{
|
|
||||||
var configuration = context.Services.GetConfiguration();
|
|
||||||
var host = context.Services.GetHostingEnvironment();
|
|
||||||
var service = context.Services;
|
|
||||||
|
|
||||||
//请求日志
|
|
||||||
Configure<AbpAuditingOptions>(optios =>
|
|
||||||
{
|
|
||||||
optios.IsEnabled = true;
|
|
||||||
optios.AlwaysLogSelectors.Add(x => Task.FromResult(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
//动态Api
|
|
||||||
Configure<AbpAspNetCoreMvcOptions>(options =>
|
|
||||||
{
|
|
||||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, options => options.RemoteServiceName = "default");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly, options => options.RemoteServiceName = "rbac");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly, options => options.RemoteServiceName = "bbs");
|
|
||||||
});
|
|
||||||
|
|
||||||
//设置api格式
|
|
||||||
service.AddControllers().AddNewtonsoftJson(options =>
|
|
||||||
{
|
|
||||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
options.SerializerSettings.Converters.Add(new StringEnumConverter());
|
|
||||||
});
|
|
||||||
|
|
||||||
Configure<AbpAntiForgeryOptions>(options =>
|
|
||||||
{
|
|
||||||
options.AutoValidate = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
//Swagger
|
|
||||||
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
|
|
||||||
{
|
|
||||||
options.SwaggerDoc("default", new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
|
|
||||||
});
|
|
||||||
|
|
||||||
//跨域
|
|
||||||
context.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy(DefaultCorsPolicyName, builder =>
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
.WithOrigins(
|
|
||||||
configuration["App:CorsOrigins"]!
|
|
||||||
.Split(";", StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(o => o.RemovePostFix("/"))
|
|
||||||
.ToArray()
|
|
||||||
)
|
|
||||||
.WithAbpExposedHeaders()
|
|
||||||
.SetIsOriginAllowedToAllowWildcardSubdomains()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowCredentials();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
//jwt鉴权
|
|
||||||
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
|
|
||||||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ClockSkew = TimeSpan.Zero,
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidateLifetime = true,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
ValidIssuer = jwtOptions.Issuer,
|
|
||||||
ValidAudience = jwtOptions.Audience,
|
|
||||||
RequireExpirationTime = true,
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
|
|
||||||
};
|
|
||||||
options.Events = new JwtBearerEvents
|
|
||||||
{
|
|
||||||
OnMessageReceived = context =>
|
|
||||||
{
|
|
||||||
var accessToken = context.Request.Query["access_token"];
|
|
||||||
if (!string.IsNullOrEmpty(accessToken))
|
|
||||||
{
|
|
||||||
context.Token = accessToken;
|
|
||||||
}
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.AddQQ(options =>
|
|
||||||
{
|
|
||||||
configuration.GetSection("OAuth:QQ").Bind(options);
|
|
||||||
})
|
|
||||||
.AddGitee(options =>
|
|
||||||
{
|
|
||||||
configuration.GetSection("OAuth:Gitee").Bind(options);
|
|
||||||
});
|
|
||||||
|
|
||||||
//授权
|
|
||||||
context.Services.AddAuthorization();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
|
||||||
{
|
|
||||||
var service = context.ServiceProvider;
|
|
||||||
|
|
||||||
var env = context.GetEnvironment();
|
|
||||||
var app = context.GetApplicationBuilder();
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
//跨域
|
|
||||||
app.UseCors(DefaultCorsPolicyName);
|
|
||||||
|
|
||||||
//鉴权
|
|
||||||
app.UseAuthentication();
|
|
||||||
|
|
||||||
//swagger
|
|
||||||
app.UseYiSwagger();
|
|
||||||
|
|
||||||
//请求处理
|
|
||||||
app.UseYiApiHandlinge();
|
|
||||||
|
|
||||||
//静态资源
|
|
||||||
app.UseStaticFiles("/api/app/wwwroot");
|
|
||||||
app.UseDefaultFiles();
|
|
||||||
app.UseDirectoryBrowser("/api/app/wwwroot");
|
|
||||||
|
|
||||||
//工作单元
|
|
||||||
app.UseUnitOfWork();
|
|
||||||
|
|
||||||
//授权
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
//审计日志
|
|
||||||
app.UseAuditing();
|
|
||||||
|
|
||||||
//日志记录
|
|
||||||
app.UseAbpSerilogEnrichers();
|
|
||||||
|
|
||||||
//终节点
|
|
||||||
app.UseConfiguredEndpoints();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
//"Default": "Information",
|
|
||||||
"Default": "Debug",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//应用启动
|
|
||||||
"App": {
|
|
||||||
"SelfUrl": "http://*:19001",
|
|
||||||
"CorsOrigins": "http://localhost:19001;http://localhost:18000"
|
|
||||||
},
|
|
||||||
|
|
||||||
//数据库类型列表
|
|
||||||
"DbList": [ "Sqlite", "Mysql", "Sqlserver", "Oracle", "PostgreSQL" ],
|
|
||||||
|
|
||||||
"DbConnOptions": {
|
|
||||||
"Url": "DataSource=yi-abp-dev.db",
|
|
||||||
"DbType": "Sqlite",
|
|
||||||
"EnabledReadWrite": false,
|
|
||||||
"EnabledCodeFirst": true,
|
|
||||||
"EnabledSqlLog": true,
|
|
||||||
"EnabledDbSeed": true,
|
|
||||||
"EnableUnderLine": false // 启用驼峰转下划线
|
|
||||||
//读写分离地址
|
|
||||||
//"ReadUrl": [
|
|
||||||
// "DataSource=[xxxx]", //Sqlite
|
|
||||||
// "server=[xxxx];port=3306;database=[xxxx];user id=[xxxx];password=[xxxx]", //Mysql
|
|
||||||
// "Data Source=[xxxx];Initial Catalog=[xxxx];User ID=[xxxx];password=[xxxx]" //Sqlserver
|
|
||||||
// "HOST=[xxxx];PORT=5432;DATABASE=[xxxx];USERID=[xxxx];PASSWORD=[xxxx]" //PostgreSQL
|
|
||||||
//]
|
|
||||||
},
|
|
||||||
|
|
||||||
//鉴权
|
|
||||||
"JwtOptions": {
|
|
||||||
"Issuer": "https://ccnetcore.com",
|
|
||||||
"Audience": "https://ccnetcore.com",
|
|
||||||
"SecurityKey": "zqxwcevrbtnymu312412ihe9rfwhe78rh23djoi32hrui3ryf9e8wfh34iuj54y0934uti4h97fgw7hf97wyh8yy69520",
|
|
||||||
"ExpiresMinuteTime": 86400
|
|
||||||
},
|
|
||||||
|
|
||||||
//第三方登录
|
|
||||||
"OAuth": {
|
|
||||||
//QQ
|
|
||||||
"QQ": {
|
|
||||||
"ClientId": "",
|
|
||||||
"ClientSecret": "",
|
|
||||||
"RedirectUri": ""
|
|
||||||
},
|
|
||||||
//码云
|
|
||||||
"Gitee": {
|
|
||||||
"ClientId": "",
|
|
||||||
"ClientSecret": "",
|
|
||||||
"RedirectUri": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
//Rbac模块
|
|
||||||
"RbacOptions": {
|
|
||||||
//超级管理员种子数据默认密码
|
|
||||||
"AdminPassword": "123456",
|
|
||||||
|
|
||||||
//是否开启验证码验证
|
|
||||||
"EnableCaptcha": true,
|
|
||||||
|
|
||||||
//是否开启注册功能
|
|
||||||
"EnableRegister": false,
|
|
||||||
|
|
||||||
//开启定时数据库备份
|
|
||||||
"EnableDataBaseBackup": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user