diff --git a/Yi.Framework.Net6/Build.props b/Yi.Framework.Net6/Build.props new file mode 100644 index 00000000..ee47ef8a --- /dev/null +++ b/Yi.Framework.Net6/Build.props @@ -0,0 +1,3 @@ + + + diff --git a/Yi.Framework.Net6/Version.cs b/Yi.Framework.Net6/Version.cs new file mode 100644 index 00000000..f5b81f50 --- /dev/null +++ b/Yi.Framework.Net6/Version.cs @@ -0,0 +1,90 @@ + +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyCompany("YiFramework")] +[assembly: AssemblyFileVersion(VersionInfo.FullVersion)] +[assembly: AssemblyInformationalVersion(VersionInfo.FullVersion)] +[assembly: AssemblyVersion(VersionInfo.FullVersion)] +[assembly: ComVisible(false)] + +#pragma warning disable IDE1006 // 命名样式 +internal static class VersionInfo +{ + /// + /// 主版本: 项目进行了重大修改,导致不再向下兼容,主版本号加1,其它版本号清0; + /// + public const string Major = "1"; + + /// + /// 次版本:项目进行了重构,增加了功能,但向下兼容,子版本号加1,主版本号不变, 修正版本号清0; + /// + public const string Minor = "1"; + + /// + /// 生成号 + /// + public const string Build = "0"; + + /// + /// 修订号:项目进行了Bug修复,向下兼容,修正版本号加1,主版本号、子版本号不 变; + /// + public const string Revision = "0"; + + /// + /// 版本名称 + /// + public const string VersionName = null; + + /// + /// 版本 + /// + public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision; +#pragma warning disable CS1570 // XML 注释出现 XML 格式错误 + /// + /// 比较 a,b两个版本 + /// 当 a > b 时,返回 1 + /// 当 a = b 时,返回 0 + /// 当 a < b 时,返回 -1 + /// +#pragma warning restore CS1570 // XML 注释出现 XML 格式错误 + public static int Compare(this Version a, Version b) + + { + // 比较主版本 + if (a.Major != b.Major) + { + return a.Major > b.Major ? 1 : -1; + } + + // 比较次版本 + if (a.Minor != b.Minor) + { + return a.Minor > b.Minor ? 1 : -1; + } + + // 比较生成号 + if (a.Build < 0 || b.Build < 0) + { + return 0; + } + + if (a.Build != b.Build) + { + return a.Build > b.Build ? 1 : -1; + } + + // 比较修订号 + if (a.Revision < 0 || b.Revision < 0) + { + return 0; + } + if (a.Revision != b.Revision) + { + return a.Revision > b.Revision ? 1 : -1; + } + + return 0; + } +#pragma warning restore IDE1006 // 命名样式 +} \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.sln b/Yi.Framework.Net6/Yi.Framework.sln new file mode 100644 index 00000000..c47f2103 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.sln @@ -0,0 +1,332 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33103.184 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{EEF5F221-0E32-4A3D-B647-B4B5E7305806}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{32A813F5-13B2-4DCA-8B59-F27F1B0D5678}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{5F2B846D-96CE-400A-878E-220498F4EE31}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core", "src\framework\Yi.Framework.Core\Yi.Framework.Core.csproj", "{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Application", "src\project\template\Yi.Template.Application\Yi.Template.Application.csproj", "{456835D1-4968-4195-9993-B2A580E85056}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Application.Contracts", "src\project\template\Yi.Template.Application.Contracts\Yi.Template.Application.Contracts.csproj", "{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Domain", "src\project\template\Yi.Template.Domain\Yi.Template.Domain.csproj", "{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Domain.Shared", "src\project\template\Yi.Template.Domain.Shared\Yi.Template.Domain.Shared.csproj", "{26171153-1784-455B-9582-0558AEEC03CF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Sqlsugar", "src\project\template\Yi.Template.Sqlsugar\Yi.Template.Sqlsugar.csproj", "{3C3A7BAC-F27F-433E-BF91-289FA42E4995}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Web", "src\project\template\Yi.Template.Web\Yi.Template.Web.csproj", "{01CC7B62-F42C-45CE-BACA-F450593A1AF2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.BackgroundJobs.Quartz", "src\module\Yi.Framework.BackgroundJobs.Quartz\Yi.Framework.BackgroundJobs.Quartz.csproj", "{1879A863-9864-4E16-8492-504055807684}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd", "src\framework\Yi.Framework.Ddd\Yi.Framework.Ddd.csproj", "{949F35A7-36E4-4080-9940-24BE52532078}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Autofac", "src\framework\Yi.Framework.Core.Autofac\Yi.Framework.Core.Autofac.csproj", "{63BA134E-9D23-4EB8-87E4-B45B33D954F5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore", "src\framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj", "{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching", "src\module\Yi.Framework.Caching\Yi.Framework.Caching.csproj", "{8767C5B7-3A17-4729-BCAA-B391B6A215AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.Redis", "src\module\Yi.Framework.Caching.Redis\Yi.Framework.Caching.Redis.csproj", "{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.MemoryCache", "src\module\Yi.Framework.Caching.MemoryCache\Yi.Framework.Caching.MemoryCache.csproj", "{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Uow", "src\framework\Yi.Framework.Uow\Yi.Framework.Uow.csproj", "{3D83BE69-71BB-43BE-B3F1-A532215561CD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Sqlsugar", "src\framework\Yi.Framework.Core.Sqlsugar\Yi.Framework.Core.Sqlsugar.csproj", "{58F4071D-66B7-4839-A247-79AF0E4E1C8E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Mapster", "src\framework\Yi.Framework.Core.AutoMapper\Yi.Framework.Core.Mapster.csproj", "{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Office.Excel", "src\module\Yi.Framework.Office.Excel\Yi.Framework.Office.Excel.csproj", "{4EEC6607-F0D8-4277-9463-104DA7E184B6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.WeChatPay", "src\module\Yi.Framework.WeChatPay\Yi.Framework.WeChatPay.csproj", "{588D0DA9-303A-4FF0-A2D1-83037E2B269F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Data", "src\framework\Yi.Framework.Data\Yi.Framework.Data.csproj", "{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Auth.JwtBearer", "src\framework\Yi.Framework.Auth.JwtBearer\Yi.Framework.Auth.JwtBearer.csproj", "{D40C583D-58BE-422D-9A57-94DECB751EB4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Template", "src\module\Yi.Framework.Template\Yi.Framework.Template.csproj", "{134C4AB9-2AFE-4383-84DE-825DF9499CB4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "template", "template", "{A3707874-7890-42AF-A686-E3AACD6F108C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bbs", "bbs", "{B758A87D-0BFA-44A5-BA33-FBA44151CEB4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Domain.Shared", "src\project\bbs\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj", "{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Domain", "src\project\bbs\Yi.BBS.Domain\Yi.BBS.Domain.csproj", "{86C82BB6-E333-40E8-8DDE-20C3A538433C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Application.Contracts", "src\project\bbs\Yi.BBS.Application.Contracts\Yi.BBS.Application.Contracts.csproj", "{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Sqlsugar", "src\project\bbs\Yi.BBS.Sqlsugar\Yi.BBS.Sqlsugar.csproj", "{A8043204-9DAC-4F08-8C73-423CB72927EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Web", "src\project\bbs\Yi.BBS.Web\Yi.BBS.Web.csproj", "{83BE964D-D53C-4D1B-B8C6-5306C393C07F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Application", "src\project\bbs\Yi.BBS.Application\Yi.BBS.Application.csproj", "{959A33C5-7826-4AE7-AC51-40BDC2B767B2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rbac", "rbac", "{07C9E949-DB5E-4315-A497-FF73746667D8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Domain.Shared", "src\project\rbac\Yi.RBAC.Domain.Shared\Yi.RBAC.Domain.Shared.csproj", "{5467178B-3731-4346-A0A3-3CB1AC0953AB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Domain", "src\project\rbac\Yi.RBAC.Domain\Yi.RBAC.Domain.csproj", "{2E082104-D3A6-40DE-A4E5-DE326B75A62D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Sqlsugar", "src\project\rbac\Yi.RBAC.Sqlsugar\Yi.RBAC.Sqlsugar.csproj", "{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Application.Contracts", "src\project\rbac\Yi.RBAC.Application.Contracts\Yi.RBAC.Application.Contracts.csproj", "{478DA36E-F547-49CD-8B48-41DC5551C5C2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Application", "src\project\rbac\Yi.RBAC.Application\Yi.RBAC.Application.csproj", "{2074EA00-59A4-49CE-97A6-735F4B77443B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Web", "src\project\rbac\Yi.RBAC.Web\Yi.RBAC.Web.csproj", "{0C031C7D-6F80-4559-977C-AC001036EC44}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ImageSharp", "src\module\Yi.Framework.ImageSharp\Yi.Framework.ImageSharp.csproj", "{60E54034-792C-4A90-BCDF-4D5FFB45089E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.EventBus", "src\module\Yi.Framework.EventBus\Yi.Framework.EventBus.csproj", "{FC559052-36EC-4379-B447-298FAD6045F4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{12EA3BCF-8991-4010-B41E-67C476CBA690}" + ProjectSection(SolutionItems) = preProject + ..\.gitignore = ..\.gitignore + Build.props = Build.props + ..\readme\git提交规范.txt = ..\readme\git提交规范.txt + src\project\rbac\GlobalUsings.cs = src\project\rbac\GlobalUsings.cs + Version.cs = Version.cs + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.OperLogManager", "src\module\Yi.Framework.OperLogManager\Yi.Framework.OperLogManager.csproj", "{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.FileManager", "src\module\Yi.Framework.FileManager\Yi.Framework.FileManager.csproj", "{1BF3115D-B027-4805-AF7B-41B3AE9CB355}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.MultiTenancy", "src\framework\Yi.Framework.MultiTenancy\Yi.Framework.MultiTenancy.csproj", "{590B1EC0-CDA9-4937-BE07-FBB04437D21F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.DictionaryManager", "src\module\Yi.Framework.DictionaryManager\Yi.Framework.DictionaryManager.csproj", "{8941B30D-698B-477A-8737-43E7B4A8695A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Sms.Aliyun", "src\module\Yi.Framework.Sms.Aliyun\Yi.Framework.Sms.Aliyun.csproj", "{063178CF-C5B9-463C-A8A4-F32B743818E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Release|Any CPU.Build.0 = Release|Any CPU + {456835D1-4968-4195-9993-B2A580E85056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {456835D1-4968-4195-9993-B2A580E85056}.Debug|Any CPU.Build.0 = Debug|Any CPU + {456835D1-4968-4195-9993-B2A580E85056}.Release|Any CPU.ActiveCfg = Release|Any CPU + {456835D1-4968-4195-9993-B2A580E85056}.Release|Any CPU.Build.0 = Release|Any CPU + {D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Release|Any CPU.Build.0 = Release|Any CPU + {C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Release|Any CPU.Build.0 = Release|Any CPU + {26171153-1784-455B-9582-0558AEEC03CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26171153-1784-455B-9582-0558AEEC03CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26171153-1784-455B-9582-0558AEEC03CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26171153-1784-455B-9582-0558AEEC03CF}.Release|Any CPU.Build.0 = Release|Any CPU + {3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Release|Any CPU.Build.0 = Release|Any CPU + {01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Release|Any CPU.Build.0 = Release|Any CPU + {1879A863-9864-4E16-8492-504055807684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1879A863-9864-4E16-8492-504055807684}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1879A863-9864-4E16-8492-504055807684}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1879A863-9864-4E16-8492-504055807684}.Release|Any CPU.Build.0 = Release|Any CPU + {949F35A7-36E4-4080-9940-24BE52532078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {949F35A7-36E4-4080-9940-24BE52532078}.Debug|Any CPU.Build.0 = Debug|Any CPU + {949F35A7-36E4-4080-9940-24BE52532078}.Release|Any CPU.ActiveCfg = Release|Any CPU + {949F35A7-36E4-4080-9940-24BE52532078}.Release|Any CPU.Build.0 = Release|Any CPU + {63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Release|Any CPU.Build.0 = Release|Any CPU + {2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Release|Any CPU.Build.0 = Release|Any CPU + {8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Release|Any CPU.Build.0 = Release|Any CPU + {F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Release|Any CPU.Build.0 = Release|Any CPU + {67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Release|Any CPU.Build.0 = Release|Any CPU + {3D83BE69-71BB-43BE-B3F1-A532215561CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D83BE69-71BB-43BE-B3F1-A532215561CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D83BE69-71BB-43BE-B3F1-A532215561CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D83BE69-71BB-43BE-B3F1-A532215561CD}.Release|Any CPU.Build.0 = Release|Any CPU + {58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Release|Any CPU.Build.0 = Release|Any CPU + {DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Release|Any CPU.Build.0 = Release|Any CPU + {4EEC6607-F0D8-4277-9463-104DA7E184B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4EEC6607-F0D8-4277-9463-104DA7E184B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4EEC6607-F0D8-4277-9463-104DA7E184B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4EEC6607-F0D8-4277-9463-104DA7E184B6}.Release|Any CPU.Build.0 = Release|Any CPU + {588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Release|Any CPU.Build.0 = Release|Any CPU + {DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Release|Any CPU.Build.0 = Release|Any CPU + {D40C583D-58BE-422D-9A57-94DECB751EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D40C583D-58BE-422D-9A57-94DECB751EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D40C583D-58BE-422D-9A57-94DECB751EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D40C583D-58BE-422D-9A57-94DECB751EB4}.Release|Any CPU.Build.0 = Release|Any CPU + {134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Release|Any CPU.Build.0 = Release|Any CPU + {DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Release|Any CPU.Build.0 = Release|Any CPU + {86C82BB6-E333-40E8-8DDE-20C3A538433C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86C82BB6-E333-40E8-8DDE-20C3A538433C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86C82BB6-E333-40E8-8DDE-20C3A538433C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86C82BB6-E333-40E8-8DDE-20C3A538433C}.Release|Any CPU.Build.0 = Release|Any CPU + {679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Release|Any CPU.Build.0 = Release|Any CPU + {A8043204-9DAC-4F08-8C73-423CB72927EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8043204-9DAC-4F08-8C73-423CB72927EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8043204-9DAC-4F08-8C73-423CB72927EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8043204-9DAC-4F08-8C73-423CB72927EF}.Release|Any CPU.Build.0 = Release|Any CPU + {83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Release|Any CPU.Build.0 = Release|Any CPU + {959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Release|Any CPU.Build.0 = Release|Any CPU + {5467178B-3731-4346-A0A3-3CB1AC0953AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5467178B-3731-4346-A0A3-3CB1AC0953AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5467178B-3731-4346-A0A3-3CB1AC0953AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5467178B-3731-4346-A0A3-3CB1AC0953AB}.Release|Any CPU.Build.0 = Release|Any CPU + {2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Release|Any CPU.Build.0 = Release|Any CPU + {ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Release|Any CPU.Build.0 = Release|Any CPU + {478DA36E-F547-49CD-8B48-41DC5551C5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {478DA36E-F547-49CD-8B48-41DC5551C5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {478DA36E-F547-49CD-8B48-41DC5551C5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {478DA36E-F547-49CD-8B48-41DC5551C5C2}.Release|Any CPU.Build.0 = Release|Any CPU + {2074EA00-59A4-49CE-97A6-735F4B77443B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2074EA00-59A4-49CE-97A6-735F4B77443B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2074EA00-59A4-49CE-97A6-735F4B77443B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2074EA00-59A4-49CE-97A6-735F4B77443B}.Release|Any CPU.Build.0 = Release|Any CPU + {0C031C7D-6F80-4559-977C-AC001036EC44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C031C7D-6F80-4559-977C-AC001036EC44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C031C7D-6F80-4559-977C-AC001036EC44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C031C7D-6F80-4559-977C-AC001036EC44}.Release|Any CPU.Build.0 = Release|Any CPU + {60E54034-792C-4A90-BCDF-4D5FFB45089E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60E54034-792C-4A90-BCDF-4D5FFB45089E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60E54034-792C-4A90-BCDF-4D5FFB45089E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60E54034-792C-4A90-BCDF-4D5FFB45089E}.Release|Any CPU.Build.0 = Release|Any CPU + {FC559052-36EC-4379-B447-298FAD6045F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC559052-36EC-4379-B447-298FAD6045F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC559052-36EC-4379-B447-298FAD6045F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC559052-36EC-4379-B447-298FAD6045F4}.Release|Any CPU.Build.0 = Release|Any CPU + {8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Release|Any CPU.Build.0 = Release|Any CPU + {1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Release|Any CPU.Build.0 = Release|Any CPU + {590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Release|Any CPU.Build.0 = Release|Any CPU + {8941B30D-698B-477A-8737-43E7B4A8695A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8941B30D-698B-477A-8737-43E7B4A8695A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8941B30D-698B-477A-8737-43E7B4A8695A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8941B30D-698B-477A-8737-43E7B4A8695A}.Release|Any CPU.Build.0 = Release|Any CPU + {063178CF-C5B9-463C-A8A4-F32B743818E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {063178CF-C5B9-463C-A8A4-F32B743818E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {063178CF-C5B9-463C-A8A4-F32B743818E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {063178CF-C5B9-463C-A8A4-F32B743818E2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {83B2D7AD-ED8E-4392-B0AE-4227498CD75F} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {456835D1-4968-4195-9993-B2A580E85056} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {D2378C23-2CFE-468A-924A-B8C9D4A3A8ED} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {26171153-1784-455B-9582-0558AEEC03CF} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {3C3A7BAC-F27F-433E-BF91-289FA42E4995} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {01CC7B62-F42C-45CE-BACA-F450593A1AF2} = {A3707874-7890-42AF-A686-E3AACD6F108C} + {1879A863-9864-4E16-8492-504055807684} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {949F35A7-36E4-4080-9940-24BE52532078} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {63BA134E-9D23-4EB8-87E4-B45B33D954F5} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {2F5E5843-14FB-48F1-AEB0-B9FFE103B972} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {8767C5B7-3A17-4729-BCAA-B391B6A215AA} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {3D83BE69-71BB-43BE-B3F1-A532215561CD} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {58F4071D-66B7-4839-A247-79AF0E4E1C8E} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {4EEC6607-F0D8-4277-9463-104DA7E184B6} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {588D0DA9-303A-4FF0-A2D1-83037E2B269F} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {DEE07142-32CE-4B5F-A5A3-452064EBF4A2} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {D40C583D-58BE-422D-9A57-94DECB751EB4} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {134C4AB9-2AFE-4383-84DE-825DF9499CB4} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {A3707874-7890-42AF-A686-E3AACD6F108C} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678} + {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678} + {DEA3342F-1954-4EE9-9A59-CAF1D7832F33} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {86C82BB6-E333-40E8-8DDE-20C3A538433C} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {A8043204-9DAC-4F08-8C73-423CB72927EF} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {83BE964D-D53C-4D1B-B8C6-5306C393C07F} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {959A33C5-7826-4AE7-AC51-40BDC2B767B2} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4} + {07C9E949-DB5E-4315-A497-FF73746667D8} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678} + {5467178B-3731-4346-A0A3-3CB1AC0953AB} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {2E082104-D3A6-40DE-A4E5-DE326B75A62D} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {ECF1AA6F-8FCD-428F-9648-2DAE3C345C96} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {478DA36E-F547-49CD-8B48-41DC5551C5C2} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {2074EA00-59A4-49CE-97A6-735F4B77443B} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {0C031C7D-6F80-4559-977C-AC001036EC44} = {07C9E949-DB5E-4315-A497-FF73746667D8} + {60E54034-792C-4A90-BCDF-4D5FFB45089E} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {FC559052-36EC-4379-B447-298FAD6045F4} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {8A604A6B-D1FA-4CFF-BCF5-557519B10FCB} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {1BF3115D-B027-4805-AF7B-41B3AE9CB355} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {590B1EC0-CDA9-4937-BE07-FBB04437D21F} = {5F2B846D-96CE-400A-878E-220498F4EE31} + {8941B30D-698B-477A-8737-43E7B4A8695A} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + {063178CF-C5B9-463C-A8A4-F32B743818E2} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6C1A3808-0F4F-43FB-A9FE-5F27A3BB2ECF} + EndGlobalSection +EndGlobal diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Extensions/HttpContextExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Extensions/HttpContextExtensions.cs new file mode 100644 index 00000000..b16e5509 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Extensions/HttpContextExtensions.cs @@ -0,0 +1,99 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Yi.Framework.AspNetCore.Extensions +{ + public static class HttpContextExtensions + { + /// + /// 设置文件下载名称 + /// + /// + /// + public static void FileInlineHandle(this HttpContext httpContext, string fileName) + { + string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8")); + httpContext.Response.Headers.Add("Content-Disposition", "inline;filename=" + encodeFilename); + + } + + /// + /// 设置文件附件名称 + /// + /// + /// + public static void FileAttachmentHandle(this HttpContext httpContext, string fileName) + { + string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8")); + httpContext.Response.Headers.Add("Content-Disposition", "attachment;filename=" + encodeFilename); + + } + + /// + /// 获取语言种类 + /// + /// + /// + public static string GetLanguage(this HttpContext httpContext) + { + string res = "zh-CN"; + var str = httpContext.Request.Headers["Accept-Language"].FirstOrDefault(); + if (str is not null) + { + res = str.Split(",")[0]; + } + return res; + + } + + /// + /// 判断是否为异步请求 + /// + /// + /// + public static bool IsAjaxRequest(this HttpRequest request) + { + string header = request.Headers["X-Requested-With"]; + return "XMLHttpRequest".Equals(header); + } + /// + /// 获取客户端IP + /// + /// + /// + public static string GetClientIp(this HttpContext context) + { + if (context == null) return ""; + var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + if (string.IsNullOrEmpty(result)) + { + result = context.Connection.RemoteIpAddress?.ToString(); + } + if (string.IsNullOrEmpty(result) || result.Contains("::1")) + result = "127.0.0.1"; + + result = result.Replace("::ffff:", "127.0.0.1"); + + //Ip规则效验 + var regResult = Regex.IsMatch(result, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); + + result = regResult ? result : "127.0.0.1"; + return result; + } + + /// + /// 获取浏览器标识 + /// + /// + /// + public static string GetUserAgent(this HttpContext context) + { + return context.Request.Headers["User-Agent"]; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/CorsUseExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/CorsUseExtensions.cs new file mode 100644 index 00000000..e4e85233 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/CorsUseExtensions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AspNetCore.Microsoft.AspNetCore.Builder +{ + public static class CorsUseExtensions + { + public static void UseCorsServer(this IApplicationBuilder app) + { + app.UseCors("CorsPolicy"); + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ErrorHandExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ErrorHandExtensions.cs new file mode 100644 index 00000000..85b05dc7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ErrorHandExtensions.cs @@ -0,0 +1,109 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Exceptions; + +namespace Microsoft.AspNetCore.Builder +{ + + internal class ExceptionModle + { + public int Code { get; set; } + public string? Message { get; set; } + public string? Details { get; set; } + } + public class ErrorHandMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + //private readonly IErrorHandle _errorHandle; + public ErrorHandMiddleware(RequestDelegate next, ILoggerFactory loggerFactory /*, IErrorHandle errorHandle*/) + { + this._next = next; + this._logger = loggerFactory.CreateLogger(); + } + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next(context); + } + catch (BusinessException businessEx) + { + context.Response.ContentType = "application/json;charset=utf-8"; + context.Response.StatusCode = (int)ResultCodeEnum.Denied; + + var result = new ExceptionModle + { + Code = businessEx.Code.GetHashCode(), + Message = businessEx.Message, + Details = businessEx.Details, + }; + //业务错误,不记录日志 + await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings() + { + //设置首字母小写 + ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() + })); + + } + catch (AuthException ex) + { + context.Response.ContentType = "application/json;charset=utf-8"; + //系统错误,记录日志 + _logger.LogError(ex, $"授权失败:{ex.Message}"); + //await _errorHandle.Invoer(context, ex); + context.Response.StatusCode = (int)ResultCodeEnum.NoPermission; + //系统错误,需要记录 + var result = new ExceptionModle + { + Code = ex.Code.GetHashCode(), + Message = ex.Message, + Details = "授权失败", + }; + await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings() + { + //设置首字母小写 + ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() + })); + + } + catch (Exception ex) + { + context.Response.ContentType = "application/json;charset=utf-8"; + //系统错误,记录日志 + _logger.LogError(ex, $"系统错误:{ex.Message}"); + //await _errorHandle.Invoer(context, ex); + context.Response.StatusCode = (int)ResultCodeEnum.NotSuccess; + //系统错误,需要记录 + var result = new ExceptionModle + { + Code = 500, + Message = ex.Message, + Details = "系统错误", + }; + await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings() + { + //设置首字母小写 + ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() + })); + } + } + + } + + public static class ErrorHandExtensions + { + public static IApplicationBuilder UseErrorHandlingServer(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerUseExtensons.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerUseExtensons.cs new file mode 100644 index 00000000..cf37af7b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerUseExtensons.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Swashbuckle.AspNetCore.SwaggerUI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AspNetCore.Microsoft.AspNetCore.Builder +{ + public static class SwaggerUseExtensons + { + public static IApplicationBuilder UseSwaggerServer(this IApplicationBuilder app, params SwaggerModel[] swaggerModels) + { + + app.UseSwagger(); + app.UseSwaggerUI(c => + { + if (swaggerModels.Length == 0) + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework"); + } + else + { + foreach (var k in swaggerModels) + { + + c.SwaggerEndpoint(k.Url, k.Name); + } + } + + }); + return app; + } + + } + public class SwaggerModel + { + public SwaggerModel(string name) + { + this.Name = name; + this.Url = "/swagger/v1/swagger.json"; + } + public SwaggerModel(string url, string name) + { + this.Url = url; + this.Name = name; + } + public string Url { get; set; } + public string Name { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Hosting/StratUrlsExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Hosting/StratUrlsExtensions.cs new file mode 100644 index 00000000..3076545d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Hosting/StratUrlsExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AspNetCore.Microsoft.AspNetCore.Hosting +{ + public static class StratUrlsExtensions + { + public static IWebHostBuilder UseStartUrlsServer(this IWebHostBuilder hostBuilder, IConfiguration configuration, string option = "StartUrl") + { + return hostBuilder.UseUrls(configuration.GetValue(option)); + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/ControllerAddExtension.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/ControllerAddExtension.cs new file mode 100644 index 00000000..cb17808a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/ControllerAddExtension.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection +{ + public static class ControllerAddExtension + { + public static IMvcBuilder AddNewtonsoftJsonServer(this IMvcBuilder mvcBuilder) + { + return mvcBuilder.AddNewtonsoftJson(opt => + { + //忽略循环引用 + opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + //不改变字段大小 + //opt.SerializerSettings.ContractResolver = new DefaultContractResolver(); + }); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CorsAddExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CorsAddExtensions.cs new file mode 100644 index 00000000..56daefe6 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CorsAddExtensions.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class CorsAddExtensions + { + public static IServiceCollection AddCorsServer(this IServiceCollection services) + { + services.AddCors(options => options.AddPolicy("CorsPolicy", + builder => + { + builder.AllowAnyMethod() + .SetIsOriginAllowed(_ => true) + .AllowAnyHeader() + .AllowCredentials(); + })); + return services; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CurrentUserAddExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CurrentUserAddExtensions.cs new file mode 100644 index 00000000..e6874c1a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/CurrentUserAddExtensions.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Const; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.CurrentUsers.Accessor; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class CurrentUserAddExtensions + { + public static IServiceCollection AddCurrentUserServer(this IServiceCollection services) + { + services.AddSingleton(); + return services.AddTransient(); + } + + + + } + + + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs new file mode 100644 index 00000000..16932d90 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class SwaggerAddExtensions + { + public static IServiceCollection AddSwaggerServer(this IServiceCollection services, string title = "Yi意框架-API接口") + { + var apiInfo = new OpenApiInfo + { + Title = title, + Version = "v1", + Contact = new OpenApiContact { Name = "橙子", Email = "454313500@qq.com", Url = new Uri("https://ccnetcore.com") } + }; + #region 注册Swagger服务 + services.AddSwaggerGen(c => + { + c.DocInclusionPredicate((docName, description) => true); + + c.SwaggerDoc("v1", apiInfo); + + + var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location); + if (basePath is not null) + { + foreach (var item in Directory.GetFiles(basePath, "*.xml")) + { + c.IncludeXmlComments(item, true); + } + } + + c.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" } + }; + c.AddSecurityRequirement(new OpenApiSecurityRequirement() + { + [scheme] = new string[0] + }); + }); + #endregion + + return services; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Yi.Framework.AspNetCore.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Yi.Framework.AspNetCore.csproj new file mode 100644 index 00000000..c37d68fb --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/Yi.Framework.AspNetCore.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs new file mode 100644 index 00000000..85f7cba7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers.Accessor; +using Yi.Framework.Core.CurrentUsers; + +namespace Yi.Framework.AspNetCore +{ + public class YiFrameworkAspNetCoreModule : IStartupModule + { + + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddHttpContextAccessor(); + services.AddCurrentUserServer(); + + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/JwtTokenManager.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/JwtTokenManager.cs new file mode 100644 index 00000000..70974444 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/JwtTokenManager.cs @@ -0,0 +1,100 @@ +using JWT; +using JWT.Algorithms; +using JWT.Builder; +using JWT.Exceptions; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Auth.JwtBearer.Authentication.Options; +using Yi.Framework.Core.Helper; + +namespace Yi.Framework.Auth.JwtBearer.Authentication +{ + public class JwtTokenManager + { + private JwtTokenOptions _jwtTokenOptions; + + public JwtTokenManager(IOptions options) + { + _jwtTokenOptions = options.Value; + } + public string CreateToken(Dictionary? claimDic) + { + var token = JwtBuilder.Create() + .WithAlgorithm(new RS256Algorithm(RSAFileHelper.GetKey(), RSAFileHelper.GetKey())) + .AddClaim(ClaimName.Issuer, _jwtTokenOptions.Issuer) + .AddClaim(ClaimName.Audience, _jwtTokenOptions.Audience) + .AddClaim(ClaimName.Subject, _jwtTokenOptions.Subject) + .AddClaim(ClaimName.IssuedAt, UnixEpoch.GetSecondsSince(new DateTimeOffset(DateTime.UtcNow))) + .ExpirationTime(DateTime.Now.AddSeconds(_jwtTokenOptions.ExpSecond)); + if (claimDic is not null) + { + foreach (var d in claimDic) + { + token.AddClaim(d.Key, d.Value); + }; + } + return token.Encode(); + } + + public IDictionary? VerifyToken(string token, TokenVerifyErrorAction tokenVerifyErrorAction) + { + IDictionary? claimDic = null; + try + { + + claimDic = JwtBuilder.Create() + .WithAlgorithm(new RS256Algorithm(RSAFileHelper.GetPublicKey())) + .WithValidationParameters(ValidationParameters.Default) + .Decode>(token); + } + catch (TokenNotYetValidException ex) + { + if (tokenVerifyErrorAction.TokenNotYetValidAction is not null) + { + tokenVerifyErrorAction.TokenNotYetValidAction(ex); + } + //Console.WriteLine("Token错误"); + } + catch (TokenExpiredException ex) + { + if (tokenVerifyErrorAction.TokenExpiredAction is not null) + { + tokenVerifyErrorAction.TokenExpiredAction(ex); + } + //Console.WriteLine("Token过期"); + } + catch (SignatureVerificationException ex) + { + if (tokenVerifyErrorAction.SignatureVerificationAction is not null) + { + tokenVerifyErrorAction.SignatureVerificationAction(ex); + } + //Console.WriteLine("Token无效"); + } + catch (Exception ex) + { + if (tokenVerifyErrorAction.ErrorAction is not null) + { + tokenVerifyErrorAction.ErrorAction(ex); + } + //Console.WriteLine("Token内部错误,json序列化"); + } + return claimDic; + + } + + public class TokenVerifyErrorAction + { + public Action? TokenNotYetValidAction { get; set; } + + public Action? TokenExpiredAction { get; set; } + public Action? SignatureVerificationAction { get; set; } + + public Action? ErrorAction { get; set; } + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/Options/JwtTokenOptions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/Options/JwtTokenOptions.cs new file mode 100644 index 00000000..c2643148 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/Options/JwtTokenOptions.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Auth.JwtBearer.Authentication.Options +{ + public class JwtTokenOptions + { + /// + /// 听众 + /// + public string Audience { get; set; } = string.Empty; + + /// + /// 发行者 + /// + public string Issuer { get; set; } = string.Empty; + + /// + /// 主题 + /// + public string Subject { get; set; } = string.Empty; + + /// + /// 过期时间,单位秒 + /// + public long ExpSecond { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/YiJwtAuthenticationHandler.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/YiJwtAuthenticationHandler.cs new file mode 100644 index 00000000..332fa901 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authentication/YiJwtAuthenticationHandler.cs @@ -0,0 +1,132 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using System.Net; +using System.Security.Claims; +using System.Text.Json; +using Yi.Framework.Core.Helper; + +namespace Yi.Framework.Auth.JwtBearer.Authentication +{ + public class YiJwtAuthenticationHandler : IAuthenticationHandler + { + private JwtTokenManager _jwtTokenManager; + public YiJwtAuthenticationHandler(JwtTokenManager jwtTokenManager) + { + _jwtTokenManager = jwtTokenManager; + } + public const string YiJwtSchemeName = "YiJwtAuth"; + + private AuthenticationScheme _scheme; + private HttpContext _context; + /// + /// 初始化数据 + /// + /// + /// + /// + public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) + { + _scheme = scheme; + _context = context; + return Task.CompletedTask; + } + + + /// + /// 生成认证票据 + /// + /// + /// + /// + private AuthenticationTicket GetAuthTicket(IDictionary dicClaims) + { + List claims = new List(); + foreach (var claim in dicClaims) + { + var p = (JsonElement)claim.Value; + string? resp=null; + switch (p.ValueKind) + { + + case JsonValueKind.String: + resp = p.GetString(); + break; + case JsonValueKind.Number: + resp = p.GetInt64().ToString(); + break; + } + claims.Add(new Claim(claim.Key, resp ?? "")); + } + var claimsIdentity = new ClaimsIdentity(claims.ToArray(), YiJwtSchemeName); + var principal = new ClaimsPrincipal(claimsIdentity); + return new AuthenticationTicket(principal, _scheme.Name); + } + + /// + /// 处理操作 + /// + /// + /// + public Task AuthenticateAsync() + { + AuthenticateResult result = AuthenticateResult.Fail("未发现授权令牌"); + _context.Request.Headers.TryGetValue("Authorization", out StringValues values); + string valStr = values.ToString(); + if (!string.IsNullOrWhiteSpace(valStr) && valStr.Length>10) + { + var tokenHeader = valStr.Substring(0, 6); + if (tokenHeader == "Bearer") + { + var token = valStr.Substring(7); + + var claimDic = _jwtTokenManager.VerifyToken(token, new JwtTokenManager.TokenVerifyErrorAction() + { + TokenExpiredAction = (ex) => { result = AuthenticateResult.Fail("Token过期"); }, + SignatureVerificationAction = (ex) => { result = AuthenticateResult.Fail("Token效验失效"); }, + TokenNotYetValidAction = (ex) => { result = AuthenticateResult.Fail("Token完全错误"); }, + ErrorAction = (ex) => { result = AuthenticateResult.Fail("Token内部错误"); } + }); + if (claimDic is not null) + { + //成功 + result = AuthenticateResult.Success(GetAuthTicket(claimDic)); + } + } + else + { + result = AuthenticateResult.Fail("授权令牌格式错误"); + } + + } + return Task.FromResult(result); + } + + /// + /// 未登录时的处理 + /// + /// + /// + /// + public Task ChallengeAsync(AuthenticationProperties? properties) + { + _context.Request.Headers.TryGetValue("Authorization", out StringValues values); + _context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + return Task.CompletedTask; + } + + /// + /// 权限不足的处理 + /// + /// + /// + /// + public Task ForbidAsync(AuthenticationProperties? properties) + { + _context.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return Task.CompletedTask; + } + + + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/DefaultPermissionHandler.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/DefaultPermissionHandler.cs new file mode 100644 index 00000000..4aad26a0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/DefaultPermissionHandler.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers; + +namespace Yi.Framework.Auth.JwtBearer.Authorization +{ + public class DefaultPermissionHandler : IPermissionHandler + { + private ICurrentUser _currentUser { get; set; } + + public DefaultPermissionHandler(ICurrentUser currentUser) + { + _currentUser = currentUser; + } + public bool IsPass(string permission) + { + if (_currentUser.Permission is not null) + { + return _currentUser.Permission.Contains(permission); + + } + + return false; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/IPermissionHandler.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/IPermissionHandler.cs new file mode 100644 index 00000000..4cc17784 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/IPermissionHandler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers; + +namespace Yi.Framework.Auth.JwtBearer.Authorization +{ + public interface IPermissionHandler + { + bool IsPass(string permission ); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionAttribute.cs new file mode 100644 index 00000000..475d3180 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionAttribute.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Exceptions; +using Yi.Framework.Core.Model; + +namespace Yi.Framework.Auth.JwtBearer.Authorization +{ + + [AttributeUsage(AttributeTargets.Method)] + + public class PermissionAttribute : ActionFilterAttribute + { + internal string Code { get; set; } + + public PermissionAttribute(string code) + { + this.Code = code; + } + + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionGlobalAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionGlobalAttribute.cs new file mode 100644 index 00000000..06e7d17d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Authorization/PermissionGlobalAttribute.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Yi.Framework.Auth.JwtBearer.Authorization; +using Yi.Framework.Core.Exceptions; + +namespace SF.AspNetCore.Auth.Authorization; +public class PermissionGlobalAttribute : ActionFilterAttribute +{ + private readonly IPermissionHandler _permissionHandler; + public PermissionGlobalAttribute(IPermissionHandler permissionHandler) + { + _permissionHandler=permissionHandler; + } + public override void OnActionExecuting(ActionExecutingContext context) + { + if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return; + PermissionAttribute? perAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) + .FirstOrDefault(a => a.GetType().Equals(typeof(PermissionAttribute))) as PermissionAttribute; + //空对象直接返回 + if (perAttribute is null) return; + + var result = _permissionHandler.IsPass(perAttribute.Code); + + if (!result) + { + throw new AuthException(message: $"您无权限访问该接口-{context.HttpContext.Request.Path.Value}"); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Yi.Framework.Auth.JwtBearer.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Yi.Framework.Auth.JwtBearer.csproj new file mode 100644 index 00000000..00bb5f5e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/Yi.Framework.Auth.JwtBearer.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/YiFrameworkAuthJwtBearerModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/YiFrameworkAuthJwtBearerModule.cs new file mode 100644 index 00000000..dbddcffe --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Auth.JwtBearer/YiFrameworkAuthJwtBearerModule.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using SF.AspNetCore.Auth.Authorization; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Auth.JwtBearer.Authentication; +using Yi.Framework.Auth.JwtBearer.Authentication.Options; +using Yi.Framework.Auth.JwtBearer.Authorization; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Configuration; + +namespace Yi.Framework.Auth.JwtBearer +{ + [DependsOn(typeof(YiFrameworkCoreModule))] + public class YiFrameworkAuthJwtBearerModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.Configure(Appsettings.appConfiguration("JwtTokenOptions")); + services.AddAuthentication(YiJwtAuthenticationHandler.YiJwtSchemeName); + services.AddTransient(); + services.AddSingleton(); + services.AddAuthentication(option => + { + option.AddScheme(YiJwtAuthenticationHandler.YiJwtSchemeName, YiJwtAuthenticationHandler.YiJwtSchemeName); + }); + services.AddSingleton(); + services.AddControllers(options => { + options.Filters.Add(); + }); + //services.AddSingleton(); + //services.AddControllers(options => { + // options.Filters.Add(); + //}); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/Yi.Framework.Core.Mapster.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/Yi.Framework.Core.Mapster.csproj new file mode 100644 index 00000000..6202c43e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/Yi.Framework.Core.Mapster.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/YiFrameworkCoreMapsterModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/YiFrameworkCoreMapsterModule.cs new file mode 100644 index 00000000..396d6b3d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.AutoMapper/YiFrameworkCoreMapsterModule.cs @@ -0,0 +1,26 @@ +using MapsterMapper; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core.Attributes; + +namespace Yi.Framework.Core.AutoMapper +{ + [DependsOn( + typeof(YiFrameworkCoreModule) + )] + public class YiFrameworkCoreMapsterModule : IStartupModule + { + + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + + //添加全局自动mapper + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacExtensions.cs new file mode 100644 index 00000000..1afba5bf --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacExtensions.cs @@ -0,0 +1,27 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Autofac.Extensions +{ + public static class AutoFacExtensions + { + public static IHostBuilder UseAutoFacServerProviderFactory(this IHostBuilder hostBuilder) + { + hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory()); + + return hostBuilder; + } + + public static IHostBuilder ConfigureAutoFacContainer(this IHostBuilder hostBuilder, Action configureDelegate) + { + hostBuilder.UseAutoFacServerProviderFactory(); + return hostBuilder.ConfigureContainer(configureDelegate); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacModuleExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacModuleExtensions.cs new file mode 100644 index 00000000..bd87fdca --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Extensions/AutoFacModuleExtensions.cs @@ -0,0 +1,35 @@ +using Autofac; +using Autofac.Core.Registration; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Autofac.Modules; + +namespace Yi.Framework.Core.Autofac.Extensions +{ + public static class AutoFacModuleExtensions + { + public static void RegisterYiModule(this ContainerBuilder builder, params Assembly[] assemblies) where TModule : YiAutoFacModule, new() + { + new TModule().Load(builder, assemblies); + } + + + public static void RegisterYiModule(this ContainerBuilder builder, AutoFacModuleEnum autoFacModuleEnum, params Assembly[] assemblies) + { + Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(AutoFacModuleExtensions).Assembly).GetCurrentClassLogger(); + switch (autoFacModuleEnum) + { + case AutoFacModuleEnum.PropertiesAutowiredModule: + _logger.Info($"意框架添加AutoFac模块:{nameof(PropertiesAutowiredModule)}-属性注入模块"); + new PropertiesAutowiredModule().Load(builder, assemblies); + break; + } + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/AutoFacModuleEnum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/AutoFacModuleEnum.cs new file mode 100644 index 00000000..8b25c34b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/AutoFacModuleEnum.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Autofac.Modules +{ + public enum AutoFacModuleEnum + { + PropertiesAutowiredModule + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/PropertiesAutowiredModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/PropertiesAutowiredModule.cs new file mode 100644 index 00000000..289dd8c2 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/PropertiesAutowiredModule.cs @@ -0,0 +1,32 @@ +using Autofac; +using Autofac.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; + + +namespace Yi.Framework.Core.Autofac.Modules +{ + internal class PropertiesAutowiredModule : YiAutoFacModule + { + internal override void Load(ContainerBuilder containerBuilder, params Assembly[] assemblies) + { + containerBuilder.RegisterAssemblyTypes(assemblies) + .PropertiesAutowired(new AutowiredPropertySelector()); + } + + } + + public class AutowiredPropertySelector : IPropertySelector + { + public bool InjectProperty(PropertyInfo propertyInfo, object instance) + { + return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(AutowiredAttribute)); + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/YiAutoFacModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/YiAutoFacModule.cs new file mode 100644 index 00000000..68d60f6c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Modules/YiAutoFacModule.cs @@ -0,0 +1,15 @@ +using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Autofac.Modules +{ + public abstract class YiAutoFacModule + { + internal abstract void Load(ContainerBuilder containerBuilder,params Assembly[] assemblies); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Properties/launchSettings.json b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Properties/launchSettings.json new file mode 100644 index 00000000..a8b2dde8 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Yi.Framework.Autofac": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53043;http://localhost:53044" + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Yi.Framework.Core.Autofac.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Yi.Framework.Core.Autofac.csproj new file mode 100644 index 00000000..d30b69ea --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/Yi.Framework.Core.Autofac.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/YiFrameworkCoreAutofacModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/YiFrameworkCoreAutofacModule.cs new file mode 100644 index 00000000..19467e7b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Autofac/YiFrameworkCoreAutofacModule.cs @@ -0,0 +1,27 @@ +using Autofac.Core; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Autofac +{ + public class YiFrameworkCoreAutofacModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //将控制器交由autofac注册 + services.Replace(ServiceDescriptor.Transient()); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Const/SqlsugarConst.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Const/SqlsugarConst.cs new file mode 100644 index 00000000..274024ae --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Const/SqlsugarConst.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Sqlsugar.Const +{ + public class SqlsugarConst + { + public const string 读写分离为空 = "开启读写分离后,读库连接不能为空"; + + public const string DbType配置为空 = "DbType配置为空,必须选择一个数据库类型"; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarCodeFirstExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarCodeFirstExtensions.cs new file mode 100644 index 00000000..c9bd3f08 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarCodeFirstExtensions.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Sqlsugar.Options; + +namespace Yi.Framework.Core.Sqlsugar.Extensions +{ + public static class SqlsugarCodeFirstExtensions + { + public static void UseSqlsugarCodeFirstServer(this IApplicationBuilder app) + { + var db = app.ApplicationServices.GetRequiredService(); + var options = app.ApplicationServices.GetRequiredService>(); + + if (options.Value.EnabledCodeFirst == false) return; + + db.DbMaintenance.CreateDatabase(); + var assemblys = new List(); + + //全盘加载 + if (options.Value.EntityAssembly is null) + { + assemblys.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList()); + } + //按需加载 + else + { + options.Value.EntityAssembly.ForEach(a => + { + assemblys.Add(Assembly.Load(a)); + }); + } + + foreach (var assembly in assemblys) + { + TableInvoer(db, assembly.GetTypes().ToList()); + } + + } + + private static void TableInvoer(ISqlSugarClient _Db, List typeList) + { + foreach (var t in typeList) + { + //扫描如果存在SugarTable特性 并且 不是分表模型,直接codefirst + if (t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SugarTable)) + && !t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SplitTableAttribute))))) + { + _Db.CodeFirst.SetStringDefaultLength(200).InitTables(t);//这样一个表就能成功创建了 + } + } + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarDataFiterExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarDataFiterExtensions.cs new file mode 100644 index 00000000..e6a96ce3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarDataFiterExtensions.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Sqlsugar.Extensions +{ + public static class SqlsugarDataFilterExtensions + { + public static IApplicationBuilder UseSqlsugarDataFiterServer(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } + + public class SqlsugarDataFilterMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + public SqlsugarDataFilterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) + { + this._next = next; + this._logger = loggerFactory.CreateLogger(); + } + public async Task InvokeAsync(HttpContext context) + { + + await _next(context); + + } + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarExtensions.cs new file mode 100644 index 00000000..165d8eea --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Extensions/SqlsugarExtensions.cs @@ -0,0 +1,159 @@ +using Autofac.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Configuration; +using Yi.Framework.Core.Model; +using Yi.Framework.Core.Sqlsugar.Const; +using Yi.Framework.Core.Sqlsugar.Options; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using DbType = SqlSugar.DbType; + +namespace Yi.Framework.Core.Sqlsugar.Extensions +{ + /// + /// 这一块,需要做成上下文对象,会进行重构 + /// + public static class SqlsugarExtensions + { + //使用上下文对象 + public static void AddDbSqlsugarContextServer(this IServiceCollection services) + { + services.AddSingleton(x => x.GetRequiredService().SqlSugarClient); + services.AddSingleton(); + } + + //直接使用sqlsugar + public static void AddSqlsugarServer(this IServiceCollection services, Action? action = null) + { + var dbConnOptions = Appsettings.app("DbConnOptions"); + + if (dbConnOptions.DbType is null) + { + throw new ArgumentException(SqlsugarConst.DbType配置为空); + } + var slavaConFig = new List(); + + + + if (dbConnOptions.EnabledReadWrite) + { + if (dbConnOptions.ReadUrl is null) + { + throw new ArgumentException(SqlsugarConst.读写分离为空); + } + + var readCon = dbConnOptions.ReadUrl; + + readCon.ForEach(s => + { + //如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接 + slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s }); + }); + } + + + + + SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig() + { + //准备添加分表分库 + DbType = dbConnOptions.DbType ?? DbType.Sqlite, + ConnectionString = dbConnOptions.Url, + IsAutoCloseConnection = true, + MoreSettings = new ConnMoreSettings() + { + DisableNvarchar = true + }, + SlaveConnectionConfigs = slavaConFig, + //设置codefirst非空值判断 + ConfigureExternalServices = new ConfigureExternalServices + { + EntityService = (c, p) => + { + //高版C#写法 支持string?和string + if (new NullabilityInfoContext() + .Create(c).WriteState is NullabilityState.Nullable) + { + p.IsNullable = true; + } + } + } + }, + db => + { + //扩展 + if (action is not null) + { + action(db); + } + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + + switch (entityInfo.OperationType) + { + case DataFilterType.UpdateByObject: + + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime))) + { + entityInfo.SetValue(DateTime.Now); + } + //if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId))) + //{ + // if (_currentUser != null) + // { + // entityInfo.SetValue(_currentUser.Id); + // } + //} + break; + case DataFilterType.InsertByObject: + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime))) + { + entityInfo.SetValue(DateTime.Now); + } + //if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId))) + //{ + // if (_currentUser != null) + // { + // entityInfo.SetValue(_currentUser.Id); + // } + //} + + //插入时,需要租户id,先预留 + if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId))) + { + //if (this.CurrentTenant is not null) + //{ + // entityInfo.SetValue(this.CurrentTenant.Id); + //} + } + break; + } + }; + db.Aop.OnLogExecuting = (s, p) => + { + var _logger = ServiceLocatorModel.Instance?.GetRequiredService>(); + + StringBuilder sb = new StringBuilder(); + sb.Append("执行SQL:" + s.ToString()); + foreach (var i in p) + { + sb.Append($"\r\n参数:{i.ParameterName},参数值:{i.Value}"); + } + sb.Append($"\r\n 完整SQL:{UtilMethods.GetSqlString(DbType.MySql, s, p)}"); + _logger?.LogDebug(sb.ToString()); + }; + + }); + services.AddSingleton(sqlSugar);//这边是SqlSugarScope用AddSingleton + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Filters/SqlsugarDataFilter.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Filters/SqlsugarDataFilter.cs new file mode 100644 index 00000000..f01082d4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Filters/SqlsugarDataFilter.cs @@ -0,0 +1,50 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Filters; + +namespace Yi.Framework.Core.Sqlsugar.Filters +{ + public class SqlsugarDataFilter : IDataFilter + { + private ISqlSugarClient _Db { get; set; } + public SqlsugarDataFilter(ISqlSugarClient sqlSugarClient) + { + _Db = sqlSugarClient; + } + public void AddFilter(Expression> expression) where TFilter : class + { + _Db.QueryFilter.AddTableFilter(expression); + } + + public IDisposable Disable() where TFilter : class + { + _Db.QueryFilter.ClearAndBackup(); + return this; + } + + public IDisposable Enable() where TFilter : class + { + throw new NotImplementedException("暂时没有单独还原过滤器的方式"); + } + + public bool IsEnabled() where TFilter : class + { + throw new NotImplementedException("暂时没有判断过滤器的方式"); + } + + public void RemoveFilter() where TFilter : class + { + _Db.QueryFilter.Clear(); + } + + public void Dispose() + { + _Db.QueryFilter.Restore(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Options/DbConnOptions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Options/DbConnOptions.cs new file mode 100644 index 00000000..22a6fcd3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Options/DbConnOptions.cs @@ -0,0 +1,47 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Sqlsugar.Options +{ + public class DbConnOptions + { + /// + /// 连接字符串,必填 + /// + public string? Url { get; set; } + + /// + /// 数据库类型 + /// + public DbType? DbType { get; set; } + + /// + /// 开启种子数据 + /// + public bool EnabledDbSeed { get; set; } = false; + + /// + /// 开启读写分离 + /// + public bool EnabledReadWrite { get; set; } = false; + + /// + /// 开启codefirst + /// + public bool EnabledCodeFirst { get; set; }=false; + + /// + /// 实体程序集 + /// + public List? EntityAssembly { get; set; } + + /// + /// 读写分离 + /// + public List? ReadUrl { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Repositories/SqlsugarRepository.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Repositories/SqlsugarRepository.cs new file mode 100644 index 00000000..ad59e324 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Repositories/SqlsugarRepository.cs @@ -0,0 +1,155 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Helper; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Entities; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.Framework.Core.Sqlsugar.Repositories +{ + [AppService(typeof(IRepository<>))] + public class SqlsugarRepository : SimpleClient, IRepository where T : class, new() + { + public SqlsugarRepository(ISqlSugarClient context) : base(context) + { + } + /// + /// 注释一下,严格意义这里应该protected,但是我认为 简易程度 与 耦合程度 中是需要进行衡量的 + /// + public ISugarQueryable _DbQueryable => base.AsQueryable(); + + protected ISqlSugarClient _Db { get { return Context; } set { } } + + public async Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page) + { + return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = page.PageNum, PageSize = page.PageSize }); + } + + public async Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page, Expression>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc) + { + return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = page.PageNum, PageSize = page.PageSize }, orderByExpression, orderByType.EnumToEnum()); + } + + public async Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc) + { + return await _DbQueryable.Where(whereExpression).OrderByIF(orderBy is not null, orderBy + " " + orderByType.ToString().ToLower()).ToPageListAsync(page.PageNum, page.PageSize); + } + + + + + public async Task> GetPageListAsync(Expression> whereExpression, int pageNum,int pageSize) + { + return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize }); + } + + public async Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, Expression>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc) + { + return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType.EnumToEnum()); + } + + public async Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc) + { + return await _DbQueryable.Where(whereExpression).OrderByIF(orderBy is not null, orderBy + " " + orderByType.ToString().ToLower()).ToPageListAsync(pageNum, pageSize); + } + + + + + + + + public async Task UpdateIgnoreNullAsync(T updateObj) + { + return await _Db.Updateable(updateObj).IgnoreColumns(true).ExecuteCommandAsync() > 0; + } + + public override async Task DeleteAsync(T deleteObj) + { + //逻辑删除 + if (deleteObj is ISoftDelete) + { + //反射赋值 + ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, deleteObj); + return await UpdateAsync(deleteObj); + + } + else + { + return await base.DeleteAsync(deleteObj); + + } + } + public override async Task DeleteAsync(List deleteObjs) + { + if (typeof(ISoftDelete).IsAssignableFrom(typeof(T))) + { + //反射赋值 + deleteObjs.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); + return await UpdateRangeAsync(deleteObjs); + } + else + { + return await base.DeleteAsync(deleteObjs); + } + } + public override async Task DeleteAsync(Expression> whereExpression) + { + if (typeof(ISoftDelete).IsAssignableFrom(typeof(T))) + { + var entities = await GetListAsync(whereExpression); + //反射赋值 + entities.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); + return await UpdateRangeAsync(entities); + } + else + { + return await base.DeleteAsync(whereExpression); + } + } + public override async Task DeleteByIdAsync(dynamic id) + { + if (typeof(ISoftDelete).IsAssignableFrom(typeof(T))) + { + var entity = await GetByIdAsync(id); + //反射赋值 + ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity); + return await UpdateAsync(entity); + } + else + { + return await _Db.Deleteable().In(id).ExecuteCommandAsync() > 0; + } + + } + public override async Task DeleteByIdsAsync(dynamic[] ids) + { + if (typeof(ISoftDelete).IsAssignableFrom(typeof(T))) + { + var entities = await _DbQueryable.In(ids).ToListAsync(); + if (entities.Count == 0) + { + return false; + } + //反射赋值 + entities.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); + return await UpdateRangeAsync(entities); + } + else + { + return await base.DeleteByIdsAsync(ids); + } + + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/SqlSugarDbContext.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/SqlSugarDbContext.cs new file mode 100644 index 00000000..6ff158ab --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/SqlSugarDbContext.cs @@ -0,0 +1,152 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Model; +using Yi.Framework.Core.Sqlsugar.Const; +using Yi.Framework.Core.Sqlsugar.Options; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; + +namespace Yi.Framework.Core.Sqlsugar +{ + public class SqlSugarDbContext + { + /// + /// SqlSugar 客户端 + /// + public ISqlSugarClient SqlSugarClient { get; set; } + + protected ICurrentUser _currentUser; + + protected ILogger _logger; + + protected IOptions _options; + + public SqlSugarDbContext(IOptions options, ICurrentUser currentUser, ILogger logger) + { + _currentUser = currentUser; + _logger = logger; + _options = options; + var dbConnOptions = options.Value; + #region 组装options + if (dbConnOptions.DbType is null) + { + throw new ArgumentException(SqlsugarConst.DbType配置为空); + } + var slavaConFig = new List(); + if (dbConnOptions.EnabledReadWrite) + { + if (dbConnOptions.ReadUrl is null) + { + throw new ArgumentException(SqlsugarConst.读写分离为空); + } + + var readCon = dbConnOptions.ReadUrl; + + readCon.ForEach(s => + { + //如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接 + slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s }); + }); + } + #endregion + SqlSugarClient = new SqlSugarScope(new ConnectionConfig() + { + //准备添加分表分库 + DbType = dbConnOptions.DbType ?? DbType.Sqlite, + ConnectionString = dbConnOptions.Url, + IsAutoCloseConnection = true, + MoreSettings = new ConnMoreSettings() + { + DisableNvarchar = true + }, + SlaveConnectionConfigs = slavaConFig, + //设置codefirst非空值判断 + ConfigureExternalServices = new ConfigureExternalServices + { + EntityService = (c, p) => + { + //高版C#写法 支持string?和string + if (new NullabilityInfoContext() + .Create(c).WriteState is NullabilityState.Nullable) + { + p.IsNullable = true; + } + } + } + }, + db => + { + + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + + switch (entityInfo.OperationType) + { + case DataFilterType.UpdateByObject: + + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime))) + { + entityInfo.SetValue(DateTime.Now); + } + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId))) + { + if (_currentUser != null) + { + entityInfo.SetValue(_currentUser.Id); + } + } + break; + case DataFilterType.InsertByObject: + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime))) + { + entityInfo.SetValue(DateTime.Now); + } + if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId))) + { + if (_currentUser != null) + { + entityInfo.SetValue(_currentUser.Id); + } + } + + //插入时,需要租户id,先预留 + if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId))) + { + //if (this.CurrentTenant is not null) + //{ + // entityInfo.SetValue(this.CurrentTenant.Id); + //} + } + break; + } + }; + db.Aop.OnLogExecuting = (s, p) => + { + StringBuilder sb = new StringBuilder(); + //sb.Append("执行SQL:" + s.ToString()); + //foreach (var i in p) + //{ + // sb.Append($"\r\n参数:{i.ParameterName},参数值:{i.Value}"); + //} + sb.Append($"\r\n 完整SQL:{UtilMethods.GetSqlString(DbType.MySql, s, p)}"); + logger?.LogDebug(sb.ToString()); + }; + //扩展 + this.OnSqlSugarClientConfig(db); + }); + } + + //上下文对象扩展 + protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient) + { + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWork.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWork.cs new file mode 100644 index 00000000..bda2bc4a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWork.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Model; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Uow; + +namespace Yi.Framework.Core.Sqlsugar.Uow +{ + public class SqlsugarUnitOfWork : IUnitOfWork + { + public ISqlSugarClient Db { get; set; } + public ITenant Tenant { get; set; } + public bool IsTran { get; set; } + public bool IsCommit { get; set; } + public bool IsClose { get; set; } + + public void Dispose() + { + + if (this.IsTran && IsCommit == false) + { + this.Tenant.RollbackTran(); + } + if (this.Db.Ado.Transaction == null && IsClose == false) + { + this.Db.Close(); + } + } + + public bool Commit() + { + if (this.IsTran && this.IsCommit == false) + { + this.Tenant.CommitTran(); + IsCommit = true; + } + if (this.Db.Ado.Transaction == null && this.IsClose == false) + { + this.Db.Close(); + IsClose = true; + } + return IsCommit; + } + + public IRepository GetRepository() + { + if (ServiceLocatorModel.Instance is null) + throw new ArgumentNullException("ServiceLocatorModel.Instance"); + //又是你这个骚东西 + return ServiceLocatorModel.Instance.GetRequiredService>(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWorkManager.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWorkManager.cs new file mode 100644 index 00000000..17e35ae2 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Uow/SqlsugarUnitOfWorkManager.cs @@ -0,0 +1,37 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Uow; + +namespace Yi.Framework.Core.Sqlsugar.Uow +{ + /// + /// 此部分为sqlsugr的魔改版本 + /// + internal class SqlsugarUnitOfWorkManager : IUnitOfWorkManager + { + public SqlsugarUnitOfWorkManager(ISqlSugarClient db) + { + this.Db = db; + } + public ISqlSugarClient Db { get; set; } + public IUnitOfWork CreateContext(bool isTran = true) + { + SqlsugarUnitOfWork uow = new SqlsugarUnitOfWork(); + return CreateContext(isTran, uow); + } + private IUnitOfWork CreateContext(bool isTran, SqlsugarUnitOfWork sugarUnitOf) + { + sugarUnitOf.Db = Db; + sugarUnitOf.Tenant = Db.AsTenant(); + sugarUnitOf.IsTran = isTran; + Db.Open(); + if (isTran) + Db.AsTenant().BeginTran(); + return sugarUnitOf; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Yi.Framework.Core.Sqlsugar.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Yi.Framework.Core.Sqlsugar.csproj new file mode 100644 index 00000000..d7032fa3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/Yi.Framework.Core.Sqlsugar.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/YiFrameworkCoreSqlsugarModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/YiFrameworkCoreSqlsugarModule.cs new file mode 100644 index 00000000..104082e7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core.Sqlsugar/YiFrameworkCoreSqlsugarModule.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using StartupModules; +using Yi.Framework.Core.Configuration; +using Yi.Framework.Core.Sqlsugar.Extensions; +using Yi.Framework.Core.Sqlsugar.Filters; +using Yi.Framework.Core.Sqlsugar.Options; +using Yi.Framework.Core.Sqlsugar.Repositories; +using Yi.Framework.Core.Sqlsugar.Uow; +using Yi.Framework.Data.Filters; +using Yi.Framework.Ddd; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Uow; + +namespace Yi.Framework.Core.Sqlsugar +{ + public class YiFrameworkCoreSqlsugarModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + app.UseSqlsugarCodeFirstServer(); + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddTransient(typeof(IRepository<>), typeof(SqlsugarRepository<>)); + //services.Replace(new ServiceDescriptor(typeof(IUnitOfWorkManager), typeof(SqlsugarUnitOfWorkManager), ServiceLifetime.Singleton)); + services.Replace(new ServiceDescriptor(typeof(IDataFilter), typeof(SqlsugarDataFilter), ServiceLifetime.Scoped)); + services.Configure(Appsettings.appConfiguration("DbConnOptions")); + + //使用db上下文 + services.AddDbSqlsugarContextServer(); + + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AppServiceAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AppServiceAttribute.cs new file mode 100644 index 00000000..59beb884 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AppServiceAttribute.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Attributes +{ + /// 1、[AppService]:自动去找接口,如果存在就是接口,如果不存在就是本身 + /// 2、[AppService(ServiceType = typeof(注册抽象或者接口或者本身))],手动去注册,放type即可 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public class AppServiceAttribute : Attribute + { + public AppServiceAttribute() { } + public AppServiceAttribute(Type? serviceType) + { + ServiceType=serviceType; + } + + public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime) + { + ServiceType = serviceType; + ServiceLifetime= serviceLifetime; + } + /// + /// 服务声明周期 + /// 不给默认值的话注册的是作用域 + /// + public LifeTime ServiceLifetime { get; set; } = LifeTime.Transient; + /// + /// 指定服务类型 + /// + public Type? ServiceType { get; set; } + + } + + public enum LifeTime + { + Transient, Scoped, Singleton + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AutowiredAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AutowiredAttribute.cs new file mode 100644 index 00000000..d9c752af --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/AutowiredAttribute.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public class AutowiredAttribute : Attribute + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/DependsOnAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/DependsOnAttribute.cs new file mode 100644 index 00000000..085dbcc9 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/DependsOnAttribute.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Attributes +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class DependsOnAttribute : Attribute + { + public Type[] DependedTypes { get; } + + public DependsOnAttribute(params Type[] dependedTypes) + { + DependedTypes = dependedTypes ?? new Type[0]; + } + + public virtual Type[] GetDependedTypes() + { + return DependedTypes; + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/QueryParameterAttribute.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/QueryParameterAttribute.cs new file mode 100644 index 00000000..20c1740e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Attributes/QueryParameterAttribute.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Attributes +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] + public class QueryParameterAttribute:Attribute + { + public QueryParameterAttribute() + { + } + public QueryParameterAttribute(QueryOperatorEnum queryOperatorEnum) + { + QueryOperator = queryOperatorEnum; + } + + public QueryOperatorEnum QueryOperator { get; set; } + + /// + /// 验证值为0时是否作为查询条件 + /// true-作为查询条件 false-不作为查询条件 + /// + public bool VerifyIsZero { get; set; } = false; + + /// + /// + /// + public string ColumnName { get; set; } + + public ColumnTypeEnum ColumnType { get; set; } + } + + public enum ColumnTypeEnum + { + datetime, + @bool + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Configuration/Appsettings.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Configuration/Appsettings.cs new file mode 100644 index 00000000..d121ee54 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Configuration/Appsettings.cs @@ -0,0 +1,91 @@ +using Microsoft.Extensions.Configuration.Json; +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Configuration +{ + public class Appsettings + { + static IConfiguration? Configuration { get; set; } + static string? contentPath { get; set; } + + public Appsettings(string contentPath) + { + string Path = "appsettings.json"; + + //如果你把配置文件 是 根据环境变量来分开了,可以这样写 + //Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json"; + + Configuration = new ConfigurationBuilder() + .SetBasePath(contentPath) + .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话,可以直接读目录里的json文件,而不是 bin 文件夹下的,所以不用修改复制属性 + .Build(); + } + + public Appsettings(IConfiguration configuration) + { + Configuration = configuration; + } + + /// + /// 封装要操作的字符 + /// + /// 节点配置 + /// + public static string? app(params string[] sections) + { + try + { + + if (sections.Any()) + { + return Configuration?[string.Join(":", sections)]; + } + } + catch (Exception) { } + + return ""; + } + + public static bool appBool(params string[] sections) + { + + return Bool(app(sections)); + + } + + public static bool Bool(object? thisValue) + { + bool reval = false; + if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return reval; + } + + /// + /// 递归获取配置信息数组 + /// + /// + /// + /// + public static T app(params string[] sections) + { + T app = Activator.CreateInstance(); + // 引用 Microsoft.Extensions.Configuration.Binder 包 + Configuration.Bind(string.Join(":", sections), app); + return app; + } + + + public static IConfiguration? appConfiguration(params string[] sections) + { + return Configuration?.GetSection(string.Join(":", sections)); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/PathConst.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/PathConst.cs new file mode 100644 index 00000000..ba393ce5 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/PathConst.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Const +{ + /// + /// 定义公共文件常量 + /// + public class PathConst + { + public const string wwwroot = "wwwroot"; + public const string DataTemplate = "_DataTemplate"; + public const string DataExport = "_DataExport"; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/TokenTypeConst.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/TokenTypeConst.cs new file mode 100644 index 00000000..850293ac --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Const/TokenTypeConst.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Const +{ + public class TokenTypeConst + { + public const string Id = nameof(Id); + + public const string UserName= nameof(UserName); + + public const string TenantId = nameof(TenantId); + + public const string Email = nameof(Email); + + public const string PhoneNumber = nameof(PhoneNumber); + + public const string Roles = nameof(Roles); + + public const string Permission = nameof(Permission); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs new file mode 100644 index 00000000..06dd9632 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs @@ -0,0 +1,32 @@ +using System.Security.Claims; +using Yi.Framework.Core.Utils; + +namespace Yi.Framework.Core.CurrentUsers.Accessor +{ + public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor + { + public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal(); + + private readonly AsyncLocal _currentPrincipal = new AsyncLocal(); + + protected abstract ClaimsPrincipal GetClaimsPrincipal(); + + public virtual IDisposable Change(ClaimsPrincipal principal) + { + return SetCurrent(principal); + } + + private IDisposable SetCurrent(ClaimsPrincipal principal) + { + var parent = Principal; + _currentPrincipal.Value = principal; + return new DisposeAction, ClaimsPrincipal>>(static (state) => + { + var (currentPrincipal, parent) = state; + currentPrincipal.Value = parent; + }, (_currentPrincipal, parent)); + + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..e17de77e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.CurrentUsers.Accessor; + +namespace Yi.Framework.Core.CurrentUsers.Accessor +{ + public class HttpContextCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor + { + private readonly IHttpContextAccessor _httpContextAccessor; + + public HttpContextCurrentPrincipalAccessor(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return _httpContextAccessor.HttpContext?.User ?? base.GetClaimsPrincipal(); + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs new file mode 100644 index 00000000..50dff9c4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs @@ -0,0 +1,11 @@ +using System.Security.Claims; + +namespace Yi.Framework.Core.CurrentUsers.Accessor +{ + public interface ICurrentPrincipalAccessor + { + ClaimsPrincipal Principal { get; } + IDisposable Change(ClaimsPrincipal principal); + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..83c24746 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs @@ -0,0 +1,15 @@ +using System.Security.Claims; + +using Yi.Framework.Core.CurrentUsers.Accessor; + +namespace SF.CurrentUser.CS.Accessor +{ + public class StaticPrincipalAccessor : CurrentPrincipalAccessorBase + { + public static ClaimsPrincipal ClaimsPrincipal { get; set; } + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return ClaimsPrincipal; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..f4138299 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs @@ -0,0 +1,13 @@ +using System.Security.Claims; + +namespace Yi.Framework.Core.CurrentUsers.Accessor +{ + public class ThreadCurrentPrincipalAccessor : CurrentPrincipalAccessorBase + { + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return Thread.CurrentPrincipal as ClaimsPrincipal; + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/CurrentUser.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/CurrentUser.cs new file mode 100644 index 00000000..051fcb3d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/CurrentUser.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Const; +using Yi.Framework.Core.CurrentUsers.Accessor; + +namespace Yi.Framework.Core.CurrentUsers +{ + public class CurrentUser : ICurrentUser + { + private readonly ICurrentPrincipalAccessor _principalAccessor; + public CurrentUser(ICurrentPrincipalAccessor principalAccessor) + { + _principalAccessor = principalAccessor; + } + public bool IsAuthenticated => Id != 0; + + public long Id => FindUserId(); + + public string UserName => this.FindClaimValue(TokenTypeConst.UserName); + + /// + /// 暂时为默认值 + /// + public Guid TenantId { get; set; } = Guid.Empty; + + public string Email => FindClaimValue(TokenTypeConst.Email); + + public bool EmailVerified=> false; + + public string PhoneNumber => FindClaimValue(TokenTypeConst.PhoneNumber); + + public bool PhoneNumberVerified => false; + + public string[]? Roles => this.FindClaims(TokenTypeConst.Roles).Select(c => c.Value).Distinct().ToArray(); + + public string[]? Permission => this.FindClaims(TokenTypeConst.Permission).Select(c => c.Value).Distinct().ToArray(); + + public virtual Claim FindClaim(string claimType) + { + return _principalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == claimType); + } + + public virtual Claim[] FindClaims(string claimType) + { + return _principalAccessor.Principal?.Claims.Where(c => c.Type == claimType).ToArray() ?? new Claim[0]; + } + + public virtual Claim[] GetAllClaims() + { + return _principalAccessor.Principal?.Claims.ToArray() ?? new Claim[0]; + } + + public string FindClaimValue(string claimType) + { + return FindClaim(claimType)?.Value; + } + + + public long FindUserId() + { + var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id); + if (userIdOrNull == null || string.IsNullOrWhiteSpace(userIdOrNull.Value)) + { + return 0; + } + + if (long.TryParse(userIdOrNull.Value, out long userId)) + { + return userId; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/ICurrentUser.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/ICurrentUser.cs new file mode 100644 index 00000000..8364db9c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/CurrentUsers/ICurrentUser.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.CurrentUsers +{ + public interface ICurrentUser + { + public bool IsAuthenticated { get; } + public long Id { get; } + + public string UserName { get; } + + public Guid TenantId { get; } + + public string Email { get; } + + public bool EmailVerified { get; } + + public string PhoneNumber { get; } + + public bool PhoneNumberVerified { get; } + + public string[]? Roles { get; } + + public string[]? Permission { get; } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/IScopedDependency.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/IScopedDependency.cs new file mode 100644 index 00000000..2b5f628c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/IScopedDependency.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.DependencyInjection +{ + internal interface IScopedDependency + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ISingletonDependency.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ISingletonDependency.cs new file mode 100644 index 00000000..d79d686d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ISingletonDependency.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.DependencyInjection +{ + public interface ISingletonDependency + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ITransientDependency.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ITransientDependency.cs new file mode 100644 index 00000000..b075939d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/DependencyInjection/ITransientDependency.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.DependencyInjection +{ + public interface ITransientDependency + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs new file mode 100644 index 00000000..1776d35f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Enums +{ + /// + /// 定义公共文件路径 + /// + public enum FileTypeEnum + { + File, + Image, + Thumbnail, + Excel, + Temp + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/OrderByEnum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/OrderByEnum.cs new file mode 100644 index 00000000..b1edac3a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/OrderByEnum.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Enums +{ + public enum OrderByEnum + { + Asc, + Desc + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs new file mode 100644 index 00000000..13439675 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Enums +{ + public enum QueryOperatorEnum + { + /// + /// 相等 + /// + Equal, + /// + /// 匹配 + /// + Like, + /// + /// 大于 + /// + GreaterThan, + /// + /// 大于或等于 + /// + GreaterThanOrEqual, + /// + /// 小于 + /// + LessThan, + /// + /// 小于或等于 + /// + LessThanOrEqual, + /// + /// 等于集合 + /// + In, + /// + /// 不等于集合 + /// + NotIn, + /// + /// 左边匹配 + /// + LikeLeft, + /// + /// 右边匹配 + /// + LikeRight, + /// + /// 不相等 + /// + NoEqual, + /// + /// 为空或空 + /// + IsNullOrEmpty, + /// + /// 不为空 + /// + IsNot, + /// + /// 不匹配 + /// + NoLike, + /// + /// 时间段 值用 "|" 隔开 + /// + DateRange + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs new file mode 100644 index 00000000..e4197867 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Enums +{ + public enum ResultCodeEnum + { + /// + /// 操作成功。 + /// + Success = 200, + + /// + /// 操作不成功 + /// + NotSuccess = 500, + + /// + /// 无权限 + /// + NoPermission = 401, + + /// + /// 被拒绝 + /// + Denied = 403 + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/AuthException.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/AuthException.cs new file mode 100644 index 00000000..154ea3c6 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/AuthException.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Exceptions +{ + public class AuthException : Exception, + IHasErrorCode, + IHasErrorDetails, + IHasLogLevel + { + public int Code { get; set; } + + public string? Details { get; set; } + + public LogLevel LogLevel { get; set; } + + public AuthException( + + string? message = null, + ResultCodeEnum code = ResultCodeEnum.NoPermission, + string? details = null, + Exception? innerException = null, + LogLevel logLevel = LogLevel.Warning) + : base(message, innerException) + { + Code =(int) code; + Details = details; + LogLevel = logLevel; + } + + /// + /// 序列化参数的构造函数 + /// + public AuthException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + public AuthException WithData(string name, object value) + { + Data[name] = value; + return this; + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/BusinessException.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/BusinessException.cs new file mode 100644 index 00000000..64a8d54f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/BusinessException.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Exceptions +{ + public class BusinessException : Exception, + IHasErrorCode, + IHasErrorDetails, + IHasLogLevel + { + public int Code { get; set; } + + public string? Details { get; set; } + + public LogLevel LogLevel { get; set; } + + public BusinessException( + int code = (int)ResultCodeEnum.Denied, + string? message = null, + string? details = null, + Exception? innerException = null, + LogLevel logLevel = LogLevel.Warning) + : base(message, innerException) + { + Code = code; + Details = details; + LogLevel = logLevel; + } + + /// + /// 序列化参数的构造函数 + /// + public BusinessException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + public BusinessException WithData(string name, object value) + { + Data[name] = value; + return this; + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/ExceptionExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/ExceptionExtensions.cs new file mode 100644 index 00000000..1a9e5b59 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/ExceptionExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Runtime.ExceptionServices; +using Microsoft.Extensions.Logging; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Exceptions; + +/// +/// չ +/// +public static class ExceptionExtensions +{ + /// + /// ʹ ٴ׳쳣 + /// + /// Exception to be re-thrown + public static void ReThrow(this Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + + /// + /// ȡ쳣е־ȼ + /// + /// + /// + /// + public static LogLevel GetLogLevel(this Exception exception, LogLevel defaultLevel = LogLevel.Error) + { + return (exception as IHasLogLevel)?.LogLevel ?? defaultLevel; + } + /// + /// ȡ쳣е־ + /// + /// + /// + /// + public static int GetLogErrorCode(this Exception exception, ResultCodeEnum defaultCode = ResultCodeEnum.NotSuccess) + { + return (exception as IHasErrorCode)?.Code ?? (int)defaultCode; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorCode.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorCode.cs new file mode 100644 index 00000000..d57e891b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorCode.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Exceptions +{ + internal interface IHasErrorCode + { + int Code { get; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorDetails.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorDetails.cs new file mode 100644 index 00000000..2ea6e71f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasErrorDetails.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Exceptions +{ + public interface IHasErrorDetails + { + string? Details { get; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasLogLevel.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasLogLevel.cs new file mode 100644 index 00000000..038eaa32 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/IHasLogLevel.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Exceptions +{ + public interface IHasLogLevel + { + LogLevel LogLevel { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/UserFriendlyException.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/UserFriendlyException.cs new file mode 100644 index 00000000..97a71782 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Exceptions/UserFriendlyException.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Exceptions +{ + public class UserFriendlyException : BusinessException + { + public UserFriendlyException( +string message, +int code = (int)ResultCodeEnum.Denied, +string? details = null, +Exception? innerException = null, +LogLevel logLevel = LogLevel.Warning) +: base( + code, + message, + details, + innerException, + logLevel) + { + Details = details; + } + + /// + /// 序列化参数的构造函数 + /// + public UserFriendlyException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/AutoIocAddExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/AutoIocAddExtensions.cs new file mode 100644 index 00000000..e66b870f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/AutoIocAddExtensions.cs @@ -0,0 +1,132 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.DependencyInjection; + +namespace Yi.Framework.Core.Extensions +{ + public static class AutoIocAddExtensions + { + public static IServiceCollection AddAutoIocServer(this IServiceCollection services, params string[] assemblyStr) + { + foreach (var a in assemblyStr) + { + RegIoc(services, Assembly.Load(a)); + } + return services; + } + + /// + /// 扫描全部 + /// + /// + /// + public static IServiceCollection AddAutoIocServer(this IServiceCollection services) + { + var assemblys = Yi.Framework.Core.Module.ModuleAssembly.Assemblies; + foreach (var a in assemblys) + { + RegIoc(services, a); + } + return services; + } + private static void RegIoc(IServiceCollection services, Assembly assembly) + { + foreach (var type in assembly.GetTypes()) + { + RegIocByAttribute(services, type); + RegIocByInterface(services, type); + } + } + + private static void RegIocByAttribute(IServiceCollection services, Type type) + { + var serviceAttributes = type.GetCustomAttributes(); + if (serviceAttributes is null) + { + return; + } + //处理多个特性注入情况 + foreach (var serviceAttribute in serviceAttributes) + { + + if (serviceAttribute is not null) + { + //泛型类需要单独进行处理 + //情况1:使用自定义[AppService(ServiceType = typeof(注册抽象或者接口))],手动去注册,放type即可 + var serviceType = serviceAttribute.ServiceType; + //if (serviceType is not null && serviceType.Name.Contains("IDataSeed`")) + //{ + // Console.WriteLine(); + //} + + //情况2 自动去找接口,如果存在就是接口,如果不存在就是本身 + if (serviceType == null) + { + //获取最远靠近的接口 + var p = type.GetInterfaces().ToList(); + var firstInter = type.GetInterfaces().Where(u => u.Name == $"I{type.Name}").LastOrDefault(); + if (firstInter is null) + { + serviceType = type; + } + else + { + serviceType = firstInter; + } + } + + switch (serviceAttribute.ServiceLifetime) + { + case LifeTime.Singleton: + services.AddSingleton(serviceType, type); + break; + case LifeTime.Scoped: + services.AddScoped(serviceType, type); + break; + case LifeTime.Transient: + services.AddTransient(serviceType, type); + break; + } + + } + + } + + } + + private static void RegIocByInterface(IServiceCollection services, Type type) + { + var serviceInterfaces = type.GetInterfaces(); + if (serviceInterfaces is not null) + { + var serviceType = type; + + //规范 + var firstInter = type.GetInterfaces().Where(u => u != typeof(ITransientDependency) && u.Name == $"I{type.Name}").LastOrDefault(); + + if (firstInter is not null) + { + serviceType = firstInter; + } + if (serviceInterfaces.Contains(typeof(ITransientDependency))) + { + services.AddTransient(serviceType, type); + } + if (serviceInterfaces.Contains(typeof(IScopedDependency))) + { + services.AddScoped(serviceType, type); + } + if (serviceInterfaces.Contains(typeof(ISingletonDependency))) + { + services.AddSingleton(serviceType, type); + } + } + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/ModuleExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/ModuleExtensions.cs new file mode 100644 index 00000000..8dc1db62 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Extensions/ModuleExtensions.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using StartupModules.Internal; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Module; + +namespace Yi.Framework.Core.Extensions +{ + + /// + /// 该类来自于StartupModules + /// + public static class ModuleExtensions + { + public static WebApplicationBuilder UseYiModules(this WebApplicationBuilder builder, Type startType) + { + var moduleManager = new ModuleManager(startType); + + + Assembly[] assemblies2 = moduleManager.ToAssemblyArray(moduleManager.Invoker()); + return builder.UseStartupModules(delegate (StartupModulesOptions options) + { + options.DiscoverStartupModules(assemblies2); + }); + } + } +} + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/AssemblyHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/AssemblyHelper.cs new file mode 100644 index 00000000..7f646689 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/AssemblyHelper.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class AssemblyHelper + { + + /// + /// 此处统一获取程序集,排除微软内部相关 + /// + /// + public static Assembly[] GetAllLoadAssembly() + { + return AppDomain.CurrentDomain.GetAssemblies(); + } + + public static List GetReferanceAssemblies(this AppDomain domain) + { + var list = new List(); + domain.GetAssemblies().ToList().ForEach(i => + { + GetReferanceAssemblies(i, list); + }); + return list; + } + private static void GetReferanceAssemblies(Assembly assembly, List list) + { + assembly.GetReferencedAssemblies().ToList().ForEach(i => + { + var ass = Assembly.Load(i); + if (!list.Contains(ass)) + { + list.Add(ass); + GetReferanceAssemblies(ass, list); + } + }); + } + + public static List GetClass(string assemblyFile, string? className = null, string? spaceName = null) + { + Assembly assembly = Assembly.Load(assemblyFile); + return assembly.GetTypes().Where(m => m.IsClass + && className == null ? true : m.Name == className + && spaceName == null ? true : m.Namespace == spaceName + && !m.Name.StartsWith("<>") + ).ToList(); + } + + public static List GetClassByParentClass(string assemblyFile, Type type) + { + Assembly assembly = Assembly.Load(assemblyFile); + + List resList = new List(); + + List typeList = assembly.GetTypes().Where(m => m.IsClass).ToList(); + foreach (var t in typeList) + { + var data = t.BaseType; + if (data == type) + { + resList.Add(t); + } + + } + return resList; + } + + + public static List GetClassByInterfaces(string assemblyFile, Type type) + { + Assembly assembly = Assembly.Load(assemblyFile); + + List resList = new List(); + + List typeList = assembly.GetTypes().Where(m => m.IsClass).ToList(); + foreach (var t in typeList) + { + var data = t.GetInterfaces(); + if (data.Contains(type)) + { + resList.Add(t); + } + + } + return resList; + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/Base32Helper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/Base32Helper.cs new file mode 100644 index 00000000..2f89bc1c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/Base32Helper.cs @@ -0,0 +1,101 @@ +using System; +using System.Text; + +namespace Yi.Framework.Core.Helper +{ + public sealed class Base32Helper + { + + // the valid chars for the encoding + private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP"; + + /// + /// Converts an array of bytes to a Base32-k string. + /// + public static string ToString(byte[] bytes) + { + StringBuilder sb = new StringBuilder(); // holds the base32 chars + byte index; + int hi = 5; + int currentByte = 0; + + while (currentByte < bytes.Length) + { + // do we need to use the next byte? + if (hi > 8) + { + // get the last piece from the current byte, shift it to the right + // and increment the byte counter + index = (byte)(bytes[currentByte++] >> (hi - 5)); + if (currentByte != bytes.Length) + { + // if we are not at the end, get the first piece from + // the next byte, clear it and shift it to the left + index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index); + } + + hi -= 3; + } + else if (hi == 8) + { + index = (byte)(bytes[currentByte++] >> 3); + hi -= 3; + } + else + { + + // simply get the stuff from the current byte + index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3); + hi += 5; + } + + sb.Append(ValidChars[index]); + } + + return sb.ToString(); + } + + + /// + /// Converts a Base32-k string into an array of bytes. + /// + /// + /// Input string s contains invalid Base32-k characters. + /// + public static byte[] FromBase32String(string str) + { + int numBytes = str.Length * 5 / 8; + byte[] bytes = new Byte[numBytes]; + + // all UPPERCASE chars + str = str.ToUpper(); + + int bit_buffer; + int currentCharIndex; + int bits_in_buffer; + + if (str.Length < 3) + { + bytes[0] = (byte)(ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); + return bytes; + } + + bit_buffer = (ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); + bits_in_buffer = 10; + currentCharIndex = 2; + for (int i = 0; i < bytes.Length; i++) + { + bytes[i] = (byte)bit_buffer; + bit_buffer >>= 8; + bits_in_buffer -= 8; + while (bits_in_buffer < 8 && currentCharIndex < str.Length) + { + bit_buffer |= ValidChars.IndexOf(str[currentCharIndex++]) << bits_in_buffer; + bits_in_buffer += 5; + } + } + + return bytes; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ConsoleHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ConsoleHelper.cs new file mode 100644 index 00000000..dfd6a8ab --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ConsoleHelper.cs @@ -0,0 +1,54 @@ +using System; + +namespace Yi.Framework.Core.Helper +{ + public static class ConsoleHelper + { + public static void WriteColorLine(string str, ConsoleColor color) + { + ConsoleColor currentForeColor = Console.ForegroundColor; + Console.ForegroundColor = color; + Console.WriteLine(str); + Console.ForegroundColor = currentForeColor; + } + + /// + /// 打印错误信息 + /// + /// 待打印的字符串 + /// 想要打印的颜色 + public static void WriteErrorLine(this string str, ConsoleColor color = ConsoleColor.Red) + { + WriteColorLine(str, color); + } + + /// + /// 打印警告信息 + /// + /// 待打印的字符串 + /// 想要打印的颜色 + public static void WriteWarningLine(this string str, ConsoleColor color = ConsoleColor.Yellow) + { + WriteColorLine(str, color); + } + /// + /// 打印正常信息 + /// + /// 待打印的字符串 + /// 想要打印的颜色 + public static void WriteInfoLine(this string str, ConsoleColor color = ConsoleColor.White) + { + WriteColorLine(str, color); + } + /// + /// 打印成功的信息 + /// + /// 待打印的字符串 + /// 想要打印的颜色 + public static void WriteSuccessLine(this string str, ConsoleColor color = ConsoleColor.Green) + { + WriteColorLine(str, color); + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DateHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DateHelper.cs new file mode 100644 index 00000000..0ac37315 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DateHelper.cs @@ -0,0 +1,58 @@ +using System; + +namespace Yi.Framework.Core.Helper +{ + public class DateHelper + { + public static DateTime StampToDateTime(string time) + { + time = time.Substring(0, 10); + double timestamp = Convert.ToInt64(time); + System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); + dateTime = dateTime.AddSeconds(timestamp).ToLocalTime(); + return dateTime; + } + + public static string TimeSubTract(DateTime time1,DateTime time2) + { + TimeSpan subTract = time1.Subtract(time2); + return $"{subTract.Days} 天 {subTract.Hours} 时 {subTract.Minutes} 分 "; + } + /// + /// 时间戳转本地时间-时间戳精确到秒 + /// + public static DateTime ToLocalTimeDateBySeconds(long unix) + { + var dto = DateTimeOffset.FromUnixTimeSeconds(unix); + return dto.ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到秒 + /// + public static long ToUnixTimestampBySeconds(DateTime dt) + { + DateTimeOffset dto = new DateTimeOffset(dt); + return dto.ToUnixTimeSeconds(); + } + + + /// + /// 时间戳转本地时间-时间戳精确到毫秒 + /// + public static DateTime ToLocalTimeDateByMilliseconds(long unix) + { + var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix); + return dto.ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到毫秒 + /// + public static long ToUnixTimestampByMilliseconds(DateTime dt) + { + DateTimeOffset dto = new DateTimeOffset(dt); + return dto.ToUnixTimeMilliseconds(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DistinctHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DistinctHelper.cs new file mode 100644 index 00000000..18df6efb --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/DistinctHelper.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public class Compare : IEqualityComparer + { + private Func _getField; + public Compare(Func getfield) + { + this._getField = getfield; + } + public bool Equals(T? x, T? y) + { + return EqualityComparer.Default.Equals(_getField(x!), _getField(y!)); + } + + public int GetHashCode(T obj) + { + return EqualityComparer.Default.GetHashCode(this._getField(obj)!); + } + } + public static class DistinctHelper + { + /// + /// 自定义Distinct扩展方法 + /// + /// 要去重的对象类 + /// 自定义去重的字段类型 + /// 要去重的对象 + /// 获取自定义去重字段的委托 + /// + public static IEnumerable DistinctNew(this IEnumerable source, Func getfield) + { + return source.Distinct(new Compare(getfield)); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/EnumHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/EnumHelper.cs new file mode 100644 index 00000000..eaef0d79 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/EnumHelper.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class EnumHelper + { + public static New EnumToEnum(this object oldEnum) + { + if (oldEnum is null) + { + throw new ArgumentNullException(nameof(oldEnum)); + } + return (New)Enum.ToObject(typeof(New), oldEnum.GetHashCode()); + } + + public static TEnum StringToEnum(this string str) + { + return (TEnum)Enum.Parse(typeof(TEnum), str); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ExpressionHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ExpressionHelper.cs new file mode 100644 index 00000000..bac80dc0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ExpressionHelper.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class ExpressionHelper + { + + + /// + /// Expression表达式树lambda参数拼接组合 + /// + /// + /// + /// + /// + /// + public static Expression Compose(this Expression first, Expression second, Func merge) + { + var parameterMap = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); + var secondBody = LambdaParameteRebinder.ReplaceParameter(parameterMap, second.Body); + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + /// + /// Expression表达式树lambda参数拼接--false + /// + /// + /// + public static Expression> False() => f => false; + + /// + /// Expression表达式树lambda参数拼接-true + /// + /// + /// + public static Expression> True() => f => true; + + /// + /// Expression表达式树lambda参数拼接--and + /// + /// + /// + /// + /// + public static Expression> And(this Expression> first, Expression> second) => first.Compose(second, Expression.And); + + /// + /// Expression表达式树lambda参数拼接--or + /// + /// + /// + /// + /// + public static Expression> Or(this Expression> first, Expression> second) => first.Compose(second, Expression.Or); + } + + public class LambdaParameteRebinder : ExpressionVisitor + { + /// + /// 存放表达式树的参数的字典 + /// + private readonly Dictionary map; + + /// + /// 构造函数 + /// + /// + public LambdaParameteRebinder(Dictionary map) + { + this.map = map ?? new Dictionary(); + } + + /// + /// 重载参数访问的方法,访问表达式树参数,如果字典中包含,则取出 + /// + /// 表达式树参数 + /// + protected override Expression VisitParameter(ParameterExpression node) + { + if (map.TryGetValue(node, out ParameterExpression expression)) + { + node = expression; + } + return base.VisitParameter(node); + } + + public static Expression ReplaceParameter(Dictionary map, Expression exp) + { + return new LambdaParameteRebinder(map).Visit(exp); + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/FileHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/FileHelper.cs new file mode 100644 index 00000000..906b7253 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/FileHelper.cs @@ -0,0 +1,490 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Yi.Framework.Core.Helper +{ + public class FileHelper : IDisposable + { + + private bool _alreadyDispose = false; + + + + #region 构造函数 + public FileHelper() + { + // + // TODO: 在此处添加构造函数逻辑 + // + } + ~FileHelper() + { + Dispose(); ; + } + + protected virtual void Dispose(bool isDisposing) + { + if (_alreadyDispose) return; + _alreadyDispose = true; + } + #endregion + + #region IDisposable 成员 + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + + #region 取得文件后缀名 + /**************************************** + * 函数名称:GetPostfixStr + * 功能说明:取得文件后缀名 + * 参 数:filename:文件名称 + * 调用示列: + * string filename = "aaa.aspx"; + * string s = EC.FileObj.GetPostfixStr(filename); + *****************************************/ + /// + /// 取后缀名 + /// + /// 文件名 + /// .gif|.html格式 + public static string GetPostfixStr(string filename) + { + int start = filename.LastIndexOf("."); + int length = filename.Length; + string postfix = filename.Substring(start, length - start); + return postfix; + } + #endregion + + #region 根据文件大小获取指定前缀的可用文件名 + /// + /// 根据文件大小获取指定前缀的可用文件名 + /// + /// 文件夹 + /// 文件前缀 + /// 文件大小(1m) + /// 文件后缀(.log) + /// 可用文件名 + //public static string GetAvailableFileWithPrefixOrderSize(string folderPath, string prefix, int size = 1 * 1024 * 1024, string ext = ".log") + //{ + // var allFiles = new DirectoryInfo(folderPath); + // var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d=>d.Name).ToList(); + + // if (selectFiles.Count > 0) + // { + // return selectFiles.FirstOrDefault().FullName; + // } + + // return Path.Combine(folderPath, $@"{prefix}_{DateTime.Now.DateToTimeStamp()}.log"); + //} + //public static string GetAvailableFileNameWithPrefixOrderSize(string _contentRoot, string prefix, int size = 1 * 1024 * 1024, string ext = ".log") + //{ + // var folderPath = Path.Combine(_contentRoot, "Log"); + // if (!Directory.Exists(folderPath)) + // { + // Directory.CreateDirectory(folderPath); + // } + + // var allFiles = new DirectoryInfo(folderPath); + // var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList(); + + // if (selectFiles.Count > 0) + // { + // return selectFiles.FirstOrDefault().Name.Replace(".log",""); + // } + + // return $@"{prefix}_{DateTime.Now.DateToTimeStamp()}"; + //} + #endregion + + #region 写文件 + /**************************************** + * 函数名称:WriteFile + * 功能说明:写文件,会覆盖掉以前的内容 + * 参 数:Path:文件路径,Strings:文本内容 + * 调用示列: + * string Path = Server.MapPath("Default2.aspx"); + * string Strings = "这是我写的内容啊"; + * EC.FileObj.WriteFile(Path,Strings); + *****************************************/ + /// + /// 写文件 + /// + /// 文件路径 + /// 文件内容 + public static void WriteFile(string Path, string Strings) + { + if (!File.Exists(Path)) + { + FileStream f = File.Create(Path); + f.Close(); + } + StreamWriter f2 = new StreamWriter(Path, false, Encoding.GetEncoding("gb2312")); + f2.Write(Strings); + f2.Close(); + f2.Dispose(); + } + + /// + /// 写文件 + /// + /// 文件路径 + /// 文件内容 + /// 编码格式 + public static void WriteFile(string Path, string Strings, Encoding encode) + { + if (!File.Exists(Path)) + { + FileStream f = File.Create(Path); + f.Close(); + } + StreamWriter f2 = new StreamWriter(Path, false, encode); + f2.Write(Strings); + f2.Close(); + f2.Dispose(); + } + #endregion + + #region 读文件 + /**************************************** + * 函数名称:ReadFile + * 功能说明:读取文本内容 + * 参 数:Path:文件路径 + * 调用示列: + * string Path = Server.MapPath("Default2.aspx"); + * string s = EC.FileObj.ReadFile(Path); + *****************************************/ + /// + /// 读文件 + /// + /// 文件路径 + /// + public static string ReadFile(string Path) + { + string s = ""; + if (!File.Exists(Path)) + s = "不存在相应的目录"; + else + { + StreamReader f2 = new StreamReader(Path, Encoding.GetEncoding("gb2312")); + s = f2.ReadToEnd(); + f2.Close(); + f2.Dispose(); + } + + return s; + } + + /// + /// 读文件 + /// + /// 文件路径 + /// 编码格式 + /// + public static string ReadFile(string Path, Encoding encode) + { + string s = ""; + if (!File.Exists(Path)) + s = "不存在相应的目录"; + else + { + StreamReader f2 = new StreamReader(Path, encode); + s = f2.ReadToEnd(); + f2.Close(); + f2.Dispose(); + } + + return s; + } + #endregion + + #region 追加文件 + /**************************************** + * 函数名称:FileAdd + * 功能说明:追加文件内容 + * 参 数:Path:文件路径,strings:内容 + * 调用示列: + * string Path = Server.MapPath("Default2.aspx"); + * string Strings = "新追加内容"; + * EC.FileObj.FileAdd(Path, Strings); + *****************************************/ + /// + /// 追加文件 + /// + /// 文件路径 + /// 内容 + public static void FileAdd(string Path, string strings) + { + StreamWriter sw = File.AppendText(Path); + sw.Write(strings); + sw.Flush(); + sw.Close(); + } + #endregion + + #region 拷贝文件 + /**************************************** + * 函数名称:FileCoppy + * 功能说明:拷贝文件 + * 参 数:OrignFile:原始文件,NewFile:新文件路径 + * 调用示列: + * string orignFile = Server.MapPath("Default2.aspx"); + * string NewFile = Server.MapPath("Default3.aspx"); + * EC.FileObj.FileCoppy(OrignFile, NewFile); + *****************************************/ + /// + /// 拷贝文件 + /// + /// 原始文件 + /// 新文件路径 + public static void FileCoppy(string orignFile, string NewFile) + { + File.Copy(orignFile, NewFile, true); + } + + #endregion + + #region 删除文件 + /**************************************** + * 函数名称:FileDel + * 功能说明:删除文件 + * 参 数:Path:文件路径 + * 调用示列: + * string Path = Server.MapPath("Default3.aspx"); + * EC.FileObj.FileDel(Path); + *****************************************/ + /// + /// 删除文件 + /// + /// 路径 + public static void FileDel(string Path) + { + File.Delete(Path); + } + #endregion + + #region 移动文件 + /**************************************** + * 函数名称:FileMove + * 功能说明:移动文件 + * 参 数:OrignFile:原始路径,NewFile:新文件路径 + * 调用示列: + * string orignFile = Server.MapPath("../说明.txt"); + * string NewFile = Server.MapPath("http://www.cnblogs.com/说明.txt"); + * EC.FileObj.FileMove(OrignFile, NewFile); + *****************************************/ + /// + /// 移动文件 + /// + /// 原始路径 + /// 新路径 + public static void FileMove(string orignFile, string NewFile) + { + File.Move(orignFile, NewFile); + } + #endregion + + #region 在当前目录下创建目录 + /**************************************** + * 函数名称:FolderCreate + * 功能说明:在当前目录下创建目录 + * 参 数:OrignFolder:当前目录,NewFloder:新目录 + * 调用示列: + * string orignFolder = Server.MapPath("test/"); + * string NewFloder = "new"; + * EC.FileObj.FolderCreate(OrignFolder, NewFloder); + *****************************************/ + /// + /// 在当前目录下创建目录 + /// + /// 当前目录 + /// 新目录 + public static void FolderCreate(string orignFolder, string NewFloder) + { + Directory.SetCurrentDirectory(orignFolder); + Directory.CreateDirectory(NewFloder); + } + #endregion + + #region 递归删除文件夹目录及文件 + /**************************************** + * 函数名称:DeleteFolder + * 功能说明:递归删除文件夹目录及文件 + * 参 数:dir:文件夹路径 + * 调用示列: + * string dir = Server.MapPath("test/"); + * EC.FileObj.DeleteFolder(dir); + *****************************************/ + /// + /// 递归删除文件夹目录及文件 + /// + /// + /// + public static void DeleteFolder(string dir) + { + if (Directory.Exists(dir)) //如果存在这个文件夹删除之 + { + foreach (string d in Directory.GetFileSystemEntries(dir)) + { + if (File.Exists(d)) + File.Delete(d); //直接删除其中的文件 + else + DeleteFolder(d); //递归删除子文件夹 + } + Directory.Delete(dir); //删除已空文件夹 + } + + } + #endregion + + #region 将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。 + /**************************************** + * 函数名称:CopyDir + * 功能说明:将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。 + * 参 数:srcPath:原始路径,aimPath:目标文件夹 + * 调用示列: + * string srcPath = Server.MapPath("test/"); + * string aimPath = Server.MapPath("test1/"); + * EC.FileObj.CopyDir(srcPath,aimPath); + *****************************************/ + /// + /// 指定文件夹下面的所有内容copy到目标文件夹下面 + /// + /// 原始路径 + /// 目标文件夹 + public static void CopyDir(string srcPath, string aimPath) + { + try + { + // 检查目标目录是否以目录分割字符结束如果不是则添加之 + if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar) + aimPath += Path.DirectorySeparatorChar; + // 判断目标目录是否存在如果不存在则新建之 + if (!Directory.Exists(aimPath)) + Directory.CreateDirectory(aimPath); + // 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组 + //如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法 + //string[] fileList = Directory.GetFiles(srcPath); + string[] fileList = Directory.GetFileSystemEntries(srcPath); + //遍历所有的文件和目录 + foreach (string file in fileList) + { + //先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 + + if (Directory.Exists(file)) + CopyDir(file, aimPath + Path.GetFileName(file)); + //否则直接Copy文件 + else + File.Copy(file, aimPath + Path.GetFileName(file), true); + } + + } + catch (Exception ee) + { + throw new Exception(ee.ToString()); + } + } + #endregion + + /// + /// 获取目录下全部文件名 + /// + /// + /// + /// + public static List GetAllFileNames(string path, string pattern = "*") + { + List folder = new DirectoryInfo(path).GetFiles(pattern).ToList(); + + return folder.Select(x => x.Name).ToList(); + } + /// + /// 文件内容替换 + /// + public static string FileContentReplace(string path, string oldStr, string newStr) + { + var content = File.ReadAllText(path); + + if (content.Contains(oldStr)) + { + File.Delete(path); + File.WriteAllText(path, content.Replace(oldStr, newStr)); + } + + return path; + } + /// + /// 文件名称 + /// + public static string FileNameReplace(string path, string oldStr, string newStr) + { + string fileName = Path.GetFileName(path); + if (!fileName.Contains(oldStr)) + { + return path; + } + + string? directoryName = Path.GetDirectoryName(path); + string newFileName = fileName.Replace(oldStr, newStr); + string newPath = Path.Combine(directoryName ?? "", newFileName); + File.Move(path, newPath); + + return newPath; + } + /// + /// 目录名替换 + /// + public static string DirectoryNameReplace(string path, string oldStr, string newStr) + { + string fileName = Path.GetFileName(path); + if (!fileName.Contains(oldStr)) + { + return path; + } + + string? directoryName = Path.GetDirectoryName(path); + string newFileName = fileName.Replace(oldStr, newStr); + string newPath = Path.Combine(directoryName ?? "", newFileName); + Directory.Move(path, newPath); + return newPath; + } + + /// + /// 全部信息递归替换 + /// + /// + /// + /// + public static void AllInfoReplace(string dirPath, string oldStr, string newStr) + { + var path = DirectoryNameReplace(dirPath, oldStr, newStr); + var dirInfo = new DirectoryInfo(path); + var files = dirInfo.GetFiles(); + var dirs = dirInfo.GetDirectories(); + if (files.Length > 0) + { + foreach (var f in files) + { + FileContentReplace(f.FullName, oldStr, newStr); + FileNameReplace(f.FullName, oldStr, newStr); + } + } + if (dirs.Length > 0) + { + foreach (var d in dirs) + { + AllInfoReplace(d.FullName, oldStr, newStr); + } + } + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HtmlHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HtmlHelper.cs new file mode 100644 index 00000000..857de345 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HtmlHelper.cs @@ -0,0 +1,24 @@ +namespace Yi.Framework.Core.Helper +{ + public static class HtmlHelper + { + #region 去除富文本中的HTML标签 + /// + /// 去除富文本中的HTML标签 + /// + /// + /// + /// + public static string ReplaceHtmlTag(string html, int length = 0) + { + string strText = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", ""); + strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", ""); + + if (length > 0 && strText.Length > length) + return strText.Substring(0, length); + + return strText; + } + #endregion + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HttpHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HttpHelper.cs new file mode 100644 index 00000000..eb37c1ae --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/HttpHelper.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mime; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class HttpHelper + { + + public static HttpClient Client { get; set; } = new HttpClient(); + + public static async Task Get(string url) + { + return await Client.GetStringAsync(url); + } + + public static async Task GetIO(string url) + { + return await Client.GetStreamAsync(url); + } + + + public static async Task Post(string url, object? item = null, Dictionary? head = null) + { + + using StringContent json = new(JsonSerializer.Serialize(item), Encoding.UTF8, MediaTypeNames.Application.Json); + + + if (head is not null) + { + foreach (var d in head) + { + json.Headers.Add(d.Key, d.Value); + } + } + + var httpResponse = await Client.PostAsync(url, json); + + httpResponse.EnsureSuccessStatusCode(); + + var content = httpResponse.Content; + + return await content.ReadAsStringAsync(); + } + + +// public static string HttpGet(string Url, string postDataStr="") +// { +//#pragma warning disable SYSLIB0014 // 类型或成员已过时 +// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr); +//#pragma warning restore SYSLIB0014 // 类型或成员已过时 +// request.Method = "GET"; +// request.ContentType = "text/html;charset=UTF-8"; + +// HttpWebResponse response = (HttpWebResponse)request.GetResponse(); +// Stream myResponseStream = response.GetResponseStream(); +// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); +// string retString = myStreamReader.ReadToEnd(); +// myStreamReader.Close(); +// myResponseStream.Close(); + +// return retString; +// } + +// public static bool HttpIOGet(string Url, string file, string postDataStr="") +// { +// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr); +// request.Method = "GET"; +// request.ContentType = "text/html;charset=UTF-8"; + +// HttpWebResponse response = (HttpWebResponse)request.GetResponse(); +// Stream myResponseStream = response.GetResponseStream(); +// FileStream writer = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write); +// byte[] buffer = new byte[1024]; +// int c; +// while ((c = myResponseStream.Read(buffer, 0, buffer.Length)) > 0) +// { +// writer.Write(buffer, 0, c); +// } +// writer.Close(); +// myResponseStream.Close(); + +// return true; +// } + +// public static string HttpPost(string Url, string postDataStr="") +// { +// CookieContainer cookie = new CookieContainer(); +//#pragma warning disable SYSLIB0014 // 类型或成员已过时 +// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); +//#pragma warning restore SYSLIB0014 // 类型或成员已过时 +// request.Method = "POST"; +// request.ContentType = "application/x-www-form-urlencoded"; +// request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr); +// request.CookieContainer = cookie; + +// Stream myRequestStream = request.GetRequestStream(); +// StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312")); +// myStreamWriter.Write(postDataStr); +// myStreamWriter.Close(); + +// HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + +// response.Cookies = cookie.GetCookies(response.ResponseUri); +// Stream myResponseStream = response.GetResponseStream(); +// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); +// string retString = myStreamReader.ReadToEnd(); +// myStreamReader.Close(); +// myResponseStream.Close(); + +// return retString; +// } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IdHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IdHelper.cs new file mode 100644 index 00000000..ca1ad53d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IdHelper.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class IdHelper + { + public static dynamic[] ToDynamicArray(this IEnumerable ids) + { + return ids.Select(id => (dynamic)id).ToArray(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IpHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IpHelper.cs new file mode 100644 index 00000000..60a4fdd7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/IpHelper.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; + +namespace Yi.Framework.Core.Helper +{ + public class IpHelper + { + /// + /// 获取当前IP地址 + /// + /// + /// + public static string GetCurrentIp(string preferredNetworks) + { + var instanceIp = "127.0.0.1"; + + try + { + // 获取可用网卡 + var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up); + + // 获取所有可用网卡IP信息 + var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses); + + if (ipCollection is null) + { + return instanceIp; + } + + foreach (var ipadd in ipCollection) + { + if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork) + { + if (string.IsNullOrEmpty(preferredNetworks)) + { + instanceIp = ipadd.Address.ToString(); + break; + } + + if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue; + instanceIp = ipadd.Address.ToString(); + break; + } + } + } + catch + { + // ignored + } + + return instanceIp; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/JsonHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/JsonHelper.cs new file mode 100644 index 00000000..87e29171 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/JsonHelper.cs @@ -0,0 +1,518 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Text.Json; + +namespace Yi.Framework.Core.Helper +{ + public class JsonHelper + { + public static string ObjToStr(T obj, string dateTimeFormat) + { + IsoDateTimeConverter timeConverter = new IsoDateTimeConverter() + { + DateTimeFormat = dateTimeFormat + }; + return Newtonsoft.Json.JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter); + } + + public static string ObjToStr(T obj) + { + return Newtonsoft.Json.JsonConvert.SerializeObject(obj); + } + + public static T StrToObj(string str) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(str)!; + } + /// + /// 转换对象为JSON格式数据 + /// + /// + /// 对象 + /// 字符格式的JSON数据 + public static string GetJSON(object obj) + { + string result = String.Empty; + try + { + System.Text.Json.JsonSerializer.Serialize(""); + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = + new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); + using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) + { + serializer.WriteObject(ms, obj); + result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); + } + } + catch (Exception) + { + throw; + } + return result; + } + /// + /// 转换List的数据为JSON格式 + /// + /// + /// 列表值 + /// JSON格式数据 + public string JSON(List vals) + { + System.Text.StringBuilder st = new System.Text.StringBuilder(); + try + { + System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); + + foreach (T city in vals) + { + using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) + { + s.WriteObject(ms, city); + st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray())); + } + } + } + catch (Exception) + { + } + + return st.ToString(); + } + /// + /// JSON格式字符转换为T类型的对象 + /// + /// + /// + /// + public static T ParseFormByJson(string jsonStr) + { + T obj = Activator.CreateInstance(); + using (System.IO.MemoryStream ms = + new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr))) + { + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = + new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); + return (T)serializer.ReadObject(ms)!; + } + } + + public string JSON1(List vals) + { + System.Text.StringBuilder st = new System.Text.StringBuilder(); + try + { + System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(SendData)); + + foreach (SendData city in vals) + { + using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) + { + s.WriteObject(ms, city); + st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray())); + } + } + } + catch (Exception) + { + } + + return st.ToString(); + } + + private static bool IsJsonStart(ref string json) + { + if (!string.IsNullOrEmpty(json)) + { + json = json.Trim('\r', '\n', ' '); + if (json.Length > 1) + { + char s = json[0]; + char e = json[json.Length - 1]; + return (s == '{' && e == '}') || (s == '[' && e == ']'); + } + } + return false; + } + public static bool IsJson(string json) + { + int errIndex; + return IsJson(json, out errIndex); + } + public static bool IsJson(string json, out int errIndex) + { + errIndex = 0; + if (IsJsonStart(ref json)) + { + CharState cs = new CharState(); + char c; + for (int i = 0; i < json.Length; i++) + { + c = json[i]; + if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。 + { + string item = json.Substring(i); + int err; + int length = GetValueLength(item, true, out err); + cs.childrenStart = false; + if (err > 0) + { + errIndex = i + err; + return false; + } + i = i + length - 1; + } + if (cs.isError) + { + errIndex = i; + return false; + } + } + + return !cs.arrayStart && !cs.jsonStart; + } + return false; + } + + /// + /// 获取值的长度(当Json值嵌套以"{"或"["开头时) + /// + private static int GetValueLength(string json, bool breakOnErr, out int errIndex) + { + errIndex = 0; + int len = 0; + if (!string.IsNullOrEmpty(json)) + { + CharState cs = new CharState(); + char c; + for (int i = 0; i < json.Length; i++) + { + c = json[i]; + if (!SetCharState(c, ref cs))//设置关键符号状态。 + { + if (!cs.jsonStart && !cs.arrayStart)//json结束,又不是数组,则退出。 + { + break; + } + } + else if (cs.childrenStart)//正常字符,值状态下。 + { + int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值,返回一个长度。。。 + cs.childrenStart = false; + cs.valueStart = 0; + //cs.state = 0; + i = i + length - 1; + } + if (breakOnErr && cs.isError) + { + errIndex = i; + return i; + } + if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。 + { + len = i + 1;//长度比索引+1 + break; + } + } + } + return len; + } + + /// + /// 设置字符状态(返回true则为关键词,返回false则当为普通字符处理) + /// + private static bool SetCharState(char c, ref CharState cs) + { + cs.CheckIsError(c); + switch (c) + { + case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] + #region 大括号 + if (cs.keyStart <= 0 && cs.valueStart <= 0) + { + cs.keyStart = 0; + cs.valueStart = 0; + if (cs.jsonStart && cs.state == 1) + { + cs.childrenStart = true; + } + else + { + cs.state = 0; + } + cs.jsonStart = true;//开始。 + return true; + } + #endregion + break; + case '}': + #region 大括号结束 + if (cs.keyStart <= 0 && cs.valueStart < 2 && cs.jsonStart) + { + cs.jsonStart = false;//正常结束。 + cs.state = 0; + cs.keyStart = 0; + cs.valueStart = 0; + cs.setDicValue = true; + return true; + } + // cs.isError = !cs.jsonStart && cs.state == 0; + #endregion + break; + case '[': + #region 中括号开始 + if (!cs.jsonStart) + { + cs.arrayStart = true; + return true; + } + else if (cs.jsonStart && cs.state == 1) + { + cs.childrenStart = true; + return true; + } + #endregion + break; + case ']': + #region 中括号结束 + if (cs.arrayStart && !cs.jsonStart && cs.keyStart <= 2 && cs.valueStart <= 0)//[{},333]//这样结束。 + { + cs.keyStart = 0; + cs.valueStart = 0; + cs.arrayStart = false; + return true; + } + #endregion + break; + case '"': + case '\'': + #region 引号 + if (cs.jsonStart || cs.arrayStart) + { + if (cs.state == 0)//key阶段,有可能是数组["aa",{}] + { + if (cs.keyStart <= 0) + { + cs.keyStart = (c == '"' ? 3 : 2); + return true; + } + else if ((cs.keyStart == 2 && c == '\'') || (cs.keyStart == 3 && c == '"')) + { + if (!cs.escapeChar) + { + cs.keyStart = -1; + return true; + } + else + { + cs.escapeChar = false; + } + } + } + else if (cs.state == 1 && cs.jsonStart)//值阶段必须是Json开始了。 + { + if (cs.valueStart <= 0) + { + cs.valueStart = (c == '"' ? 3 : 2); + return true; + } + else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"')) + { + if (!cs.escapeChar) + { + cs.valueStart = -1; + return true; + } + else + { + cs.escapeChar = false; + } + } + + } + } + #endregion + break; + case ':': + #region 冒号 + if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0) + { + if (cs.keyStart == 1) + { + cs.keyStart = -1; + } + cs.state = 1; + return true; + } + // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1); + #endregion + break; + case ',': + #region 逗号 //["aa",{aa:12,}] + + if (cs.jsonStart) + { + if (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1) + { + cs.state = 0; + cs.keyStart = 0; + cs.valueStart = 0; + //if (cs.valueStart == 1) + //{ + // cs.valueStart = 0; + //} + cs.setDicValue = true; + return true; + } + } + else if (cs.arrayStart && cs.keyStart <= 2) + { + cs.keyStart = 0; + //if (cs.keyStart == 1) + //{ + // cs.keyStart = -1; + //} + return true; + } + #endregion + break; + case ' ': + case '\r': + case '\n'://[ "a",\r\n{} ] + case '\0': + case '\t': + if (cs.keyStart <= 0 && cs.valueStart <= 0) //cs.jsonStart && + { + return true;//跳过空格。 + } + break; + default: //值开头。。 + if (c == '\\') //转义符号 + { + if (cs.escapeChar) + { + cs.escapeChar = false; + } + else + { + cs.escapeChar = true; + return true; + } + } + else + { + cs.escapeChar = false; + } + if (cs.jsonStart || cs.arrayStart) // Json 或数组开始了。 + { + if (cs.keyStart <= 0 && cs.state == 0) + { + cs.keyStart = 1;//无引号的 + } + else if (cs.valueStart <= 0 && cs.state == 1 && cs.jsonStart)//只有Json开始才有值。 + { + cs.valueStart = 1;//无引号的 + } + } + break; + } + return false; + } + } + /// + /// 字符状态 + /// + public class CharState + { + internal bool jsonStart = false;//以 "{"开始了... + internal bool setDicValue = false;// 可以设置字典值了。 + internal bool escapeChar = false;//以"\"转义符号开始了 + /// + /// 数组开始【仅第一开头才算】,值嵌套的以【childrenStart】来标识。 + /// + internal bool arrayStart = false;//以"[" 符号开始了 + internal bool childrenStart = false;//子级嵌套开始了。 + /// + /// 【0 初始状态,或 遇到“,”逗号】;【1 遇到“:”冒号】 + /// + internal int state = 0; + + /// + /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 + /// + internal int keyStart = 0; + /// + /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 + /// + internal int valueStart = 0; + internal bool isError = false;//是否语法错误。 + + internal void CheckIsError(char c)//只当成一级处理(因为GetLength会递归到每一个子项处理) + { + if (keyStart > 1 || valueStart > 1) + { + return; + } + //示例 ["aa",{"bbbb":123,"fff","ddd"}] + switch (c) + { + case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] + isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。 + break; + case '}': + isError = !jsonStart || (keyStart != 0 && state == 0);//重复结束错误 或者 提前结束{"aa"}。正常的有{} + break; + case '[': + isError = arrayStart && state == 0;//重复开始错误 + break; + case ']': + isError = !arrayStart || jsonStart;//重复开始错误 或者 Json 未结束 + break; + case '"': + case '\'': + isError = !(jsonStart || arrayStart); //json 或数组开始。 + if (!isError) + { + //重复开始 [""",{"" "}] + isError = (state == 0 && keyStart == -1) || (state == 1 && valueStart == -1); + } + if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}] + { + isError = true; + } + break; + case ':': + isError = !jsonStart || state == 1;//重复出现。 + break; + case ',': + isError = !(jsonStart || arrayStart); //json 或数组开始。 + if (!isError) + { + if (jsonStart) + { + isError = state == 0 || (state == 1 && valueStart > 1);//重复出现。 + } + else if (arrayStart)//["aa,] [,] [{},{}] + { + isError = keyStart == 0 && !setDicValue; + } + } + break; + case ' ': + case '\r': + case '\n'://[ "a",\r\n{} ] + case '\0': + case '\t': + break; + default: //值开头。。 + isError = (!jsonStart && !arrayStart) || (state == 0 && keyStart == -1) || (valueStart == -1 && state == 1);// + break; + } + //if (isError) + //{ + + //} + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MD5Hepler.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MD5Hepler.cs new file mode 100644 index 00000000..c7f4c1f2 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MD5Hepler.cs @@ -0,0 +1,132 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Yi.Framework.Core.Helper +{ + public class MD5Helper + { + /// + /// 生成PasswordSalt + /// + /// 返回string + public static string GenerateSalt() + { + byte[] buf = new byte[16]; +#pragma warning disable SYSLIB0023 // 类型或成员已过时 + (new RNGCryptoServiceProvider()).GetBytes(buf); +#pragma warning restore SYSLIB0023 // 类型或成员已过时 + return Convert.ToBase64String(buf); + } + + /// + /// 加密密码 + /// + /// 密码 + /// 加密类型 + /// PasswordSalt + /// 加密后的密码 + public static string SHA2Encode(string pass, string salt, int passwordFormat = 1) + { + if (passwordFormat == 0) // MembershipPasswordFormat.Clear + return pass; + + byte[] bIn = Encoding.Unicode.GetBytes(pass); + byte[] bSalt = Convert.FromBase64String(salt); + byte[] bAll = new byte[bSalt.Length + bIn.Length]; + byte[]? bRet = null; + + Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length); + Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length); + +#pragma warning disable SYSLIB0021 // 类型或成员已过时 + var s = SHA512Managed.Create(); +#pragma warning restore SYSLIB0021 // 类型或成员已过时 + bRet = s.ComputeHash(bAll); + + return ConvertEx.ToUrlBase64String(bRet); + } + + /// + /// 16位MD5加密 + /// + /// + /// + public static string MD5Encrypt16(string password) + { + var md5 = MD5.Create(); + string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8); + t2 = t2.Replace("-", string.Empty); + return t2; + } + + /// + /// 32位MD5加密 + /// + /// + /// + public static string MD5Encrypt32(string password = "") + { + string pwd = string.Empty; + try + { + if (!string.IsNullOrEmpty(password) && !string.IsNullOrWhiteSpace(password)) + { + MD5 md5 = MD5.Create(); //实例化一个md5对像 + // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择  + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); + // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得 + foreach (var item in s) + { + // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 + pwd = string.Concat(pwd, item.ToString("X2")); + } + } + } + catch + { + throw new Exception($"错误的 password 字符串:【{password}】"); + } + return pwd; + } + + /// + /// 64位MD5加密 + /// + /// + /// + public static string MD5Encrypt64(string password) + { + // 实例化一个md5对像 + // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择  + MD5 md5 = MD5.Create(); + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); + return Convert.ToBase64String(s); + } + } + public class ConvertEx + { + static readonly char[] padding = { '=' }; + public static string ToUrlBase64String(byte[] inArray) + { + var str = Convert.ToBase64String(inArray); + str = str.TrimEnd(padding).Replace('+', '-').Replace('/', '_'); + + return str; + } + + public static byte[] FromUrlBase64String(string s) + { + string incoming = s.Replace('_', '/').Replace('-', '+'); + switch (s.Length % 4) + { + case 2: incoming += "=="; break; + case 3: incoming += "="; break; + } + byte[] bytes = Convert.FromBase64String(incoming); + + return bytes; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MimeHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MimeHelper.cs new file mode 100644 index 00000000..d238f27e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/MimeHelper.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Core.Helper +{ + public static class MimeHelper + { + // 通过自己定义一个静态类 + // 将所有的Content Type都扔进去吧 + // 调用的时候直接调用静态方法即可。 + + public static List ImageType { get; set; } = new List + { + ".jpg",".png",".jpge" + }; + + private static Hashtable _mimeMappingTable; + + private static void AddMimeMapping(string extension, string MimeType) + { + MimeHelper._mimeMappingTable.Add(extension, MimeType); + } + + public static string GetMimeMapping(string FileName) + { + string text = null!; + int num = FileName.LastIndexOf('.'); + if (0 < num && num > FileName.LastIndexOf('\\')) + { + text = (string)MimeHelper._mimeMappingTable[FileName.Substring(num)]!; + } + if (text == null) + { + text = (string)MimeHelper._mimeMappingTable[".*"]!; + } + return text; + } + + public static FileTypeEnum GetFileType(string fileName) + { + var extension = Path.GetExtension(fileName); + if(ImageType.Contains(extension.ToLower())) + return FileTypeEnum.Image; + return FileTypeEnum.File; + + + } + + static MimeHelper() + { + MimeHelper._mimeMappingTable = new Hashtable(190, StringComparer.CurrentCultureIgnoreCase); + MimeHelper.AddMimeMapping(".323", "text/h323"); + MimeHelper.AddMimeMapping(".asx", "video/x-ms-asf"); + MimeHelper.AddMimeMapping(".acx", "application/internet-property-stream"); + MimeHelper.AddMimeMapping(".ai", "application/postscript"); + MimeHelper.AddMimeMapping(".aif", "audio/x-aiff"); + MimeHelper.AddMimeMapping(".aiff", "audio/aiff"); + MimeHelper.AddMimeMapping(".axs", "application/olescript"); + MimeHelper.AddMimeMapping(".aifc", "audio/aiff"); + MimeHelper.AddMimeMapping(".asr", "video/x-ms-asf"); + MimeHelper.AddMimeMapping(".avi", "video/x-msvideo"); + MimeHelper.AddMimeMapping(".asf", "video/x-ms-asf"); + MimeHelper.AddMimeMapping(".au", "audio/basic"); + MimeHelper.AddMimeMapping(".application", "application/x-ms-application"); + MimeHelper.AddMimeMapping(".bin", "application/octet-stream"); + MimeHelper.AddMimeMapping(".bas", "text/plain"); + MimeHelper.AddMimeMapping(".bcpio", "application/x-bcpio"); + MimeHelper.AddMimeMapping(".bmp", "image/bmp"); + MimeHelper.AddMimeMapping(".cdf", "application/x-cdf"); + MimeHelper.AddMimeMapping(".cat", "application/vndms-pkiseccat"); + MimeHelper.AddMimeMapping(".crt", "application/x-x509-ca-cert"); + MimeHelper.AddMimeMapping(".c", "text/plain"); + MimeHelper.AddMimeMapping(".css", "text/css"); + MimeHelper.AddMimeMapping(".cer", "application/x-x509-ca-cert"); + MimeHelper.AddMimeMapping(".crl", "application/pkix-crl"); + MimeHelper.AddMimeMapping(".cmx", "image/x-cmx"); + MimeHelper.AddMimeMapping(".csh", "application/x-csh"); + MimeHelper.AddMimeMapping(".cod", "image/cis-cod"); + MimeHelper.AddMimeMapping(".cpio", "application/x-cpio"); + MimeHelper.AddMimeMapping(".clp", "application/x-msclip"); + MimeHelper.AddMimeMapping(".crd", "application/x-mscardfile"); + MimeHelper.AddMimeMapping(".deploy", "application/octet-stream"); + MimeHelper.AddMimeMapping(".dll", "application/x-msdownload"); + MimeHelper.AddMimeMapping(".dot", "application/msword"); + MimeHelper.AddMimeMapping(".doc", "application/msword"); + MimeHelper.AddMimeMapping(".dvi", "application/x-dvi"); + MimeHelper.AddMimeMapping(".dir", "application/x-director"); + MimeHelper.AddMimeMapping(".dxr", "application/x-director"); + MimeHelper.AddMimeMapping(".der", "application/x-x509-ca-cert"); + MimeHelper.AddMimeMapping(".dib", "image/bmp"); + MimeHelper.AddMimeMapping(".dcr", "application/x-director"); + MimeHelper.AddMimeMapping(".disco", "text/xml"); + MimeHelper.AddMimeMapping(".exe", "application/octet-stream"); + MimeHelper.AddMimeMapping(".etx", "text/x-setext"); + MimeHelper.AddMimeMapping(".evy", "application/envoy"); + MimeHelper.AddMimeMapping(".eml", "message/rfc822"); + MimeHelper.AddMimeMapping(".eps", "application/postscript"); + MimeHelper.AddMimeMapping(".flr", "x-world/x-vrml"); + MimeHelper.AddMimeMapping(".fif", "application/fractals"); + MimeHelper.AddMimeMapping(".gtar", "application/x-gtar"); + MimeHelper.AddMimeMapping(".gif", "image/gif"); + MimeHelper.AddMimeMapping(".gz", "application/x-gzip"); + MimeHelper.AddMimeMapping(".hta", "application/hta"); + MimeHelper.AddMimeMapping(".htc", "text/x-component"); + MimeHelper.AddMimeMapping(".htt", "text/webviewhtml"); + MimeHelper.AddMimeMapping(".h", "text/plain"); + MimeHelper.AddMimeMapping(".hdf", "application/x-hdf"); + MimeHelper.AddMimeMapping(".hlp", "application/winhlp"); + MimeHelper.AddMimeMapping(".html", "text/html"); + MimeHelper.AddMimeMapping(".htm", "text/html"); + MimeHelper.AddMimeMapping(".hqx", "application/mac-binhex40"); + MimeHelper.AddMimeMapping(".isp", "application/x-internet-signup"); + MimeHelper.AddMimeMapping(".iii", "application/x-iphone"); + MimeHelper.AddMimeMapping(".ief", "image/ief"); + MimeHelper.AddMimeMapping(".ivf", "video/x-ivf"); + MimeHelper.AddMimeMapping(".ins", "application/x-internet-signup"); + MimeHelper.AddMimeMapping(".ico", "image/x-icon"); + MimeHelper.AddMimeMapping(".jpg", "image/jpeg"); + MimeHelper.AddMimeMapping(".jfif", "image/pjpeg"); + MimeHelper.AddMimeMapping(".jpe", "image/jpeg"); + MimeHelper.AddMimeMapping(".jpeg", "image/jpeg"); + MimeHelper.AddMimeMapping(".js", "application/x-javascript"); + MimeHelper.AddMimeMapping(".lsx", "video/x-la-asf"); + MimeHelper.AddMimeMapping(".latex", "application/x-latex"); + MimeHelper.AddMimeMapping(".lsf", "video/x-la-asf"); + MimeHelper.AddMimeMapping(".manifest", "application/x-ms-manifest"); + MimeHelper.AddMimeMapping(".mhtml", "message/rfc822"); + MimeHelper.AddMimeMapping(".mny", "application/x-msmoney"); + MimeHelper.AddMimeMapping(".mht", "message/rfc822"); + MimeHelper.AddMimeMapping(".mid", "audio/mid"); + MimeHelper.AddMimeMapping(".mpv2", "video/mpeg"); + MimeHelper.AddMimeMapping(".man", "application/x-troff-man"); + MimeHelper.AddMimeMapping(".mvb", "application/x-msmediaview"); + MimeHelper.AddMimeMapping(".mpeg", "video/mpeg"); + MimeHelper.AddMimeMapping(".m3u", "audio/x-mpegurl"); + MimeHelper.AddMimeMapping(".mdb", "application/x-msaccess"); + MimeHelper.AddMimeMapping(".mpp", "application/vnd.ms-project"); + MimeHelper.AddMimeMapping(".m1v", "video/mpeg"); + MimeHelper.AddMimeMapping(".mpa", "video/mpeg"); + MimeHelper.AddMimeMapping(".me", "application/x-troff-me"); + MimeHelper.AddMimeMapping(".m13", "application/x-msmediaview"); + MimeHelper.AddMimeMapping(".movie", "video/x-sgi-movie"); + MimeHelper.AddMimeMapping(".m14", "application/x-msmediaview"); + MimeHelper.AddMimeMapping(".mpe", "video/mpeg"); + MimeHelper.AddMimeMapping(".mp2", "video/mpeg"); + MimeHelper.AddMimeMapping(".mov", "video/quicktime"); + MimeHelper.AddMimeMapping(".mp3", "audio/mpeg"); + MimeHelper.AddMimeMapping(".mpg", "video/mpeg"); + MimeHelper.AddMimeMapping(".ms", "application/x-troff-ms"); + MimeHelper.AddMimeMapping(".nc", "application/x-netcdf"); + MimeHelper.AddMimeMapping(".nws", "message/rfc822"); + MimeHelper.AddMimeMapping(".oda", "application/oda"); + MimeHelper.AddMimeMapping(".ods", "application/oleobject"); + MimeHelper.AddMimeMapping(".pmc", "application/x-perfmon"); + MimeHelper.AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp"); + MimeHelper.AddMimeMapping(".p7b", "application/x-pkcs7-certificates"); + MimeHelper.AddMimeMapping(".p7s", "application/pkcs7-signature"); + MimeHelper.AddMimeMapping(".pmw", "application/x-perfmon"); + MimeHelper.AddMimeMapping(".ps", "application/postscript"); + MimeHelper.AddMimeMapping(".p7c", "application/pkcs7-mime"); + MimeHelper.AddMimeMapping(".pbm", "image/x-portable-bitmap"); + MimeHelper.AddMimeMapping(".ppm", "image/x-portable-pixmap"); + MimeHelper.AddMimeMapping(".pub", "application/x-mspublisher"); + MimeHelper.AddMimeMapping(".pnm", "image/x-portable-anymap"); + MimeHelper.AddMimeMapping(".png", "image/png"); + MimeHelper.AddMimeMapping(".pml", "application/x-perfmon"); + MimeHelper.AddMimeMapping(".p10", "application/pkcs10"); + MimeHelper.AddMimeMapping(".pfx", "application/x-pkcs12"); + MimeHelper.AddMimeMapping(".p12", "application/x-pkcs12"); + MimeHelper.AddMimeMapping(".pdf", "application/pdf"); + MimeHelper.AddMimeMapping(".pps", "application/vnd.ms-powerpoint"); + MimeHelper.AddMimeMapping(".p7m", "application/pkcs7-mime"); + MimeHelper.AddMimeMapping(".pko", "application/vndms-pkipko"); + MimeHelper.AddMimeMapping(".ppt", "application/vnd.ms-powerpoint"); + MimeHelper.AddMimeMapping(".pmr", "application/x-perfmon"); + MimeHelper.AddMimeMapping(".pma", "application/x-perfmon"); + MimeHelper.AddMimeMapping(".pot", "application/vnd.ms-powerpoint"); + MimeHelper.AddMimeMapping(".prf", "application/pics-rules"); + MimeHelper.AddMimeMapping(".pgm", "image/x-portable-graymap"); + MimeHelper.AddMimeMapping(".qt", "video/quicktime"); + MimeHelper.AddMimeMapping(".ra", "audio/x-pn-realaudio"); + MimeHelper.AddMimeMapping(".rgb", "image/x-rgb"); + MimeHelper.AddMimeMapping(".ram", "audio/x-pn-realaudio"); + MimeHelper.AddMimeMapping(".rmi", "audio/mid"); + MimeHelper.AddMimeMapping(".ras", "image/x-cmu-raster"); + MimeHelper.AddMimeMapping(".roff", "application/x-troff"); + MimeHelper.AddMimeMapping(".rtf", "application/rtf"); + MimeHelper.AddMimeMapping(".rtx", "text/richtext"); + MimeHelper.AddMimeMapping(".sv4crc", "application/x-sv4crc"); + MimeHelper.AddMimeMapping(".spc", "application/x-pkcs7-certificates"); + MimeHelper.AddMimeMapping(".setreg", "application/set-registration-initiation"); + MimeHelper.AddMimeMapping(".snd", "audio/basic"); + MimeHelper.AddMimeMapping(".stl", "application/vndms-pkistl"); + MimeHelper.AddMimeMapping(".setpay", "application/set-payment-initiation"); + MimeHelper.AddMimeMapping(".stm", "text/html"); + MimeHelper.AddMimeMapping(".shar", "application/x-shar"); + MimeHelper.AddMimeMapping(".sh", "application/x-sh"); + MimeHelper.AddMimeMapping(".sit", "application/x-stuffit"); + MimeHelper.AddMimeMapping(".spl", "application/futuresplash"); + MimeHelper.AddMimeMapping(".sct", "text/scriptlet"); + MimeHelper.AddMimeMapping(".scd", "application/x-msschedule"); + MimeHelper.AddMimeMapping(".sst", "application/vndms-pkicertstore"); + MimeHelper.AddMimeMapping(".src", "application/x-wais-source"); + MimeHelper.AddMimeMapping(".sv4cpio", "application/x-sv4cpio"); + MimeHelper.AddMimeMapping(".tex", "application/x-tex"); + MimeHelper.AddMimeMapping(".tgz", "application/x-compressed"); + MimeHelper.AddMimeMapping(".t", "application/x-troff"); + MimeHelper.AddMimeMapping(".tar", "application/x-tar"); + MimeHelper.AddMimeMapping(".tr", "application/x-troff"); + MimeHelper.AddMimeMapping(".tif", "image/tiff"); + MimeHelper.AddMimeMapping(".txt", "text/plain"); + MimeHelper.AddMimeMapping(".texinfo", "application/x-texinfo"); + MimeHelper.AddMimeMapping(".trm", "application/x-msterminal"); + MimeHelper.AddMimeMapping(".tiff", "image/tiff"); + MimeHelper.AddMimeMapping(".tcl", "application/x-tcl"); + MimeHelper.AddMimeMapping(".texi", "application/x-texinfo"); + MimeHelper.AddMimeMapping(".tsv", "text/tab-separated-values"); + MimeHelper.AddMimeMapping(".ustar", "application/x-ustar"); + MimeHelper.AddMimeMapping(".uls", "text/iuls"); + MimeHelper.AddMimeMapping(".vcf", "text/x-vcard"); + MimeHelper.AddMimeMapping(".wps", "application/vnd.ms-works"); + MimeHelper.AddMimeMapping(".wav", "audio/wav"); + MimeHelper.AddMimeMapping(".wrz", "x-world/x-vrml"); + MimeHelper.AddMimeMapping(".wri", "application/x-mswrite"); + MimeHelper.AddMimeMapping(".wks", "application/vnd.ms-works"); + MimeHelper.AddMimeMapping(".wmf", "application/x-msmetafile"); + MimeHelper.AddMimeMapping(".wcm", "application/vnd.ms-works"); + MimeHelper.AddMimeMapping(".wrl", "x-world/x-vrml"); + MimeHelper.AddMimeMapping(".wdb", "application/vnd.ms-works"); + MimeHelper.AddMimeMapping(".wsdl", "text/xml"); + MimeHelper.AddMimeMapping(".xap", "application/x-silverlight-app"); + MimeHelper.AddMimeMapping(".xml", "text/xml"); + MimeHelper.AddMimeMapping(".xlm", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xaf", "x-world/x-vrml"); + MimeHelper.AddMimeMapping(".xla", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xls", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xlsx", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xof", "x-world/x-vrml"); + MimeHelper.AddMimeMapping(".xlt", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xlc", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xsl", "text/xml"); + MimeHelper.AddMimeMapping(".xbm", "image/x-xbitmap"); + MimeHelper.AddMimeMapping(".xlw", "application/vnd.ms-excel"); + MimeHelper.AddMimeMapping(".xpm", "image/x-xpixmap"); + MimeHelper.AddMimeMapping(".xwd", "image/x-xwindowdump"); + MimeHelper.AddMimeMapping(".xsd", "text/xml"); + MimeHelper.AddMimeMapping(".z", "application/x-compress"); + MimeHelper.AddMimeMapping(".zip", "application/x-zip-compressed"); + MimeHelper.AddMimeMapping(".*", "application/octet-stream"); + } + } + + + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAFileHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAFileHelper.cs new file mode 100644 index 00000000..cc873a2c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAFileHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public class RSAFileHelper + { + public static RSA GetKey() + { + return GetRSA("key.pem"); + } + public static RSA GetPublicKey() + { + return GetRSA("public.pem"); + } + + private static RSA GetRSA(string fileName) + { + string rootPath = Directory.GetCurrentDirectory(); + string filePath = Path.Combine(rootPath, fileName); + if (!System.IO.File.Exists(filePath)) + throw new Exception("文件不存在"); + string key = System.IO.File.ReadAllText(filePath); + var rsa = RSA.Create(); + rsa.ImportFromPem(key.AsSpan()); + return rsa; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAHelper.cs new file mode 100644 index 00000000..f2fd6990 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RSAHelper.cs @@ -0,0 +1,390 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Yi.Framework.Core.Helper +{ + /// + /// RSA加解密 使用OpenSSL的公钥加密/私钥解密 + /// 公私钥请使用openssl生成 + /// + public class RSAHelper + { + public readonly RSA? _privateKeyRsaProvider; + public readonly RSA? _publicKeyRsaProvider; + private readonly HashAlgorithmName _hashAlgorithmName; + private readonly Encoding _encoding; + + /// + /// 实例化RSAHelper + /// + /// 加密算法类型 RSA SHA1;RSA2 SHA256 密钥长度至少为2048 + /// 编码类型 + /// 私钥 + /// 公钥 + public RSAHelper(RSAType rsaType, Encoding encoding, string privateKey, string? publicKey = null) + { + _encoding = encoding; + if (!string.IsNullOrEmpty(privateKey)) + { + _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey); + } + + if (!string.IsNullOrEmpty(publicKey)) + { + _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey); + } + + _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256; + } + + #region 使用私钥签名 + + /// + /// 使用私钥签名 + /// + /// 原始数据 + /// + public string Sign(string data) + { + byte[] dataBytes = _encoding.GetBytes(data); + + var signatureBytes = _privateKeyRsaProvider!.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); + + return Convert.ToBase64String(signatureBytes); + } + + #endregion + + #region 使用公钥验签 + + /// + /// 使用公钥验签 + /// + /// 原始数据 + /// 签名 + /// + public bool Verify(string data, string sign) + { + byte[] dataBytes = _encoding.GetBytes(data); + byte[] signBytes = Convert.FromBase64String(sign); + + var verify = _publicKeyRsaProvider!.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); + + return verify; + } + + #endregion + + #region 解密 + /// + /// 私钥解密(原) + /// + /// 解密字符串(base64) + /// + + //public string Decrypt(string cipherText) + //{ + // if (_privateKeyRsaProvider == null) + // { + // throw new Exception("_privateKeyRsaProvider is null"); + // } + // return _encoding.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1)); + //} + /// + /// 私钥解密(支持大量数据) + /// + /// + /// + public string Decrypt(string cipherText) + { + if (_privateKeyRsaProvider == null) + { + throw new Exception("_privateKeyRsaProvider is null"); + } + var bufferSize = (_privateKeyRsaProvider.KeySize / 8); + byte[] buffer = new byte[bufferSize];//待解密块 + using (MemoryStream msInput = new MemoryStream(Convert.FromBase64String(cipherText))) + { + using (MemoryStream msOutput = new MemoryStream()) + { + int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0) + { + byte[] dataToEnc = new byte[readLen]; + Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _privateKeyRsaProvider.Decrypt(dataToEnc, RSAEncryptionPadding.Pkcs1); + msOutput.Write(encData, 0, encData.Length); + } + byte[] result = msOutput.ToArray(); + return _encoding.GetString(result); + } + } + } + + #endregion + + #region 加密 + + /// + /// 公钥加密(原) + /// + /// + /// + //public string Encrypt(string text) + //{ + // if (_publicKeyRsaProvider == null) + // { + // throw new Exception("_publicKeyRsaProvider is null"); + // } + // return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1)); + //} + /// + /// 公钥加密(支持大量数据) + /// + /// + /// + public string Encrypt(string text) + { + if (_publicKeyRsaProvider == null) + { + throw new Exception("_publicKeyRsaProvider is null"); + } + var bufferSize = (_publicKeyRsaProvider.KeySize / 8 - 11); + byte[] buffer = new byte[bufferSize];//待加密块 + + using (MemoryStream msInput = new MemoryStream(_encoding.GetBytes(text))) + { + using (MemoryStream msOutput = new MemoryStream()) + { + int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0) + { + byte[] dataToEnc = new byte[readLen]; + Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _publicKeyRsaProvider.Encrypt(dataToEnc, RSAEncryptionPadding.Pkcs1); + msOutput.Write(encData, 0, encData.Length); + } + byte[] result = msOutput.ToArray(); + return Convert.ToBase64String(result); + } + } + } + + #endregion + + #region 使用私钥创建RSA实例 + /// + /// 使用私钥创建RSA实例 + /// + /// + /// + private RSA CreateRsaProviderFromPrivateKey(string privateKey) + { + var privateKeyBits = Convert.FromBase64String(privateKey); + + var rsa = RSA.Create(); + var rsaParameters = new RSAParameters(); + + using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))) + { + byte bt = 0; + ushort twobytes = 0; + twobytes = binr.ReadUInt16(); + if (twobytes == 0x8130) + binr.ReadByte(); + else if (twobytes == 0x8230) + binr.ReadInt16(); + else + throw new Exception("Unexpected value read binr.ReadUInt16()"); + + twobytes = binr.ReadUInt16(); + if (twobytes != 0x0102) + throw new Exception("Unexpected version"); + + bt = binr.ReadByte(); + if (bt != 0x00) + throw new Exception("Unexpected value read binr.ReadByte()"); + + rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr)); + rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr)); + } + + rsa.ImportParameters(rsaParameters); + return rsa; + } + + #endregion + + #region 使用公钥创建RSA实例 + /// + /// 使用公钥创建RSA实例 + /// + /// + /// + public RSA? CreateRsaProviderFromPublicKey(string publicKeyString) + { + // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" + byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; + byte[] seq = new byte[15]; + + var x509Key = Convert.FromBase64String(publicKeyString); + + // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ + using (MemoryStream mem = new MemoryStream(x509Key)) + { + using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading + { + byte bt = 0; + ushort twobytes = 0; + + twobytes = binr.ReadUInt16(); + if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) + binr.ReadByte(); //advance 1 byte + else if (twobytes == 0x8230) + binr.ReadInt16(); //advance 2 bytes + else + return null; + + seq = binr.ReadBytes(15); //read the Sequence OID + if (!CompareBytearrays(seq, seqOid)) //make sure Sequence for OID is correct + return null; + + twobytes = binr.ReadUInt16(); + if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) + binr.ReadByte(); //advance 1 byte + else if (twobytes == 0x8203) + binr.ReadInt16(); //advance 2 bytes + else + return null; + + bt = binr.ReadByte(); + if (bt != 0x00) //expect null byte next + return null; + + twobytes = binr.ReadUInt16(); + if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) + binr.ReadByte(); //advance 1 byte + else if (twobytes == 0x8230) + binr.ReadInt16(); //advance 2 bytes + else + return null; + + twobytes = binr.ReadUInt16(); + byte lowbyte = 0x00; + byte highbyte = 0x00; + + if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) + lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus + else if (twobytes == 0x8202) + { + highbyte = binr.ReadByte(); //advance 2 bytes + lowbyte = binr.ReadByte(); + } + else + return null; + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order + int modsize = BitConverter.ToInt32(modint, 0); + + int firstbyte = binr.PeekChar(); + if (firstbyte == 0x00) + { //if first byte (highest order) of modulus is zero, don't include it + binr.ReadByte(); //skip this null byte + modsize -= 1; //reduce modulus buffer size by 1 + } + + byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes + + if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data + return null; + int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) + byte[] exponent = binr.ReadBytes(expbytes); + + // ------- create RSACryptoServiceProvider instance and initialize with public key ----- + var rsa = RSA.Create(); + RSAParameters rsaKeyInfo = new RSAParameters + { + Modulus = modulus, + Exponent = exponent + }; + rsa.ImportParameters(rsaKeyInfo); + + return rsa; + } + + } + } + + #endregion + + #region 导入密钥算法 + + private int GetIntegerSize(BinaryReader binr) + { + byte bt = 0; + int count = 0; + bt = binr.ReadByte(); + if (bt != 0x02) + return 0; + bt = binr.ReadByte(); + + if (bt == 0x81) + count = binr.ReadByte(); + else + if (bt == 0x82) + { + var highbyte = binr.ReadByte(); + var lowbyte = binr.ReadByte(); + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; + count = BitConverter.ToInt32(modint, 0); + } + else + { + count = bt; + } + + while (binr.ReadByte() == 0x00) + { + count -= 1; + } + binr.BaseStream.Seek(-1, SeekOrigin.Current); + return count; + } + + private bool CompareBytearrays(byte[] a, byte[] b) + { + if (a.Length != b.Length) + return false; + int i = 0; + foreach (byte c in a) + { + if (c != b[i]) + return false; + i++; + } + return true; + } + + #endregion + + } + + /// + /// RSA算法类型 + /// + public enum RSAType + { + /// + /// SHA1 + /// + RSA = 0, + /// + /// RSA2 密钥长度至少为2048 + /// SHA256 + /// + RSA2 + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RandomHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RandomHelper.cs new file mode 100644 index 00000000..2a5ba81f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/RandomHelper.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Yi.Framework.Core.Helper +{ + public class RandomHelper + { + public static string replaceBianLiang(string content) + { + content = content.Replace("{当前时间}", DateTime.Now.TimeOfDay.ToString()); + string[] bianliang = new string[] { "{随机字母}", "{随机数字}", "{随机汉字}" }; + Regex r; + int count; + string readstr = ""; + foreach (string str in bianliang) + { + count = (content.Length - content.Replace(str, "").Length) / str.Length; + if (str == "{随机汉字}") readstr = RandChina(count); + if (str == "{随机数字}") readstr = GenerateCheckCodeNum(count); + if (str == "{随机字母}") readstr = GenerateRandomLetter(count); + if (count > readstr.Length) count = readstr.Length; + r = new Regex(str.Replace("{", "\\{").Replace("}", "\\}")); + for (int i = 0; i < count; i++) + { + content = r.Replace(content, readstr.Substring(i, 1), 1); + } + } + return content; + } + + + /// + /// 随机生成字母 + /// + /// + /// + public static string GenerateRandomLetter(int Length) + { + char[] Pattern = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + string result = ""; + int n = Pattern.Length; + Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); + for (int i = 0; i < Length; i++) + { + int rnd = random.Next(0, n); + result += Pattern[rnd]; + } + return result; + } + + /// + /// 随机生成数字 + /// + /// + /// + public static string GenerateCheckCodeNum(int codeCount) + { + int rep = 0; + string str = string.Empty; + long num2 = DateTime.Now.Ticks + rep; + rep++; + Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep))); + for (int i = 0; i < codeCount; i++) + { + int num = random.Next(); + str = str + ((char)(0x30 + ((ushort)(num % 10)))).ToString(); + } + return str; + } + + /// + /// 此函数为生成指定数目的汉字 + /// + /// 汉字数目 + /// 所有汉字 + public static string RandChina(int charLen) + { + int area, code;//汉字由区位和码位组成(都为0-94,其中区位16-55为一级汉字区,56-87为二级汉字区,1-9为特殊字符区) + StringBuilder strtem = new StringBuilder(); + Random rand = new Random(); + for (int i = 0; i < charLen; i++) + { + area = rand.Next(16, 88); + if (area == 55)//第55区只有89个字符 + { + code = rand.Next(1, 90); + } + else + { + code = rand.Next(1, 94); + } + strtem.Append(Encoding.GetEncoding("GB2312").GetString(new byte[] { Convert.ToByte(area + 160), Convert.ToByte(code + 160) })); + } + return strtem.ToString(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ReflexHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ReflexHelper.cs new file mode 100644 index 00000000..33316b1d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/ReflexHelper.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class ReflexHelper + { + + #region 对象相关 + /// + /// 取对象属性值 + /// + /// + /// + /// + public static string GetModelValue(string FieldName, object obj) + { + try + { + Type Ts = obj.GetType(); + object o = Ts.GetProperty(FieldName).GetValue(obj, null); + if (null == o) + return null; + string Value = Convert.ToString(o); + if (string.IsNullOrEmpty(Value)) + return null; + return Value; + } + catch (Exception ex) + { + throw ex; + } + return null; + } + + + /// + /// 设置对象属性值 + /// + /// + /// + /// + /// + public static bool SetModelValue(string FieldName, object Value, object obj) + { + try + { + Type Ts = obj.GetType(); + Ts.GetProperty(FieldName).SetValue(obj, Value, null); + return true; + } + catch (Exception ex) + { + throw ex; + } + return false; + } + #endregion + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/SnowflakeHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/SnowflakeHelper.cs new file mode 100644 index 00000000..cefe21e6 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/SnowflakeHelper.cs @@ -0,0 +1,102 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class SnowflakeHelper + { + public static long NextId { get => SnowFlakeSingle.Instance.NextId(); } + + public static long Next() + { + SnowflakeTool snowflakeTool = new SnowflakeTool(1); + return snowflakeTool.NextId(); + } + + private class SnowflakeTool + { + //机器ID + private static long nodeId; + private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳 + private static long sequence = 0L; + private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义) + public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID + private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码 + private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数 + private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数 + public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + private long lastTimestamp = -1L; + + /// + /// 机器码 + /// + /// + public SnowflakeTool(long workerId) + { + if (workerId > maxWorkerId || workerId < 0) + throw new Exception(string.Format("节点id 不能大于 {0} 或者 小于 0 ", workerId)); + SnowflakeTool.nodeId = workerId; + + } + + public long NextId() + { + lock (this) + { + long timestamp = TimeGen(); + if (this.lastTimestamp == timestamp) + { //同一微妙中生成ID + SnowflakeTool.sequence = (SnowflakeTool.sequence + 1) & SnowflakeTool.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限 + if (SnowflakeTool.sequence == 0) + { + //一微妙内产生的ID计数已达上限,等待下一微妙 + timestamp = TillNextMillis(this.lastTimestamp); + } + } + else + { //不同微秒生成ID + SnowflakeTool.sequence = 0; //计数清0 + } + if (timestamp < lastTimestamp) + { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过 + throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", + this.lastTimestamp - timestamp)); + } + this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳 + long nextId = (timestamp - twepoch << timestampLeftShift) | SnowflakeTool.nodeId << SnowflakeTool.workerIdShift | SnowflakeTool.sequence; + return nextId; + } + } + + /// + /// 获取下一微秒时间戳 + /// + /// + /// + private long TillNextMillis(long lastTimestamp) + { + long timestamp = TimeGen(); + while (timestamp <= lastTimestamp) + { + timestamp = TimeGen(); + } + return timestamp; + } + + /// + /// 生成当前时间戳 + /// + /// + private long TimeGen() + { + return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; + } + } + } + + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/StringHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/StringHelper.cs new file mode 100644 index 00000000..faa28a5f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/StringHelper.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Yi.Framework.Core.Helper +{ + public class StringHelper + { + /// + /// 根据分隔符返回前n条数据 + /// + /// 数据内容 + /// 分隔符 + /// 前n条 + /// 是否倒序(默认false) + /// + public static List GetTopDataBySeparator(string content, string separator, int top, bool isDesc = false) + { + if (string.IsNullOrEmpty(content)) + { + return new List() { }; + } + + if (string.IsNullOrEmpty(separator)) + { + throw new ArgumentException("message", nameof(separator)); + } + + var dataArray = content.Split(separator).Where(d => !string.IsNullOrEmpty(d)).ToArray(); + if (isDesc) + { + Array.Reverse(dataArray); + } + + if (top > 0) + { + dataArray = dataArray.Take(top).ToArray(); + } + + return dataArray.ToList(); + } + /// + /// 根据字段拼接get参数 + /// + /// + /// + public static string GetPars(Dictionary dic) + { + + StringBuilder sb = new StringBuilder(); + string? urlPars = null; + bool isEnter = false; + foreach (var item in dic) + { + sb.Append($"{(isEnter ? "&" : "")}{item.Key}={item.Value}"); + isEnter = true; + } + urlPars = sb.ToString(); + return urlPars; + } + /// + /// 根据字段拼接get参数 + /// + /// + /// + public static string GetPars(Dictionary dic) + { + + StringBuilder sb = new StringBuilder(); + string? urlPars = null; + bool isEnter = false; + foreach (var item in dic) + { + sb.Append($"{(isEnter ? "&" : "")}{item.Key}={item.Value}"); + isEnter = true; + } + urlPars = sb.ToString(); + return urlPars; + } + /// + /// 获取一个GUID + /// + /// 格式-默认为N + /// + public static string GetGUID(string format="N") { + return Guid.NewGuid().ToString(format); + } + /// + /// 根据GUID获取19位的唯一数字序列 + /// + /// + public static long GetGuidToLongID() + { + byte[] buffer = Guid.NewGuid().ToByteArray(); + return BitConverter.ToInt64(buffer, 0); + } + /// + /// 获取字符串最后X行 + /// + /// + /// + /// + public static string GetCusLine(string resourceStr, int length) { + string[] arrStr = resourceStr.Split("\r\n"); + return string.Join("", (from q in arrStr select q).Skip(arrStr.Length - length + 1).Take(length).ToArray()); + } + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/TreeHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/TreeHelper.cs new file mode 100644 index 00000000..bd688170 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/TreeHelper.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Helper +{ + public static class TreeHelper + { + public static List SetTree(List list, Action action = null!) + { + if (list is not null && list.Count > 0) + { + IList result = new List(); + long pid = list.Min(m => (m as ITreeModel)!.ParentId); + IList t = list.Where(m => (m as ITreeModel)!.ParentId == pid).ToList(); + foreach (T model in t) + { + if (action is not null) + { + action(model); + } + result.Add(model); + var item = (model as ITreeModel); + IList children = list.Where(m => (m as ITreeModel)!.ParentId == item!.Id).ToList(); + if (children.Count > 0) + { + SetTreeChildren(list, children, model, action!); + } + } + return result.OrderByDescending(m => (m as ITreeModel)!.OrderNum).ToList(); + } + return null!; + } + private static void SetTreeChildren(IList list, IList children, T model, Action action = null!) + { + var mm = (model as ITreeModel); + mm!.Children = new List(); + foreach (T item in children) + { + if (action is not null) + { + action(item); + } + mm.Children.Add(item); + var _item = (item as ITreeModel); + IList _children = list.Where(m => (m as ITreeModel)!.ParentId == _item!.Id).ToList(); + if (_children.Count > 0) + { + SetTreeChildren(list, _children, item, action!); + } + } + mm.Children = mm.Children.OrderByDescending(m => (m as ITreeModel)!.OrderNum).ToList(); + } + + + public interface ITreeModel + { + public long Id { get; set; } + public long ParentId { get; set; } + public int OrderNum { get; set; } + + public List? Children { get; set; } + } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UnicodeHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UnicodeHelper.cs new file mode 100644 index 00000000..0d8e737f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UnicodeHelper.cs @@ -0,0 +1,47 @@ +using System; +using System.Text; +using System.Text.RegularExpressions; + +namespace Yi.Framework.Core.Helper +{ + public static class UnicodeHelper + { + /// + /// 字符串转Unicode码 + /// + /// The to unicode. + /// Value. + public static string StringToUnicode(string value) + { + byte[] bytes = Encoding.Unicode.GetBytes(value); + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i += 2) + { + // 取两个字符,每个字符都是右对齐。 + stringBuilder.AppendFormat("u{0}{1}", bytes[i + 1].ToString("x").PadLeft(2, '0'), bytes[i].ToString("x").PadLeft(2, '0')); + } + return stringBuilder.ToString(); + } + + /// + /// Unicode转字符串 + /// + /// The to string. + /// Unicode. + public static string UnicodeToString(string unicode) + { + unicode = unicode.Replace("%", "\\"); + + return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace( + unicode, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16))); + + //string resultStr = ""; + //string[] strList = unicode.Split('u'); + //for (int i = 1; i < strList.Length; i++) + //{ + // resultStr += (char)int.Parse(strList[i], System.Globalization.NumberStyles.HexNumber); + //} + //return resultStr; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UrlHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UrlHelper.cs new file mode 100644 index 00000000..ed073407 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/UrlHelper.cs @@ -0,0 +1,23 @@ +namespace Yi.Framework.Core.Helper +{ + public class UrlHelper + { + /// + /// UrlEncode编码 + /// + /// url + /// + public static string UrlEncode(string url) { + return System.Web.HttpUtility.UrlEncode(url, System.Text.Encoding.UTF8); + } + /// + /// UrlEncode解码 + /// + /// 数据 + /// + public static string UrlDecode(string data) + { + return System.Web.HttpUtility.UrlDecode(data, System.Text.Encoding.UTF8); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/XmlHelper.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/XmlHelper.cs new file mode 100644 index 00000000..f40dd811 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Helper/XmlHelper.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Serialization; + +namespace Yi.Framework.Core.Helper +{ + public class XmlHelper + { + /// + /// 转换对象为JSON格式数据 + /// + /// + /// 对象 + /// 字符格式的JSON数据 + public static string? GetXML(object obj) + { + try + { + XmlSerializer xs = new XmlSerializer(typeof(T)); + + using (TextWriter tw = new StringWriter()) + { + xs.Serialize(tw, obj); + return tw.ToString(); + } + } + catch (Exception) + { + return string.Empty; + } + } + + /// + /// Xml格式字符转换为T类型的对象 + /// + /// + /// + /// + public static T ParseFormByXml(string xml,string rootName="root") + { + XmlSerializer serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootName)); + StringReader reader = new StringReader(xml); + + T res = (T)serializer.Deserialize(reader)!; + reader.Close(); + reader.Dispose(); + return res; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/GobalLogModel.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/GobalLogModel.cs new file mode 100644 index 00000000..b93b8a76 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/GobalLogModel.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Model +{ +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/ServiceLocatorModel.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/ServiceLocatorModel.cs new file mode 100644 index 00000000..297b7e6d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Model/ServiceLocatorModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Model +{ + public static class ServiceLocatorModel + { + public static IServiceProvider Instance { get; set; } + } +} + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleAssembly.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleAssembly.cs new file mode 100644 index 00000000..080564d2 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleAssembly.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Module +{ + public class ModuleAssembly + { + private static HashSet assemblies=new HashSet(); + public static Assembly[] Assemblies { get=> assemblies.ToArray();} + + public static void Add(Assembly assembly) + { + assemblies.Add(assembly); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleManager.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleManager.cs new file mode 100644 index 00000000..22e4b15e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/ModuleManager.cs @@ -0,0 +1,119 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; + +namespace Yi.Framework.Core.Module +{ + + internal class ModuleManager + { + /// + /// 全部程序集 + /// + private List ResultType = new List(); + + /// + /// 开始程序集 + /// + private Type StartType; + public ModuleManager(Type startType) + { + StartType = startType; + } + + /// + /// 执行 + /// + /// + public List Invoker() + { + StartBFSNodes(StartType); + ResultType= ResultType.Distinct().ToList(); + var result = StartTopologicalSortNodes().Reverse().ToList(); + + Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(ModuleManager).Assembly).GetCurrentClassLogger(); + foreach (var r in result) + { + //添加全局模块程序集 + ModuleAssembly.Add(r.Assembly); + _logger.Info($"意框架正在加载模块:{r.Name}"); + } + return result; + } + + + private Type[] StartTopologicalSortNodes() + { + List> topologicalSortNodes = new List>(); + + + //添加注册到节点 + foreach (var res in ResultType) + { + var typeNode = new TopologicalSortNode(res); + topologicalSortNodes.Add(typeNode); + } + + Dictionary> nodeDic = topologicalSortNodes.ToDictionary(x => x.Data); + + + //各个节点互相添加依赖 + foreach (var node in topologicalSortNodes) + { + GetDependsOnType(node.Data)?.ToList().ForEach(x => node.AddDependent(nodeDic[x])); + } + + + + return TopologicalSortNode.TopologicalSort(topologicalSortNodes).Select(x => x.Data).ToArray(); + } + + /// + /// BFS获取全部程序集 + /// + /// + private void StartBFSNodes(Type node) + { + ResultType.Add(node); + var nodes = GetDependsOnType(node); + if (nodes is not null && nodes.Count() != 0) + { + foreach (var n in nodes) + { + StartBFSNodes(n); + } + } + } + + + /// + /// 获取模块 需依赖的模块 + /// + /// + /// + private Type[]? GetDependsOnType(Type type) + { + var dependsOnbuild = type.GetCustomAttributes(typeof(DependsOnAttribute), false).FirstOrDefault() as DependsOnAttribute; + if (dependsOnbuild is null) + { + return new Type[0]; + } + return dependsOnbuild.GetDependedTypes(); + } + + + public List ToAssemblyList() + { + return ResultType.Select(a => a.Assembly).ToList(); + } + public Assembly[] ToAssemblyArray(List types) + { + return types.Select(a => a.Assembly).ToArray(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/TopologicalSortNode.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/TopologicalSortNode.cs new file mode 100644 index 00000000..630e0382 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Module/TopologicalSortNode.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Core.Module +{ + public class TopologicalSortNode + { + public T Data { get; private set; } + public List> Dependents { get; private set; } + public int IncomingEdges { get; private set; } + public TopologicalSortNode(T data) + { + Data = data; + Dependents = new List>(); + IncomingEdges = 0; + } + public void AddDependent(TopologicalSortNode dependent) + { + Dependents.Add(dependent); + dependent.IncomingEdges++; + } + + + public static List> TopologicalSort(List> graph) + { + List> result = new List>(); + Queue> queue = new Queue>(); + // 将所有入度为 0 的节点加入队列 + foreach (TopologicalSortNode node in graph) + { + if (node.IncomingEdges == 0) + { + queue.Enqueue(node); + } + } + // 依次将入度为 0 的节点出队,并将它的依赖节点的入度减 1 + while (queue.Count > 0) + { + TopologicalSortNode node = queue.Dequeue(); + result.Add(node); + foreach (TopologicalSortNode dependent in node.Dependents) + { + dependent.IncomingEdges--; + if (dependent.IncomingEdges == 0) + { + queue.Enqueue(dependent); + } + } + } + // 如果存在入度不为 0 的节点,则说明图中存在环 + foreach (TopologicalSortNode node in graph) + { + if (node.IncomingEdges != 0) + { + throw new ArgumentException("模块之间存在互相依赖!"); + } + } + return result; + } + + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Utils/DisposeAction.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Utils/DisposeAction.cs new file mode 100644 index 00000000..e1cff0ac --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Utils/DisposeAction.cs @@ -0,0 +1,27 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Yi.Framework.Core.Utils +{ + public class DisposeAction : IDisposable + { + private readonly Action _action; + + private readonly T _parameter; + + /// + /// Creates a new object. + /// + /// Action to be executed when this object is disposed. + /// The parameter of the action. + public DisposeAction(Action action, T parameter) + { + _action = action; + _parameter = parameter; + } + + public void Dispose() + { + _action(_parameter); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Yi.Framework.Core.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Yi.Framework.Core.csproj new file mode 100644 index 00000000..b83ece5f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/Yi.Framework.Core.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs new file mode 100644 index 00000000..34425609 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Core/YiFrameworkCoreModule.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using NLog.Extensions.Logging; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Configuration; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Extensions; +using Yi.Framework.Core.Model; + +namespace Yi.Framework.Core +{ + public class YiFrameworkCoreModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + //服务定位实例赋值 + ServiceLocatorModel.Instance = app.ApplicationServices; + + //全局错误,需要靠前,放在此处无效 + //app.UseErrorHandlingServer(); + + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //添加全局配置类 + services.AddSingleton(new Appsettings(context.Configuration)); + //全盘扫描,自动依赖注入 + services.AddAutoIocServer(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/AuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/AuditedObject.cs new file mode 100644 index 00000000..9867b612 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/AuditedObject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public class AuditedObject : IAuditedObject + { + public DateTime CreationTime { get; set; }= DateTime.Now; + + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IAuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IAuditedObject.cs new file mode 100644 index 00000000..68a63853 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IAuditedObject.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface IAuditedObject : ICreationAuditedObject, IModificationAuditedObject + { + } + + public interface IAuditedObject : IAuditedObject, ICreationAuditedObject, IModificationAuditedObject + { + + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/ICreationAuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/ICreationAuditedObject.cs new file mode 100644 index 00000000..e136c6e4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/ICreationAuditedObject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface ICreationAuditedObject : IHasCreationTime, IMayHaveCreator + { + + } + + public interface ICreationAuditedObject : ICreationAuditedObject, IMayHaveCreator + { + + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IDeletionAuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IDeletionAuditedObject.cs new file mode 100644 index 00000000..34d536e0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IDeletionAuditedObject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface IDeletionAuditedObject : IHasDeletionTime + { + long? DeleterId { get; } + } + + public interface IDeletionAuditedObject : IDeletionAuditedObject + { + + TUser Deleter { get; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IFullAuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IFullAuditedObject.cs new file mode 100644 index 00000000..cc081c7d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IFullAuditedObject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface IFullAuditedObject : IAuditedObject, IDeletionAuditedObject + { + + } + + public interface IFullAuditedObject : IAuditedObject, IFullAuditedObject, IDeletionAuditedObject + { + + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasCreationTime.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasCreationTime.cs new file mode 100644 index 00000000..6291376e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasCreationTime.cs @@ -0,0 +1,10 @@ +using System; + +namespace Yi.Framework.Data.Auditing; + + +public interface IHasCreationTime +{ + + DateTime CreationTime { get; set; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasDeletionTime.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasDeletionTime.cs new file mode 100644 index 00000000..5888993d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasDeletionTime.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; + +namespace Yi.Framework.Data.Auditing +{ + public interface IHasDeletionTime : ISoftDelete + { + DateTime? DeletionTime { get; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasEntityVersion.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasEntityVersion.cs new file mode 100644 index 00000000..c35b983a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasEntityVersion.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface IHasEntityVersion + { + int EntityVersion { get; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasModificationTime.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasModificationTime.cs new file mode 100644 index 00000000..a61cbae7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IHasModificationTime.cs @@ -0,0 +1,9 @@ + +namespace Yi.Framework.Data.Auditing; + + +public interface IHasModificationTime +{ + + DateTime? LastModificationTime { get; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMayHaveCreator.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMayHaveCreator.cs new file mode 100644 index 00000000..c5ee3eef --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMayHaveCreator.cs @@ -0,0 +1,13 @@ +using System; + +namespace Yi.Framework.Data.Auditing; + +public interface IMayHaveCreator +{ + TCreator Creator { get; } +} + +public interface IMayHaveCreator +{ + long? CreatorId { get; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IModificationAuditedObject.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IModificationAuditedObject.cs new file mode 100644 index 00000000..c70a2631 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IModificationAuditedObject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Auditing +{ + public interface IModificationAuditedObject : IHasModificationTime + { + long? LastModifierId { get; } + } + + public interface IModificationAuditedObject : IModificationAuditedObject + { + TUser LastModifier { get; } + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMustHaveCreator.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMustHaveCreator.cs new file mode 100644 index 00000000..c2b316c7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Auditing/IMustHaveCreator.cs @@ -0,0 +1,13 @@ +using System; + +namespace Yi.Framework.Data.Auditing; + +public interface IMustHaveCreator : IMustHaveCreator +{ + TCreator Creator { get; } +} + +public interface IMustHaveCreator +{ + long CreatorId { get; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/AbstractDataSeed.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/AbstractDataSeed.cs new file mode 100644 index 00000000..ab046d33 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/AbstractDataSeed.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.Framework.Data.DataSeeds +{ + public abstract class AbstractDataSeed : IDataSeed + { + protected readonly IRepository _repository; + public AbstractDataSeed(IRepository repository) + { + _repository = repository; + } + + /// + /// 简单种子数据,重写该方法即可 + /// + /// + public abstract List GetSeedData(); + + + /// + /// 复杂数据,重写该方法即可 + /// + /// + public async virtual Task DataHandlerAsync() + { + return await _repository.InsertRangeAsync(GetSeedData()); + } + + /// + /// 这个用来处理判断是否数据库还存在数据 + /// + /// + public virtual async Task IsInvoker() + { + var p = await _repository.IsAnyAsync(x=>true); + var p2 = await _repository.CountAsync(x => true); + if (await _repository.CountAsync(u => true) > 0) + { + return false; + } + return true; + } + + /// + /// 完全自定义数据,处理该方法即可 + /// + /// + public async virtual Task InvokerAsync() + { + bool res = true; + if (await IsInvoker()) + { + return await DataHandlerAsync(); + } + return res; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/IDataSeed.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/IDataSeed.cs new file mode 100644 index 00000000..22dc95ff --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/DataSeeds/IDataSeed.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.DataSeeds +{ + public interface IDataSeed + { + Task InvokerAsync(); + } + + public interface IDataSeed: IDataSeed + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IMultiTenant.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IMultiTenant.cs new file mode 100644 index 00000000..e8bc3266 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IMultiTenant.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Entities +{ + public interface IMultiTenant + { + public Guid TenantId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IOrderNum.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IOrderNum.cs new file mode 100644 index 00000000..04ab97c4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IOrderNum.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Entities +{ + public interface IOrderNum + { + int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/ISoftDelete.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/ISoftDelete.cs new file mode 100644 index 00000000..cbbc5277 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/ISoftDelete.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Entities +{ + public interface ISoftDelete + { + public bool IsDeleted { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IState.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IState.cs new file mode 100644 index 00000000..fee2f365 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Entities/IState.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Entities +{ + public interface IState + { + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataFiterExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataFiterExtensions.cs new file mode 100644 index 00000000..ba4a8788 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataFiterExtensions.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Data.Filters; + +namespace Yi.Framework.Data.Extensions +{ + public static class DataFilterExtensions + { + public static IApplicationBuilder UseDataFiterServer(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } + + public class DataFilterMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + public DataFilterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) + { + this._next = next; + this._logger = loggerFactory.CreateLogger(); + } + public async Task InvokeAsync(HttpContext context, IDataFilter dataFilter) + { + //添加默认的过滤器 + dataFilter.AddFilter(u => u.IsDeleted == false); + //dataFilter.AddFilter(u => u.TenantId == Guid.Empty); + await _next(context); + + } + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataSeedExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataSeedExtensions.cs new file mode 100644 index 00000000..35a9a7db --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Extensions/DataSeedExtensions.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Configuration; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Uow; + +namespace Yi.Framework.Data.Extensions +{ + public static class DataSeedExtensions + { + public static IApplicationBuilder UseDataSeedServer(this IApplicationBuilder builder) + { + if (!Appsettings.appBool("EnabledDataSeed")) + { + return builder; + } + + var dataSeeds = builder.ApplicationServices.GetServices(); + var iUnitOfWorkManager = builder.ApplicationServices.GetRequiredService(); + if (dataSeeds is not null) + { + using (var uow = iUnitOfWorkManager.CreateContext()) + { + foreach (var seed in dataSeeds) + { + seed.InvokerAsync(); + } + var res = uow.Commit(); + + if (!res) + { + throw new ApplicationException("种子数据初始化异常"); + } + } + } + return builder.UseMiddleware(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/DefaultDataFilter.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/DefaultDataFilter.cs new file mode 100644 index 00000000..9731b2d9 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/DefaultDataFilter.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Filters +{ + public class DefaultDataFilter : IDataFilter + { + private readonly IServiceProvider _serviceProvider; + + public DefaultDataFilter(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + + + public IDisposable Disable() where TFilter : class + { + return this; + } + + public IDisposable Enable() where TFilter : class + { + return this; + } + + public bool IsEnabled() where TFilter : class + { + return false; + } + + public void RemoveFilter() where TFilter : class + { + } + public void RemoveAndBackup() where TFilter : class + { + } + + public void AddFilter(Expression> expression) where TFilter : class + { + } + + public void Dispose() + { + + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/IDataFilter.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/IDataFilter.cs new file mode 100644 index 00000000..94834627 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Filters/IDataFilter.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Filters +{ + public interface IDataFilter:IDisposable + { + IDisposable Enable() where TFilter :class; + + IDisposable Disable() where TFilter : class; + + bool IsEnabled() where TFilter : class; + + void AddFilter(Expression> expression) where TFilter : class; + + void RemoveFilter() where TFilter : class; + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/DateTimeJsonConverter.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/DateTimeJsonConverter.cs new file mode 100644 index 00000000..9935896a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/DateTimeJsonConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Yi.Framework.Data.Json +{ + public class DateTimeJsonConverter : JsonConverter + { + private readonly string Format; + public DateTimeJsonConverter(string format) + { + Format = format; + } + public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options) + { + writer.WriteStringValue(date.ToString(Format)); + } + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.ParseExact(reader.GetString(), Format, null); + } + } + + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/LongToStringConverter .cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/LongToStringConverter .cs new file mode 100644 index 00000000..78283b15 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Json/LongToStringConverter .cs @@ -0,0 +1,45 @@ +using System; +using System.Buffers; +using System.Buffers.Text; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using SqlSugar; + +namespace Yi.Framework.Data.Json +{ + /// + /// 长整形转字符串 + /// + public class LongToStringConverter : JsonConverter + { + public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + ReadOnlySpan span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; + if (Utf8Parser.TryParse(span, out long number, out int bytesConsumed) && span.Length == bytesConsumed) + { + return number; + } + + if (long.TryParse(reader.GetString(), out number)) + { + return number; + } + return 0; + } + + return reader.GetInt64(); + } + + public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString()); + } + } +} + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Yi.Framework.Data.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Yi.Framework.Data.csproj new file mode 100644 index 00000000..a711a8d9 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/Yi.Framework.Data.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Data/YiFrameworkDataModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/YiFrameworkDataModule.cs new file mode 100644 index 00000000..949c1502 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Data/YiFrameworkDataModule.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data.Entities; +using Yi.Framework.Data.Extensions; +using Yi.Framework.Data.Filters; +using Yi.Framework.Ddd; +using Yi.Framework.Uow; + +namespace Yi.Framework.Data +{ + [DependsOn( + typeof(YiFrameworkDddModule), + typeof(YiFrameworkUowModule)) ] + public class YiFrameworkDataModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + + //使用了过滤器 + app.UseDataFiterServer(); + + //添加种子数据 + app.UseDataSeedServer(); + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //添加默认没有真正实现的 + services.TryAddTransient(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IEntityDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IEntityDto.cs new file mode 100644 index 00000000..5aeed368 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IEntityDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public interface IEntityDto + { + } + + public interface IEntityDto : IEntityDto + { + TKey Id { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IHasTotalCount.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IHasTotalCount.cs new file mode 100644 index 00000000..778fae5a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IHasTotalCount.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public interface IHasTotalCount + { + long Total { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IListResult.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IListResult.cs new file mode 100644 index 00000000..e39bc0d3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IListResult.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public interface IListResult + { + IReadOnlyList Items { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAllResultRequestDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAllResultRequestDto.cs new file mode 100644 index 00000000..72f7914e --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAllResultRequestDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Framework.Ddd.Dtos.Abstract +{ + public interface IPagedAllResultRequestDto: IPageTimeResultRequestDto, IPagedAndSortedResultRequestDto + { + DateTime? StartTime { get; set; } + DateTime? EndTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAndSortedResultRequestDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAndSortedResultRequestDto.cs new file mode 100644 index 00000000..8f55de87 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedAndSortedResultRequestDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Ddd.Dtos +{ + public interface IPagedAndSortedResultRequestDto + { + int PageNum { get; set; } + int PageSize { get; set; } + string? SortBy { get; set; } + + OrderByEnum SortType { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedResult.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedResult.cs new file mode 100644 index 00000000..fe9bb5c0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/Abstract/IPagedResult.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public interface IPagedResult : IListResult, IHasTotalCount + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/EntityDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/EntityDto.cs new file mode 100644 index 00000000..a0dc20c6 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/EntityDto.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + [Serializable] + public abstract class EntityDto : EntityDto, IEntityDto, IEntityDto + { + // + // 摘要: + // Id of the entity. + public TKey Id { get; set; } + + public override string ToString() + { + return $"[DTO: {GetType().Name}] Id = {Id}"; + } + } + + [Serializable] + public abstract class EntityDto : IEntityDto + { + public override string ToString() + { + return "[DTO: " + GetType().Name + "]"; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/ListResultDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/ListResultDto.cs new file mode 100644 index 00000000..630226d1 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/ListResultDto.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + [Serializable] + public class ListResultDto : IListResult + { + public IReadOnlyList Items + { + get { return _items ?? (_items = new List()); } + set { _items = value; } + } + private IReadOnlyList _items; + + public ListResultDto() + { + + } + + public ListResultDto(IReadOnlyList items) + { + Items = items; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAllResultRequestDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAllResultRequestDto.cs new file mode 100644 index 00000000..0c7a918b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAllResultRequestDto.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos.Abstract; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Framework.Ddd.Dtos +{ + public class PagedAllResultRequestDto : PagedAndSortedResultRequestDto, IPagedAllResultRequestDto, IPagedAndSortedResultRequestDto, IPageTimeResultRequestDto + { + /// + /// 查询开始时间条件 + /// + public DateTime? StartTime { get; set; } + + /// + /// 查询结束时间条件 + /// + public DateTime? EndTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAndSortedResultRequestDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAndSortedResultRequestDto.cs new file mode 100644 index 00000000..d5d114b0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedAndSortedResultRequestDto.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; + +namespace Yi.Framework.Ddd.Dtos +{ + public class PagedAndSortedResultRequestDto : IPagedAndSortedResultRequestDto + { + /// + /// 查询当前页条件 + /// + public int PageNum { get; set; } = 1; + + /// + /// 查询分页大小条件 + /// + public int PageSize { get; set; } = int.MaxValue; + + /// + /// 查询排序字段条件 + /// + public string? SortBy { get; set; } + + /// + /// 查询排序类别条件 + /// + public OrderByEnum SortType { get; set; } = OrderByEnum.Desc; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedDto.cs new file mode 100644 index 00000000..87038530 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedDto.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public class PagedDto + { + public PagedDto(long totalCount, List items) + { + Total = totalCount; + Items = items; + } + public long Total { get; set; } + + public List Items{ get; set; } +} +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedResultDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedResultDto.cs new file mode 100644 index 00000000..81b125aa --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Dtos/PagedResultDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Dtos +{ + public class PagedResultDto:ListResultDto, IPagedResult + { + public long Total { get; set; } + + public PagedResultDto() + { + + } + + public PagedResultDto(long totalCount, IReadOnlyList items) + : base(items) + { + Total = totalCount; + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/AggregateRoot.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/AggregateRoot.cs new file mode 100644 index 00000000..d009e529 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/AggregateRoot.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Entities +{ + public class AggregateRoot : IEntity, IAggregateRoot + { + } + public class AggregateRoot : Entity ,IEntity + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/Entity.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/Entity.cs new file mode 100644 index 00000000..5a05f2dd --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/Entity.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Entities +{ + [Serializable] + public abstract class Entity : IEntity + { + protected Entity() + { + } + + public override string ToString() + { + return "[ENTITY: " + GetType().Name + "] Keys = " + GetKeys(); + } + + public abstract object[] GetKeys(); + + //实体比较简化 + //public bool EntityEquals(IEntity other) + //{ + // return this.GetKeys().Equals(other.GetKeys()); + //} + + } + + [Serializable] + public abstract class Entity : Entity, IEntity, IEntity + { + public virtual TKey Id { get; set; } + + protected Entity() + { + } + + protected Entity(TKey id) + { + Id = id; + } + + public override object[] GetKeys() + { + return new object[1] { Id }; + } + + public override string ToString() + { + return $"[ENTITY: {GetType().Name}] Id = {Id}"; + } + + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IAggregateRoot.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IAggregateRoot.cs new file mode 100644 index 00000000..6f0b64a3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IAggregateRoot.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.DataProtection.KeyManagement; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Entities +{ + public interface IAggregateRoot: IEntity + { + } + public interface IAggregateRoot : IEntity + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IEntity.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IEntity.cs new file mode 100644 index 00000000..cd9753f4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Entities/IEntity.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Entities +{ + public interface IEntity + { + // + // 摘要: + // Returns an array of ordered keys for this entity. + + } + public interface IEntity : IEntity + { + // + // 摘要: + // Unique identifier for this entity. + TKey Id { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Repositories/IRepository.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Repositories/IRepository.cs new file mode 100644 index 00000000..b15dea78 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Repositories/IRepository.cs @@ -0,0 +1,63 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.Ddd.Repositories +{ + public interface IRepository + { + /// + /// 注释一下,严格意义这里应该protected,但是我认为 简易程度 与 耦合程度 中是需要进行衡量的 + /// + ISugarQueryable _DbQueryable { get; } + //单查 + Task GetByIdAsync(dynamic id); + Task GetSingleAsync(Expression> whereExpression); + Task GetFirstAsync(Expression> whereExpression); + Task IsAnyAsync(Expression> whereExpression); + Task CountAsync(Expression> whereExpression); + + //多查 + Task> GetListAsync(); + Task> GetListAsync(Expression> whereExpression); + + //分页查 + Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize); + Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, Expression>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc); + Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc); + Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page); + Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page, Expression>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc); + Task> GetPageListAsync(Expression> whereExpression, IPagedAndSortedResultRequestDto page, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc); + + //插入 + Task InsertAsync(T insertObj); + Task InsertOrUpdateAsync(T data); + Task InsertOrUpdateAsync(List datas); + Task InsertReturnIdentityAsync(T insertObj); + Task InsertReturnBigIdentityAsync(T insertObj); + Task InsertReturnSnowflakeIdAsync(T insertObj); + Task InsertReturnEntityAsync(T insertObj); + Task InsertRangeAsync(List insertObjs); + + //更新 + Task UpdateAsync(T updateObj); + Task UpdateRangeAsync(List updateObjs); + Task UpdateAsync(Expression> columns, Expression> whereExpression); + Task UpdateIgnoreNullAsync(T updateObj); + + //删除 + Task DeleteAsync(T deleteObj); + Task DeleteAsync(List deleteObjs); + Task DeleteAsync(Expression> whereExpression); + Task DeleteByIdAsync(dynamic id); + Task DeleteByIdsAsync(dynamic[] ids); + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IApplicationService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IApplicationService.cs new file mode 100644 index 00000000..ec81ea5d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IApplicationService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface IApplicationService + { + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateAppService.cs new file mode 100644 index 00000000..04b443e7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateAppService.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface ICreateAppService + : ICreateAppService + { + + } + + public interface ICreateAppService + : IApplicationService + { + Task CreateAsync(TCreateInput input); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateUpdateAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateUpdateAppService.cs new file mode 100644 index 00000000..2996249b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICreateUpdateAppService.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface ICreateUpdateAppService + : ICreateUpdateAppService + { + + } + + public interface ICreateUpdateAppService + : ICreateUpdateAppService + { + + } + + public interface ICreateUpdateAppService + : ICreateAppService, + IUpdateAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICrudAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICrudAppService.cs new file mode 100644 index 00000000..2c87e055 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/ICrudAppService.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + + public interface ICrudAppService + : ICrudAppService + { + + } + + public interface ICrudAppService + : ICrudAppService + { + + } + + public interface ICrudAppService + : ICrudAppService + { + + } + + public interface ICrudAppService + : ICrudAppService + { + + } + + public interface ICrudAppService + : IReadOnlyAppService, + ICreateUpdateAppService, + IDeleteAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IDeleteAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IDeleteAppService.cs new file mode 100644 index 00000000..344af80f --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IDeleteAppService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface IDeleteAppService : IApplicationService + { + Task DeleteAsync(string id); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IPageTimeResultRequestDto.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IPageTimeResultRequestDto.cs new file mode 100644 index 00000000..cae8b825 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IPageTimeResultRequestDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface IPageTimeResultRequestDto: IPagedAndSortedResultRequestDto + { + DateTime? StartTime { get; set; } + DateTime? EndTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IReadOnlyAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IReadOnlyAppService.cs new file mode 100644 index 00000000..911b8ee1 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IReadOnlyAppService.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface IReadOnlyAppService + : IReadOnlyAppService + { + + } + + public interface IReadOnlyAppService + : IReadOnlyAppService + { + + } + + public interface IReadOnlyAppService + : IApplicationService + { + Task GetAsync(TKey id); + + Task> GetListAsync(TGetListInput input); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IUpdateAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IUpdateAppService.cs new file mode 100644 index 00000000..16b75cb8 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/Abstract/IUpdateAppService.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Ddd.Services.Abstract +{ + public interface IUpdateAppService + : IUpdateAppService + { + + } + + public interface IUpdateAppService + : IApplicationService + { + Task UpdateAsync(TKey id, TUpdateInput input); + } + +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ApplicationService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ApplicationService.cs new file mode 100644 index 00000000..1fe25024 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ApplicationService.cs @@ -0,0 +1,12 @@ +using MapsterMapper; +using Microsoft.Extensions.DependencyInjection; + +using Yi.Framework.Core.Model; + +namespace Yi.Framework.Ddd.Services +{ + public abstract class ApplicationService + { + public IMapper _mapper { get => ServiceLocatorModel.Instance.GetRequiredService(); } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/CrudAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/CrudAppService.cs new file mode 100644 index 00000000..007fe9ab --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/CrudAppService.cs @@ -0,0 +1,175 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Helper; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Entities; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Framework.Ddd.Services +{ + + public abstract class CrudAppService + : CrudAppService + where TEntity : class, IEntity + where TEntityDto : IEntityDto + { + } + + public abstract class CrudAppService + : CrudAppService + where TEntity : class, IEntity + where TEntityDto : IEntityDto + { + } + + public abstract class CrudAppService + : CrudAppService + where TEntity : class, IEntity + where TEntityDto : IEntityDto + { + } + + + + + public abstract class CrudAppService + : CrudAppService + where TEntity : class, IEntity + where TEntityDto : IEntityDto + { + protected override Task MapToGetListOutputDtoAsync(TEntity entity) + { + return MapToGetOutputDtoAsync(entity); + } + + } + + public abstract class CrudAppService + : ReadOnlyAppService, + ICrudAppService + where TEntity : class, IEntity + where TGetOutputDto : IEntityDto + where TGetListOutputDto : IEntityDto + + { + protected virtual Task MapToEntityAsync(TGetListInput getListinput) + { + return Task.FromResult(_mapper.Map(getListinput)); + } + + + protected virtual Task MapToEntityAsync(TCreateInput createInput) + { + var entity = _mapper.Map(createInput); + + //这里判断实体的T,给id赋值 + + //雪花id + if (entity is IEntity entityForlongId) + { + if (entityForlongId.Id is default(long)) + { + //使用反射,暂时先使用sqlsuga的雪花id提供 + //ps: linshi + ReflexHelper.SetModelValue(nameof(IEntity.Id), SnowflakeHelper.NextId, entity); + } + } + if (entity is IEntity entityForGuidId) + { + if (entityForGuidId.Id == Guid.Empty) + { + ReflexHelper.SetModelValue(nameof(IEntity.Id), new Guid(), entity); + } + } + + return Task.FromResult(entity); + } + protected virtual Task MapToEntityAsync(TUpdateInput updateInput, TEntity entity) + { + _mapper.Map(updateInput, entity); + return Task.CompletedTask; + } + + protected virtual Task MapToEntityAsync(TUpdateInput updateInput) + { + var entity = _mapper.Map(updateInput); + return Task.FromResult(entity); + } + + /// + /// 增 + /// + /// + /// + public virtual async Task CreateAsync(TCreateInput input) + { + var entity = await MapToEntityAsync(input); + + //这里还可以设置租户 + await _repository.InsertAsync(entity); + + return await MapToGetOutputDtoAsync(entity); + } + + /// + /// 单、多删 + /// + /// + /// + /// + public virtual async Task DeleteAsync(string id) + { + if (id is null) + { + throw new ArgumentNullException(nameof(id)); + } + var idsValue = id.Split(','); + if (idsValue is null || idsValue.Length == 0) + { + throw new ArgumentNullException(nameof(id)); + } + return await _repository.DeleteByIdsAsync(idsValue.Select(x => (object)x!).ToArray()); + } + + ///// + ///// 删 + ///// + ///// + ///// + ///// + //public async Task DeleteAsync(TKey id) + //{ + // if (id is null) + // { + // throw new ArgumentNullException(nameof(id)); + // } + // return await _repository.DeleteByIdAsync(id); + //} + + /// + /// 改 + /// + /// + /// + /// + /// + public virtual async Task UpdateAsync(TKey id, TUpdateInput input) + { + if (id is null) + { + throw new ArgumentNullException(nameof(id)); + } + + var entity = await _repository.GetByIdAsync(id); + await MapToEntityAsync(input, entity); + await _repository.UpdateAsync(entity); + + return await MapToGetOutputDtoAsync(entity); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ReadOnlyAppService.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ReadOnlyAppService.cs new file mode 100644 index 00000000..5fac060a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Services/ReadOnlyAppService.cs @@ -0,0 +1,135 @@ +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Helper; +using Yi.Framework.Core.Model; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Entities; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Framework.Ddd.Services +{ + + public abstract class ReadOnlyAppService + : ReadOnlyAppService + where TEntity : class, IEntity + where TEntityDto : IEntityDto + { + } + + public abstract class ReadOnlyAppService +: ReadOnlyAppService +where TEntity : class, IEntity +where TEntityDto : IEntityDto + { + } + + + public abstract class ReadOnlyAppService : ApplicationService, + IReadOnlyAppService + where TEntity : class, IEntity + { + /// + /// 先暂时用服务定位的方式,之后将更改为属性注入 + /// + protected IRepository _repository { get => ServiceLocatorModel.Instance.GetRequiredService>(); } + + protected ISugarQueryable _DbQueryable => _repository._DbQueryable; + + //Mapper + protected virtual Task MapToGetOutputDtoAsync(TEntity entity) + { + return Task.FromResult(_mapper.Map(entity)); + } + protected virtual Task> MapToGetListOutputDtosAsync(List entities) + { + var dtos = _mapper.Map>(entities); + + return Task.FromResult(dtos); + } + protected virtual Task MapToGetListOutputDtoAsync(TEntity entity) + { + var dto = _mapper.Map(entity); + return Task.FromResult(dto); + } + + /// + /// 单查 + /// + /// + /// + /// + public virtual async Task GetAsync(TKey id) + { + if (id is null) + { + throw new ArgumentNullException(nameof(id)); + } + + var entity = await _repository.GetByIdAsync(id); + + return await MapToGetOutputDtoAsync(entity); + } + + /// + /// 多查 + /// + /// + /// + public virtual async Task> GetListAsync(TGetListInput input) + { + var totalCount = -1; + + var entities = new List(); + var entityDtos = new List(); + + bool isPageList = true; + + //if (totalCount > 0) + //{ + + //这里还可以追加如果是审计日志,继续拼接条件即可 + if (input is IPageTimeResultRequestDto timeInput) + { + if (timeInput.StartTime is not null) + { + timeInput.EndTime = timeInput.EndTime ?? DateTime.Now; + } + } + + + + + if (input is IPagedAndSortedResultRequestDto sortInput) + { + entities = await _repository.GetPageListAsync(_ => true, sortInput,sortInput.SortBy, sortInput.SortType); + } + + + else + { + isPageList = false; + entities = await _repository.GetListAsync(); + } + entityDtos = await MapToGetListOutputDtosAsync(entities); + //} + + //如果是分页查询,还需要统计数量 + if (isPageList) + { + totalCount = await _repository.CountAsync(_ => true); + } + return new PagedResultDto( + totalCount, + entityDtos + ); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi - Backup.Framework.Ddd.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi - Backup.Framework.Ddd.csproj new file mode 100644 index 00000000..761ed5d1 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi - Backup.Framework.Ddd.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + True + ./SwaggerDoc.xml + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi.Framework.Ddd.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi.Framework.Ddd.csproj new file mode 100644 index 00000000..d16d97c0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/Yi.Framework.Ddd.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + True + ./YiFrameworkSwaggerDoc.xml + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkDddModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkDddModule.cs new file mode 100644 index 00000000..a9fee9f5 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkDddModule.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.AutoMapper; + +namespace Yi.Framework.Ddd +{ + [DependsOn( + typeof(YiFrameworkCoreMapsterModule) + + )] + public class YiFrameworkDddModule:IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkSwaggerDoc.xml b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkSwaggerDoc.xml new file mode 100644 index 00000000..17d6484d --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Ddd/YiFrameworkSwaggerDoc.xml @@ -0,0 +1,87 @@ + + + + Yi.Framework.Ddd + + + + + 查询开始时间条件 + + + + + 查询结束时间条件 + + + + + 查询当前页条件 + + + + + 查询分页大小条件 + + + + + 查询排序字段条件 + + + + + 查询排序类别条件 + + + + + 注释一下,严格意义这里应该protected,但是我认为 简易程度 与 耦合程度 中是需要进行衡量的 + + + + + 增 + + + + + + + 单、多删 + + + + + + + + 改 + + + + + + + + + 先暂时用服务定位的方式,之后将更改为属性注入 + + + + + 单查 + + + + + + + + 多查 + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/BasicTenantInfo.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/BasicTenantInfo.cs new file mode 100644 index 00000000..7b564ea3 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/BasicTenantInfo.cs @@ -0,0 +1,24 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户信息 +/// +public class BasicTenantInfo +{ + /// + /// 租户ID + /// + public Guid? TenantId { get; } + + /// + /// 租户ID 名称 + /// + public string Name { get; } + + /// + public BasicTenantInfo(Guid? tenantId, string? name = null) + { + TenantId = tenantId; + Name = name ?? string.Empty; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/CurrentTenant.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/CurrentTenant.cs new file mode 100644 index 00000000..0bbf4825 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/CurrentTenant.cs @@ -0,0 +1,60 @@ +using Yi.Framework.Core.Utils; + +namespace Yi.Framework.MultiTenancy; + +/// +/// 当前租户实现 +/// +public class CurrentTenant : ICurrentTenant +{ + private readonly ICurrentTenantAccessor _currentTenantAccessor; + + /// + public CurrentTenant(ICurrentTenantAccessor currentTenantAccessor) + { + _currentTenantAccessor = currentTenantAccessor; + } + + /// + /// 是否有效 + /// + public virtual bool IsAvailable => Id != Guid.Empty; + + /// + /// 租户ID + /// + public virtual Guid Id => _currentTenantAccessor.Current?.TenantId ?? Guid.Empty; + + /// + /// 租户名称 + /// + public string? Name => _currentTenantAccessor.Current?.Name; + + /// + /// 替换租户 + /// + /// + /// + /// + public IDisposable Change(Guid? id, string? name = null) + { + return SetCurrent(id, name); + } + + /// + /// 设置当前租户 + /// + /// + private IDisposable SetCurrent(Guid? tenantId, string? name = null) + { + BasicTenantInfo? parentScope = _currentTenantAccessor.Current; + _currentTenantAccessor.Current = new BasicTenantInfo(tenantId, name); + + return new DisposeAction>(static ((ICurrentTenantAccessor, BasicTenantInfo) state) => + { + (ICurrentTenantAccessor currentTenantAccessor, BasicTenantInfo parentScope) = state; + currentTenantAccessor.Current = parentScope; + }, + (_currentTenantAccessor, parentScope)); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/DefaultCurrentTenantAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/DefaultCurrentTenantAccessor.cs new file mode 100644 index 00000000..83ec524a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/DefaultCurrentTenantAccessor.cs @@ -0,0 +1,28 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 默认租户访问器实现 +/// +public class DefaultCurrentTenantAccessor : ICurrentTenantAccessor +{ + private ITenantResolver _tenantResolver; + + /// + public DefaultCurrentTenantAccessor(ITenantResolver tenantResolver) + { + _tenantResolver = tenantResolver; + TenantResolveResult? tenantResolveResult = _tenantResolver.ResolveTenantIdOrNameAsync().Result; + string? tenantIdStr = tenantResolveResult.TenantIdOrName; + + Current = Guid.TryParse(tenantIdStr, out Guid tehnantId) + ? new BasicTenantInfo(tehnantId) + : new BasicTenantInfo(Guid.Empty); + } + + /// + /// 当前租户信息 + /// + public BasicTenantInfo Current { get; set; } + +} + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Extensions/MultiTenancyExtensions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Extensions/MultiTenancyExtensions.cs new file mode 100644 index 00000000..1d93bcf8 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Extensions/MultiTenancyExtensions.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.DependencyInjection; +using Yi.Framework.MultiTenancy.ResolveContributor; + +namespace Yi.Framework.MultiTenancy.Extensions; + +/// +/// 租户注入扩展方法 +/// +public static class MultiTenancyExtensions +{ + /// + /// 注入 租户 + /// + /// + /// + public static IServiceCollection AddCurrentTenant(this IServiceCollection services) + { + services.Configure(option => + { + //添加租户解析器,默认添加从当前用户中获取 + + //添加从httpheader,解析TenantId配置的租户id + option.TenantResolvers.Add(new HttpHeaderTenantResolveContributor()); + + //添加配置租户解析器,解析TenantId配置的租户id + option.TenantResolvers.Add(new ConfigurationTenantResolveContributor()); + }); + + //添加租户解析器注入 + services.AddTransient(); + + //添加当前租户 + services.AddTransient(); + + //添加默认访问器 + services.AddTransient(); + + return services; + + + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenant.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenant.cs new file mode 100644 index 00000000..2d892e11 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenant.cs @@ -0,0 +1,29 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 当前租户接口 +/// +public interface ICurrentTenant +{ + /// + /// 是否有效 + /// + bool IsAvailable { get; } + + /// + /// 租户ID + /// + Guid Id { get; } + + /// + /// 租户名称 + /// + string? Name { get; } + + /// + /// 替换租户 + /// + /// + /// + IDisposable Change(Guid? id, string? name = null); +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenantAccessor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenantAccessor.cs new file mode 100644 index 00000000..63b2cbff --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ICurrentTenantAccessor.cs @@ -0,0 +1,12 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户访问器 +/// +public interface ICurrentTenantAccessor +{ + /// + /// 当前租户信息 + /// + BasicTenantInfo Current { get; set; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContext.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContext.cs new file mode 100644 index 00000000..90585528 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContext.cs @@ -0,0 +1,21 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 解析器上下文 +/// (作用于各个)之间 +/// +public interface ITenantResolveContext +{ + /// + IServiceProvider ServiceProvider { get; } + + /// + /// 租户ID 或 名称 + /// + string TenantIdOrName { get; set; } + + /// + /// 是否已处理 + /// + bool Handled { get; set; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContributor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContributor.cs new file mode 100644 index 00000000..a1e4737a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolveContributor.cs @@ -0,0 +1,19 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户解析器贡献者 +/// +public interface ITenantResolveContributor +{ + /// + /// 贡献者名称 + /// + string Name { get; } + + /// + /// 解析 + /// + /// 解析器上下文 + /// + Task ResolveAsync(ITenantResolveContext context); +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolver.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolver.cs new file mode 100644 index 00000000..0f3987e7 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ITenantResolver.cs @@ -0,0 +1,13 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户解析器接口 +/// +public interface ITenantResolver +{ + /// + /// 解析租户Id或名称 + /// + /// + Task ResolveTenantIdOrNameAsync(); +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/ConfigurationTenantResolveContributor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/ConfigurationTenantResolveContributor.cs new file mode 100644 index 00000000..7396d552 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/ConfigurationTenantResolveContributor.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Yi.Framework.Data.Entities; +using Yi.Framework.MultiTenancy; + +namespace Yi.Framework.MultiTenancy.ResolveContributor; + +/// +/// 租户解析器贡献者 +/// +public class ConfigurationTenantResolveContributor : TenantResolveContributorBase +{ + /// + /// 租户解析器贡献者基类 + /// + public override string Name => "Configuration"; + + /// + /// 解析 + /// + /// 解析器上下文 + /// + public override Task ResolveAsync(ITenantResolveContext context) + { + IConfiguration? configuration = context.ServiceProvider.GetRequiredService(); + + string? tenantIdStr = configuration.GetValue(nameof(IMultiTenant.TenantId)); + + if (Guid.TryParse(tenantIdStr, out Guid tenantId)) + { + if (tenantId != Guid.Empty) + { + context.TenantIdOrName = tenantId.ToString(); + context.Handled = true; + } + } + + context.Handled = false; + return Task.CompletedTask; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/CurrentUserTenantResolveContributor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/CurrentUserTenantResolveContributor.cs new file mode 100644 index 00000000..bed9477b --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/CurrentUserTenantResolveContributor.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.DependencyInjection; +using Yi.Framework.Core.CurrentUsers; + +namespace Yi.Framework.MultiTenancy.ResolveContributor; + +/// +/// 当前用户中获取租户 +/// +public class CurrentUserTenantResolveContributor : TenantResolveContributorBase +{ + /// + /// 贡献者名称 + /// + public const string ContributorName = "CurrentUser"; + + /// + /// 贡献者名称 + /// + public override string Name => ContributorName; + + /// + /// 解析 + /// + /// 解析器上下文 + /// + public override Task ResolveAsync(ITenantResolveContext context) + { + ICurrentUser currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.TenantId != Guid.Empty) + { + context.Handled = true; + context.TenantIdOrName = currentUser.TenantId.ToString(); + } + else + { + context.Handled = false; + } + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/HttpHeaderTenantResolveContributor.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/HttpHeaderTenantResolveContributor.cs new file mode 100644 index 00000000..bfc6b8cd --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/ResolveContributor/HttpHeaderTenantResolveContributor.cs @@ -0,0 +1,52 @@ + +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Yi.Framework.Data.Entities; +using Yi.Framework.MultiTenancy; + +namespace Yi.Framework.MultiTenancy.ResolveContributor; + +/// +/// 租户解析器贡献者 +/// +public class HttpHeaderTenantResolveContributor : TenantResolveContributorBase +{ + /// + /// 贡献者名称 + /// + public override string Name => "HttpHeader"; + + /// + /// 解析 + /// + /// 解析器上下文 + /// + public override Task ResolveAsync(ITenantResolveContext context) + { + IHttpContextAccessor? httpContextAccessor = context.ServiceProvider.GetService(); + + //如果没有注入http对象,直接跳出 + if (httpContextAccessor is null) + { + return Task.CompletedTask; + } + HttpContext? httpContext = httpContextAccessor.HttpContext; + if (httpContext is not null) + { + string? tenantId = httpContext.Request.Headers + .Where(x => x.Key == nameof(IMultiTenant.TenantId)) + .Select(x => x.Value.ToString()) + .FirstOrDefault(); + + if (tenantId is not null) + { + if (Guid.TryParse(tenantId, out Guid tid)) + { + context.TenantIdOrName = tid.ToString(); + context.Handled = true; + } + } + } + return Task.CompletedTask; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContext.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContext.cs new file mode 100644 index 00000000..49ff8723 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContext.cs @@ -0,0 +1,35 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 解析器上下文 +/// +public class TenantResolveContext : ITenantResolveContext +{ + /// + public TenantResolveContext(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + /// + public IServiceProvider ServiceProvider { get; } + + /// + /// 租户ID 或 名称 + /// + public string TenantIdOrName { get; set; } + + /// + /// 是否已处理 + /// + public bool Handled { get; set; } + + /// + /// 是否已经处理或者为有效值 + /// + public bool HasResolvedTenantOrHost() + { + return Handled + || TenantIdOrName != Guid.Empty.ToString() && !string.IsNullOrWhiteSpace(TenantIdOrName); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContributorBase.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContributorBase.cs new file mode 100644 index 00000000..6a926822 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveContributorBase.cs @@ -0,0 +1,19 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户解析器贡献者基类 +/// +public abstract class TenantResolveContributorBase : ITenantResolveContributor +{ + /// + /// 贡献者名称 + /// + public abstract string Name { get; } + + /// + /// 解析 + /// + /// 解析器上下文 + /// + public abstract Task ResolveAsync(ITenantResolveContext context); +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveOptions.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveOptions.cs new file mode 100644 index 00000000..b84ce407 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveOptions.cs @@ -0,0 +1,27 @@ + + +using Yi.Framework.MultiTenancy.ResolveContributor; + +namespace Yi.Framework.MultiTenancy; + +/// +/// 解析器属性 +/// +public class TenantResolveOptions +{ + /// + /// 构造函数 + /// + public TenantResolveOptions() + { + TenantResolvers = new List + { + new CurrentUserTenantResolveContributor() + }; + } + + /// + /// 解析器贡献者。由这帮东西为框架提供 租户ID + /// + public List TenantResolvers { get; } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveResult.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveResult.cs new file mode 100644 index 00000000..08c0e70c --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolveResult.cs @@ -0,0 +1,17 @@ +namespace Yi.Framework.MultiTenancy; + +/// +/// 租户解析器结果 +/// +public class TenantResolveResult +{ + /// + /// 租户ID 或 名称 + /// + public string TenantIdOrName { get; set; } = Guid.Empty.ToString(); + + /// + /// 存储遍历过的 + /// + public List AppliedResolvers { get; } = new List(); +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolver.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolver.cs new file mode 100644 index 00000000..e1cdc0f0 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/TenantResolver.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Yi.Framework.MultiTenancy; + +/// +/// +/// +public class TenantResolver : ITenantResolver +{ + private readonly IServiceProvider _serviceProvider; + private readonly TenantResolveOptions _options; + + /// + /// 构造函数 + /// + public TenantResolver(IOptions options, IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _options = options.Value; + } + + /// + /// 解析租户Id或名称 + /// + public virtual async Task ResolveTenantIdOrNameAsync() + { + TenantResolveResult? result = new TenantResolveResult(); + + using (IServiceScope? serviceScope = _serviceProvider.CreateScope()) + { + TenantResolveContext? context = new TenantResolveContext(serviceScope.ServiceProvider); + + foreach (ITenantResolveContributor tenantResolver in _options.TenantResolvers) + { + await tenantResolver.ResolveAsync(context); + + result.AppliedResolvers.Add(tenantResolver.Name); + + if (context.HasResolvedTenantOrHost()) + { + result.TenantIdOrName = context.TenantIdOrName; + break; + } + } + } + return result; + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Yi.Framework.MultiTenancy.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Yi.Framework.MultiTenancy.csproj new file mode 100644 index 00000000..4a1d9a1a --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/Yi.Framework.MultiTenancy.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/YiFrameworkMultiTenancyModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/YiFrameworkMultiTenancyModule.cs new file mode 100644 index 00000000..808ec642 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.MultiTenancy/YiFrameworkMultiTenancyModule.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.MultiTenancy.Extensions; + +namespace Yi.Framework.MultiTenancy +{ + public class YiFrameworkMultiTenancyModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddCurrentTenant(); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWork.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWork.cs new file mode 100644 index 00000000..43e957c1 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWork.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.Framework.Uow +{ + internal class DefaultUnitOfWork : IUnitOfWork + { + public DefaultUnitOfWork() { } + public bool IsTran { get; set; } + public bool IsCommit { get; set; } + public bool IsClose { get; set; } + + public bool Commit() + { + return true; + } + + public void Dispose() + { + } + + public IRepository GetRepository() + { + throw new NotImplementedException(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWorkManager.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWorkManager.cs new file mode 100644 index 00000000..b755c7f9 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/DefaultUnitOfWorkManager.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Uow +{ + internal class DefaultUnitOfWorkManager : IUnitOfWorkManager + { + public IUnitOfWork CreateContext(bool isTran = true) + { + return new DefaultUnitOfWork(); + } + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWork.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWork.cs new file mode 100644 index 00000000..5799a351 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWork.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.Framework.Uow +{ + public interface IUnitOfWork : IDisposable + { + bool IsTran { get; set; } + bool IsCommit { get; set; } + bool IsClose { get; set; } + + IRepository GetRepository(); + bool Commit(); + } +} diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWorkManager.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWorkManager.cs new file mode 100644 index 00000000..00b0b408 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/IUnitOfWorkManager.cs @@ -0,0 +1,8 @@ +namespace Yi.Framework.Uow +{ + public interface IUnitOfWorkManager + { + IUnitOfWork CreateContext(bool isTran = true); + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Properties/launchSettings.json b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Properties/launchSettings.json new file mode 100644 index 00000000..b638dee4 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Yi.Framework.Uow": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53047;http://localhost:53048" + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Yi.Framework.Uow.csproj b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Yi.Framework.Uow.csproj new file mode 100644 index 00000000..37b50758 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/Yi.Framework.Uow.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/YiFrameworkUowModule.cs b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/YiFrameworkUowModule.cs new file mode 100644 index 00000000..f4ced262 --- /dev/null +++ b/Yi.Framework.Net6/src/framework/Yi.Framework.Uow/YiFrameworkUowModule.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Ddd; + +namespace Yi.Framework.Uow +{ + [DependsOn( + typeof(YiFrameworkDddModule))] + public class YiFrameworkUowModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.TryAddSingleton(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Class1.cs b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Class1.cs new file mode 100644 index 00000000..0f13a2fa --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Class1.cs @@ -0,0 +1,7 @@ +namespace Yi.Framework.BackgroundJobs.Quartz +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Properties/launchSettings.json b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Properties/launchSettings.json new file mode 100644 index 00000000..3a6101cf --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Yi.Framework.BackgroundJobs.Quartz": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:53041;http://localhost:53042" + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Yi.Framework.BackgroundJobs.Quartz.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Yi.Framework.BackgroundJobs.Quartz.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.BackgroundJobs.Quartz/Yi.Framework.BackgroundJobs.Quartz.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/MemoryCacheClient.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/MemoryCacheClient.cs new file mode 100644 index 00000000..be3dd23d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/MemoryCacheClient.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Caching.Memory; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Caching.MemoryCache +{ + public class MemoryCacheClient : CacheManager + { + private IMemoryCache _client; + public MemoryCacheClient() + { + _client = new Microsoft.Extensions.Caching.Memory.MemoryCache(new MemoryCacheOptions()); + } + public override bool Exits(string key) + { + return _client.TryGetValue(key, out var _); + } + public override T Get(string key) + { + return _client.Get(key); + } + public override bool Set(string key, T item) + { + return _client.Set(key, item) is not null; + } + + public override bool Set(string key, T item, TimeSpan time) + { + return _client.Set(key, item, time) is not null; + } + + public override long Del(string key) + { + _client.Remove(key); + return 1; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/Yi.Framework.Caching.MemoryCache.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/Yi.Framework.Caching.MemoryCache.csproj new file mode 100644 index 00000000..2371c385 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/Yi.Framework.Caching.MemoryCache.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/YiFrameworkCachingMemoryCacheModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/YiFrameworkCachingMemoryCacheModule.cs new file mode 100644 index 00000000..83076f1f --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.MemoryCache/YiFrameworkCachingMemoryCacheModule.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Caching.MemoryCache; +using Yi.Framework.Caching; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core; + +namespace Yi.Framework.Ddd +{ + [DependsOn( + typeof(YiFrameworkCoreModule) + )] + public class YiFrameworkCachingMemoryCacheModule:IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddSingleton(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/RedisCacheClient.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/RedisCacheClient.cs new file mode 100644 index 00000000..eca5c698 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/RedisCacheClient.cs @@ -0,0 +1,165 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Caching; +using Microsoft.Extensions.Options; +using Yi.Framework.Caching.Redis; +using static CSRedis.CSRedisClient; +using CSRedis; + +namespace Yi.Framework.Caching.Redis +{ + public class RedisCacheClient : CacheManager + { + private readonly CachingConnOptions _RedisOptions; + + private CSRedisClient _client; + + public RedisCacheClient(IOptionsMonitor redisConnOptions) + { + this._RedisOptions = redisConnOptions.CurrentValue; + _client = new CSRedisClient($"{_RedisOptions.Host}:{_RedisOptions.Prot},password={_RedisOptions.Password},defaultDatabase ={_RedisOptions.DB}"); + } + public override bool Exits(string key) + { + return _client.Exists(key); + } + public override T Get(string key) + { + return _client.Get(key); + } + + public override bool Set(string key, T data, TimeSpan time) + { + return _client.Set(key, data, time); + } + + public override bool Set(string key, T data) + { + return _client.Set(key, data); + } + + public override long Del(string key) + { + return _client.Del(key); + } + + public override bool HSet(string key, string fieId, object data) + { + return _client.HSet(key, fieId, data); + } + + public override bool HSet(string key, string fieId, object data, TimeSpan time) + { + var res = _client.HSet(key, fieId, data); + var res2 = _client.Expire(key, time); + return res && res2; + } + + public override T HGet(string key, string field) + { + return _client.HGet(key, field); + } + + + public override long HDel(string key, params string[] par) + { + return _client.HDel(key, par); + } + + public override long HLen(string key) + { + return _client.HLen(key); + } + + public override Dictionary HGetAll(string key) + { + return _client.HGetAll(key); + } + + /// + /// 简单发布 + /// + /// + /// + /// + public override long Publish(string channel, string message) + { + return _client.Publish(channel, message); + } + + /// + /// 简单订阅:广播,无持久化,需要Publish写入队列 + /// + /// + /// + public SubscribeObject Subscribe(params (string, Action)[] channels) + { + return _client.Subscribe(channels); + } + + /// + /// 多端争抢模式订阅,需要Lpush写入队列 + /// + /// + /// + /// + public SubscribeListObject SubscribeList(string listKey, Action onMessage) + { + return _client.SubscribeList(listKey, onMessage); + } + + /// + /// 多端非争抢模式订阅,需要Lpush写入队列 + /// + /// + /// + /// + /// + public SubscribeListBroadcastObject SubscribeListBroadcast(string listKey, string clientId, Action onMessage) + { + return _client.SubscribeListBroadcast(listKey, clientId, onMessage); + } + + public override bool LSet(string key, long index, object value) + { + return _client.LSet(key, index, value); + } + + + + /// + /// 列表插入头部 + /// + /// + /// + /// + /// + public override long LPush(string key, params T[] value) + { + return _client.LPush(key, value); + } + + /// + /// 列表弹出头部 + /// + /// + /// + /// + public override T LPop(string key) + { + return _client.LPop(key); + } + + public override string[] Keys(string pattern) + { + return _client.Keys(pattern); + } + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/Yi.Framework.Caching.Redis.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/Yi.Framework.Caching.Redis.csproj new file mode 100644 index 00000000..e378e221 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/Yi.Framework.Caching.Redis.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/YiFrameworkCachingRedisModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/YiFrameworkCachingRedisModule.cs new file mode 100644 index 00000000..c576fadb --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching.Redis/YiFrameworkCachingRedisModule.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Configuration; + +namespace Yi.Framework.Caching.Redis +{ + [DependsOn( + typeof(YiFrameworkCoreModule) + )] + public class YiFrameworkCachingRedisModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.Configure(Appsettings.appConfiguration("CachingConnOptions")); + services.AddSingleton(); + } + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CacheManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CacheManager.cs new file mode 100644 index 00000000..93efa93f --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CacheManager.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Caching +{ + public abstract class CacheManager + { + + public virtual bool Exits(string key) + { + throw new NotImplementedException(); + } + public virtual T Get(string key) + { + throw new NotImplementedException(); + } + + public virtual bool Set(string key, T data, TimeSpan time) + { + throw new NotImplementedException(); + } + + public virtual bool Set(string key, T data) + { + throw new NotImplementedException(); + } + + public virtual long Del(string key) + { + throw new NotImplementedException(); + } + + public virtual bool HSet(string key, string fieId, object data) + { + throw new NotImplementedException(); + } + + public virtual bool HSet(string key, string fieId, object data, TimeSpan time) + { + throw new NotImplementedException(); + } + + public virtual T HGet(string key, string field) + { + throw new NotImplementedException(); + } + + + public virtual long HDel(string key, params string[] par) + { + throw new NotImplementedException(); + } + + public virtual long HLen(string key) + { + throw new NotImplementedException(); + } + + public virtual Dictionary HGetAll(string key) + { + throw new NotImplementedException(); + } + + /// + /// 简单发布 + /// + /// + /// + /// + public virtual long Publish(string channel, string message) + { + throw new NotImplementedException(); + } + + + + + public virtual bool LSet(string key, long index, object value) + { + throw new NotImplementedException(); + } + + + + /// + /// 列表插入头部 + /// + /// + /// + /// + /// + public virtual long LPush(string key, params T[] value) + { + throw new NotImplementedException(); + } + + /// + /// 列表弹出头部 + /// + /// + /// + /// + public virtual T LPop(string key) + { + throw new NotImplementedException(); + } + + public virtual string[] Keys(string pattern) + { + throw new NotImplementedException(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CachingConnOptions.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CachingConnOptions.cs new file mode 100644 index 00000000..39f9ed92 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/CachingConnOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Caching +{ + public class CachingConnOptions + { + public string? Host { get; set; } + public int DB { get; set; } = 0; + public int Prot { get; set; } + public string? Password { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Caching/Yi.Framework.Caching.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/Yi.Framework.Caching.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Caching/Yi.Framework.Caching.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryConst.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryConst.cs new file mode 100644 index 00000000..1cf00335 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// 常量定义 + /// + + public class DictionaryConst + { + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryService.cs new file mode 100644 index 00000000..eda37d68 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryService.cs @@ -0,0 +1,51 @@ +using Cike.AutoWebApi.Setting; +using Yi.Framework.Ddd.Services; +using Microsoft.AspNetCore.Mvc; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.DictionaryManager.Entities; +using Yi.Framework.DictionaryManager.Dtos.Dictionary; +using Yi.Framework.Core.Attributes; +using SqlSugar; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// Dictionary服务实现 + /// + [AppService] + public class DictionaryService : CrudAppService, + IDictionaryService, IAutoApiService + { + /// + /// 查询 + /// + + public override async Task> GetListAsync(DictionaryGetListInputVo input) + { + RefAsync total = 0; + var entities = await _DbQueryable.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.State is not null, x => x.State == input.State) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto + { + Total = total, + Items = await MapToGetListOutputDtosAsync(entities) + }; + } + + + /// + /// 根据字典类型获取字典列表 + /// + /// + /// + [Route("/api/dictionary/dic-type/{dicType}")] + public async Task> GetDicType([FromRoute] string dicType) + { + var entities = await _repository.GetListAsync(u => u.DictType == dicType && u.State == true); + var result = await MapToGetListOutputDtosAsync(entities); + return result; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeConst.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeConst.cs new file mode 100644 index 00000000..18b84f8a --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// 常量定义 + /// + + public class DictionaryTypeConst + { + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeService.cs new file mode 100644 index 00000000..b2871f9a --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/DictionaryTypeService.cs @@ -0,0 +1,38 @@ +using Cike.AutoWebApi.Setting; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using Yi.Framework.DictionaryManager.Dtos.DictionaryType; +using Yi.Framework.DictionaryManager.Entities; +using Yi.Framework.Core.Attributes; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// DictionaryType服务实现 + /// + [AppService] + public class DictionaryTypeService : CrudAppService, + IDictionaryTypeService, IAutoApiService + { + + + public async override Task> GetListAsync(DictionaryTypeGetListInputVo input) + { + + RefAsync total = 0; + var entities = await _DbQueryable.WhereIF(input.DictName is not null, x => x.DictName.Contains(input.DictName!)) + .WhereIF(input.DictType is not null, x => x.DictType!.Contains(input.DictType!)) + .WhereIF(input.State is not null, x => x.State == input.State) + .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .ToPageListAsync(input.PageNum, input.PageSize, total); + + return new PagedResultDto + { + Total = total, + Items = await MapToGetListOutputDtosAsync(entities) + }; + } + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryCreateInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryCreateInputVo.cs new file mode 100644 index 00000000..cf3325cd --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryCreateInputVo.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager.Dtos.Dictionary +{ + /// + /// Dictionary输入创建对象 + /// + public class DictionaryCreateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? Remark { get; set; } + public string? ListClass { get; set; } + public string? CssClass { get; set; } + public string DictType { get; set; } = string.Empty; + public string? DictLabel { get; set; } + public string DictValue { get; set; } = string.Empty; + public bool IsDefault { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListInputVo.cs new file mode 100644 index 00000000..8a7ef6d3 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListInputVo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.Dictionary +{ + public class DictionaryGetListInputVo : PagedAndSortedResultRequestDto + { + public string? DictType { get; set; } + public string? DictLabel { get; set; } + public bool? State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListOutputDto.cs new file mode 100644 index 00000000..3dbbed30 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetListOutputDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.Dictionary +{ + public class DictionaryGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? Remark { get; set; } + public string? ListClass { get; set; } + public string? CssClass { get; set; } + public string DictType { get; set; } = string.Empty; + public string? DictLabel { get; set; } + public string DictValue { get; set; } = string.Empty; + public bool IsDefault { get; set; } + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetOutputDto.cs new file mode 100644 index 00000000..4ef84e40 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryGetOutputDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.Dictionary +{ + public class DictionaryGetOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? Remark { get; set; } + public string? ListClass { get; set; } + public string? CssClass { get; set; } + public string DictType { get; set; } = string.Empty; + public string? DictLabel { get; set; } + public string DictValue { get; set; } = string.Empty; + public bool IsDefault { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryUpdateInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryUpdateInputVo.cs new file mode 100644 index 00000000..a03314f6 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/Dictionary/DictionaryUpdateInputVo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager.Dtos.Dictionary +{ + public class DictionaryUpdateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? Remark { get; set; } + public string? ListClass { get; set; } + public string? CssClass { get; set; } + public string DictType { get; set; } = string.Empty; + public string? DictLabel { get; set; } + public string DictValue { get; set; } = string.Empty; + public bool IsDefault { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeCreateInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeCreateInputVo.cs new file mode 100644 index 00000000..42ce4a8e --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeCreateInputVo.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager.Dtos.DictionaryType +{ + /// + /// DictionaryType输入创建对象 + /// + public class DictionaryTypeCreateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string DictName { get; set; } = string.Empty; + public string DictType { get; set; } = string.Empty; + public string? Remark { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListInputVo.cs new file mode 100644 index 00000000..c450fa8d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.DictionaryType +{ + public class DictionaryTypeGetListInputVo : PagedAllResultRequestDto + { + public string? DictName { get; set; } + public string? DictType { get; set; } + public string? Remark { get; set; } + + public bool? State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListOutputDto.cs new file mode 100644 index 00000000..2ab9f1c3 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetListOutputDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.DictionaryType +{ + public class DictionaryTypeGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string DictName { get; set; } = string.Empty; + public string DictType { get; set; } = string.Empty; + public string? Remark { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetOutputDto.cs new file mode 100644 index 00000000..3ca830a6 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeGetOutputDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.DictionaryManager.Dtos.DictionaryType +{ + public class DictionaryTypeGetOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string DictName { get; set; } = string.Empty; + public string DictType { get; set; } = string.Empty; + public string? Remark { get; set; } + + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeUpdateInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeUpdateInputVo.cs new file mode 100644 index 00000000..35621692 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Dtos/DictionaryType/DictionaryTypeUpdateInputVo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.DictionaryManager.Dtos.DictionaryType +{ + public class DictionaryTypeUpdateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string DictName { get; set; } = string.Empty; + public string DictType { get; set; } = string.Empty; + public string? Remark { get; set; } + public bool State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryEntity.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryEntity.cs new file mode 100644 index 00000000..50033177 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryEntity.cs @@ -0,0 +1,76 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.DictionaryManager.Entities +{ + [SugarTable("Dictionary")] + public class DictionaryEntity : AuditedObject, IEntity, ISoftDelete, IOrderNum, IState + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + /// + /// 状态 + /// + public bool State { get; set; } = true; + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + /// + /// tag类型 + /// + [SugarColumn(ColumnName = "ListClass")] + public string? ListClass { get; set; } + /// + /// tagClass + /// + [SugarColumn(ColumnName = "CssClass")] + public string? CssClass { get; set; } + + /// + /// 字典类型 + /// + [SugarColumn(ColumnName = "DictType")] + public string DictType { get; set; } = string.Empty; + /// + /// 字典标签 + /// + [SugarColumn(ColumnName = "DictLabel")] + public string? DictLabel { get; set; } + /// + /// 字典值 + /// + [SugarColumn(ColumnName = "DictValue")] + public string DictValue { get; set; } = string.Empty; + /// + /// 是否为该类型的默认值 + /// + [SugarColumn(ColumnName = "IsDefault")] + public bool IsDefault { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryTypeEntity.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryTypeEntity.cs new file mode 100644 index 00000000..64341ad7 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Entities/DictionaryTypeEntity.cs @@ -0,0 +1,55 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.DictionaryManager.Entities +{ + [SugarTable("DictionaryType")] + public class DictionaryTypeEntity : AuditedObject, IEntity, ISoftDelete, IOrderNum + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + + /// + /// 状态 + /// + public bool? State { get; set; } = true; + + /// + /// 字典名称 + /// + [SugarColumn(ColumnName = "DictName")] + public string DictName { get; set; } = string.Empty; + /// + /// 字典类型 + /// + [SugarColumn(ColumnName = "DictType")] + public string DictType { get; set; } = string.Empty; + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryService.cs new file mode 100644 index 00000000..6f8c7db3 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services.Abstract; +using Yi.Framework.DictionaryManager.Dtos.Dictionary; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// Dictionary服务抽象 + /// + public interface IDictionaryService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryTypeService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryTypeService.cs new file mode 100644 index 00000000..b5af53d6 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/IDictionaryTypeService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services.Abstract; +using Yi.Framework.DictionaryManager.Dtos.DictionaryType; + +namespace Yi.Framework.DictionaryManager +{ + /// + /// DictionaryType服务抽象 + /// + public interface IDictionaryTypeService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Yi.Framework.DictionaryManager.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Yi.Framework.DictionaryManager.csproj new file mode 100644 index 00000000..fee0fe4d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/Yi.Framework.DictionaryManager.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/YiFrameworkDictionaryManagerModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/YiFrameworkDictionaryManagerModule.cs new file mode 100644 index 00000000..142999d5 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.DictionaryManager/YiFrameworkDictionaryManagerModule.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; + +namespace Yi.Framework.DictionaryManager +{ + [DependsOn(typeof(YiFrameworkCoreModule))] + public class YiFrameworkDictionaryManagerModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/Yi.Framework.EventBus.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/Yi.Framework.EventBus.csproj new file mode 100644 index 00000000..a6d1a9aa --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/Yi.Framework.EventBus.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/YiFrameworkEventBusModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/YiFrameworkEventBusModule.cs new file mode 100644 index 00000000..558716f1 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.EventBus/YiFrameworkEventBusModule.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core.Helper; + +namespace Yi.Framework.EventBus +{ + public class YiFrameworkEventBusModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddCikeEventBus(opt => + { + opt.AddHandlerForAsemmbly(AssemblyHelper.GetAllLoadAssembly()); + }); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileEntity.cs b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileEntity.cs new file mode 100644 index 00000000..18c9c58f --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileEntity.cs @@ -0,0 +1,48 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.FileManager +{ + /// + /// 文件表 + /// + [SugarTable("File")] + public class FileEntity : IEntity,IAuditedObject + { + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] + public long Id { get; set; } + /// + /// 文件类型 + /// + [SugarColumn(ColumnName = "FileContentType")] + public string? FileContentType { get; set; } + /// + /// 文件大小 + /// + [SugarColumn(ColumnName = "FileSize")] + public decimal FileSize { get; set; } + /// + /// 文件名 + /// + [SugarColumn(ColumnName = "FileName")] + public string FileName { get; set; } + /// + /// 文件路径 + /// + [SugarColumn(ColumnName = "FilePath")] + public string FilePath { get; set; } + + public DateTime CreationTime { get; set; } + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileGetListOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileGetListOutputDto.cs new file mode 100644 index 00000000..9cc4c5e4 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileGetListOutputDto.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.FileManager +{ + public class FileGetListOutputDto:IEntityDto + { + public long Id { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileService.cs new file mode 100644 index 00000000..f5ab7930 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/FileService.cs @@ -0,0 +1,151 @@ +using Cike.AutoWebApi.Setting; +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.AspNetCore.Extensions; +using Yi.Framework.Core.Const; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Helper; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Services.Abstract; +using Yi.Framework.ImageSharp; + +namespace Yi.Framework.FileManager +{ + /// + /// 文件处理 + /// + public class FileService : ApplicationService, IFileService, IAutoApiService + { + private readonly IRepository _repository; + private readonly ImageSharpManager _imageSharpManager; + private readonly HttpContext _httpContext; + public FileService(IRepository repository, ImageSharpManager imageSharpManager, IHttpContextAccessor httpContextAccessor + ) + { + _repository = repository; + _imageSharpManager = imageSharpManager; + if (httpContextAccessor.HttpContext is null) + { + throw new ApplicationException("HttpContext为空"); + } + _httpContext = httpContextAccessor.HttpContext; + } + + /// + /// 下载文件,是否缩略图 + /// + /// + [Route("/api/file/{code}/{isThumbnail?}")] + public async Task Get([FromRoute] long code, [FromRoute] bool? isThumbnail) + { + var file = await _repository.GetByIdAsync(code); + if (file is null) + { + return new NotFoundResult(); + } + + var path = file.FilePath; + //如果为缩略图,需要修改路径 + if (isThumbnail is true) + { + path = $"{PathConst.wwwroot}/{FileTypeEnum.Thumbnail}/{file.Id}{Path.GetExtension(file.FileName)}"; + } + //路径为: 文件路径/文件id+文件扩展名 + + if (!File.Exists(path)) + { + return new NotFoundResult(); + } + + var steam = await File.ReadAllBytesAsync(path); + + //设置附件下载,下载名称 + _httpContext.FileAttachmentHandle(file.FileName); + return new FileContentResult(steam, file.FileContentType ?? @"text/plain"); + } + + /// + /// 上传文件 + /// + /// + public async Task> Post([FromForm] IFormFileCollection file) + { + if (file.Count() == 0) + { + throw new ArgumentException("文件上传为空!"); + } + //批量插入 + List entities = new(); + + foreach (var f in file) + { + FileEntity data = new(); + data.Id = SnowflakeHelper.NextId; + data.FileSize = ((decimal)f.Length) / 1024; + data.FileName = f.FileName; + + + data.FileContentType = MimeHelper.GetMimeMapping(f.FileName); + + + var type = MimeHelper.GetFileType(f.FileName); + + //落盘文件,文件名为雪花id+自己的扩展名 + string filename = data.Id.ToString() + Path.GetExtension(f.FileName); + string typePath = $"{PathConst.wwwroot}/{type}"; + if (!Directory.Exists(typePath)) + { + Directory.CreateDirectory(typePath); + } + + var filePath = Path.Combine(typePath, filename); + data.FilePath = filePath; + + + //生成文件 + using (var stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.ReadWrite)) + { + await f.CopyToAsync(stream); + + //如果是图片类型,还需要生成缩略图,当然,如果图片很小,直接复制过去即可 + if (FileTypeEnum.Image.Equals(type)) + { + string thumbnailPath = $"{PathConst.wwwroot}/{FileTypeEnum.Thumbnail}"; + if (!Directory.Exists(thumbnailPath)) + { + Directory.CreateDirectory(thumbnailPath); + } + string thumbnailFilePath = Path.Combine(thumbnailPath, filename); + try + { + _imageSharpManager.ImageCompress(f.FileName, f.OpenReadStream(), thumbnailFilePath); + } + catch + { + var result = new byte[stream.Length]; + await stream.ReadAsync(result, 0, result.Length); + await File.WriteAllBytesAsync(thumbnailFilePath, result); + } + } + + + }; + entities.Add(data); + } + await _repository.InsertRangeAsync(entities); + return entities.Adapt>(); + + + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/IFileService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/IFileService.cs new file mode 100644 index 00000000..ad47147f --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/IFileService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.FileManager +{ + public interface IFileService + { + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/Yi.Framework.FileManager.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/Yi.Framework.FileManager.csproj new file mode 100644 index 00000000..649a12e6 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/Yi.Framework.FileManager.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + True + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/YiFrameworkFileManagerModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/YiFrameworkFileManagerModule.cs new file mode 100644 index 00000000..e6b613db --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.FileManager/YiFrameworkFileManagerModule.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core; +using Yi.Framework.Ddd; +using Yi.Framework.ImageSharp; + +namespace Yi.Framework.FileManager +{ + [DependsOn( + typeof(YiFrameworkDddModule), + typeof(YiFrameworkImageSharpModule) + )] + public class YiFrameworkFileManagerModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddTransient(); + services.AddTransient(); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/HeiCaptchaExtension.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/HeiCaptchaExtension.cs new file mode 100644 index 00000000..1720cfcb --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/HeiCaptchaExtension.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Hei.Captcha +{ + public static class HeiCaptchaExtension + { + /// + /// 启用HeiCaptcha + /// + /// + /// + public static IServiceCollection AddHeiCaptcha(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddScoped(); + return services; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageRgba32Extension.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageRgba32Extension.cs new file mode 100644 index 00000000..59c01537 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageRgba32Extension.cs @@ -0,0 +1,32 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Hei.Captcha +{ + public static class ImageRgba32Extension + { + public static byte[] ToPngArray(this Image img) where TPixel : unmanaged, IPixel + { + using (var ms = new MemoryStream()) + { + img.Save(ms, PngFormat.Instance); + return ms.ToArray(); + } + } + + public static byte[] ToGifArray(this Image img) where TPixel : unmanaged, IPixel + { + using (var ms = new MemoryStream()) + { + img.Save(ms, new GifEncoder()); + return ms.ToArray(); + } + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageSharpExtension.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageSharpExtension.cs new file mode 100644 index 00000000..8e2845ae --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/ImageSharpExtension.cs @@ -0,0 +1,216 @@ +//using SixLabors.Fonts; +//using SixLabors.ImageSharp; +//using SixLabors.ImageSharp.PixelFormats; +//using SixLabors.ImageSharp.Processing; +//using System; +//using System.Collections.Generic; + +//namespace Hei.Captcha +//{ +// public static class ImageSharpExtension +// { + +// / +// / 绘制中文字符(可以绘制字母数字,但样式可能需要改) +// / +// / +// / < param name="processingContext"> +// / +// / < param name="containerHeight"> +// / +// / < param name="color"> +// / +// / < returns > +// public static IImageProcessingContext DrawingCnText(this IImageProcessingContext processingContext, int containerWidth, int containerHeight, string text, Rgba32 color, Font font) +// where TPixel : struct, IPixel +// { +// return processingContext.Apply(img => +// { +// if (string.IsNullOrEmpty(text) == false) +// { +// Random random = new Random(); +// var textWidth = (img.Width / text.Length); +// var img2Size = Math.Min(textWidth, img.Height); +// var fontMiniSize = (int)(img2Size * 0.6); +// var fontMaxSize = (int)(img2Size * 0.95); + +// for (int i = 0; i < text.Length; i++) +// { +// using (Image img2 = new Image(img2Size, img2Size)) +// { +// Font scaledFont = new Font(font, random.Next(fontMiniSize, fontMaxSize)); +// var point = new Point(i * textWidth, (containerHeight - img2.Height) / 2); +// var textGraphicsOptions = new TextGraphicsOptions(true) +// { +// HorizontalAlignment = HorizontalAlignment.Left, +// VerticalAlignment = VerticalAlignment.Top +// }; + +// img2.Mutate(ctx => ctx +// .DrawText(textGraphicsOptions, text[i].ToString(), scaledFont, color, new Point(0, 0)) +// .Rotate(random.Next(-45, 45)) +// ); +// img.Mutate(ctx => ctx.DrawImage(img2, point, 1)); +// } +// } +// } +// }); +// } + +// public static IImageProcessingContext DrawingEnText(this IImageProcessingContext processingContext, int containerWidth, int containerHeight, string text, string[] colorHexArr, Font[] fonts) +// where TPixel : struct, IPixel +// { +// return processingContext.Apply(img => +// { +// if (string.IsNullOrEmpty(text) == false) +// { +// Random random = new Random(); +// var textWidth = (img.Width / text.Length); +// var img2Size = Math.Min(textWidth, img.Height); +// var fontMiniSize = (int)(img2Size * 0.9); +// var fontMaxSize = (int)(img2Size * 1.37); +// Array fontStyleArr = Enum.GetValues(typeof(FontStyle)); + +// for (int i = 0; i < text.Length; i++) +// { +// using (Image img2 = new Image(img2Size, img2Size)) +// { +// Font scaledFont = new Font(fonts[random.Next(0, fonts.Length)], random.Next(fontMiniSize, fontMaxSize), (FontStyle)fontStyleArr.GetValue(random.Next(fontStyleArr.Length))); +// var point = new Point(i * textWidth, (containerHeight - img2.Height) / 2); +// var colorHex = colorHexArr[random.Next(0, colorHexArr.Length)]; +// var textGraphicsOptions = new TextGraphicsOptions(true) +// { +// HorizontalAlignment = HorizontalAlignment.Left, +// VerticalAlignment = VerticalAlignment.Top +// }; + +// img2.Mutate(ctx => ctx +// .DrawText(textGraphicsOptions, text[i].ToString(), scaledFont, Rgba32.FromHex(colorHex), new Point(0, 0)) +// .DrawingGrid(containerWidth, containerHeight, Rgba32.FromHex(colorHex), 6, 1) +// .Rotate(random.Next(-45, 45)) +// ); +// img.Mutate(ctx => ctx.DrawImage(img2, point, 1)); +// } +// } +// } +// }); +// } + +// / +// / 画圆圈(泡泡) +// / +// / +// / < param name="processingContext"> +// / +// / < param name="containerHeight"> +// / +// / < param name="miniR"> +// / +// / < param name="color"> +// / +// / < returns > +// public static IImageProcessingContext DrawingCircles(this IImageProcessingContext processingContext, int containerWidth, int containerHeight, int count, int miniR, int maxR, TPixel color, bool canOverlap = false) +// where TPixel : struct, IPixel +// { +// return processingContext.Apply(img => +// { +// EllipsePolygon ep = null; +// Random random = new Random(); +// PointF tempPoint = new PointF(); +// List points = new List(); + +// if (count > 0) +// { +// for (int i = 0; i < count; i++) +// { +// if (canOverlap) +// { +// tempPoint = new PointF(random.Next(0, containerWidth), random.Next(0, containerHeight)); +// } +// else +// { +// tempPoint = getCirclePoginF(containerWidth, containerHeight, (miniR + maxR), ref points); +// } +// ep = new EllipsePolygon(tempPoint, random.Next(miniR, maxR)); + +// img.Mutate(ctx => ctx +// .Draw(color, (float)(random.Next(94, 145) / 100.0), ep.Clip()) +// ); +// } +// } +// }); +// } +// / +// / 画杂线 +// / +// / +// / < param name="processingContext"> +// / +// / < param name="containerHeight"> +// / +// / < param name="count"> +// / +// / < returns > +// public static IImageProcessingContext DrawingGrid(this IImageProcessingContext processingContext, int containerWidth, int containerHeight, TPixel color, int count, float thickness) +// where TPixel : struct, IPixel +// { +// return processingContext.Apply(img => +// { +// var points = new List { new PointF(0, 0) }; +// for (int i = 0; i < count; i++) +// { +// getCirclePoginF(containerWidth, containerHeight, 9, ref points); +// } +// points.Add(new PointF(containerWidth, containerHeight)); +// img.Mutate(ctx => ctx +// .DrawLines(color, thickness, points.ToArray()) +// ); +// }); +// } + +// / +// / 散 随机点 +// / +// / +// / < param name="containerHeight"> +// / +// / < param name="list"> +// / +// private static PointF getCirclePoginF(int containerWidth, int containerHeight, double lapR, ref List list) +// { +// Random random = new Random(); +// PointF newPoint = new PointF(); +// int retryTimes = 10; +// double tempDistance = 0; + +// do +// { +// newPoint.X = random.Next(0, containerWidth); +// newPoint.Y = random.Next(0, containerHeight); +// bool tooClose = false; +// foreach (var p in list) +// { +// tooClose = false; +// tempDistance = Math.Sqrt((Math.Pow((p.X - newPoint.X), 2) + Math.Pow((p.Y - newPoint.Y), 2))); +// if (tempDistance < lapR) +// { +// tooClose = true; +// break; +// } +// } +// if (tooClose == false) +// { +// list.Add(newPoint); +// break; +// } +// } +// while (retryTimes-- > 0); + +// if (retryTimes <= 0) +// { +// list.Add(newPoint); +// } +// return newPoint; +// } +// } +//} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/SecurityCodeHelper.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/SecurityCodeHelper.cs new file mode 100644 index 00000000..a223ef3a --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/SecurityCodeHelper.cs @@ -0,0 +1,182 @@ +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Hei.Captcha +{ + /// + /// 验证码配置和绘制逻辑 + /// + public class SecurityCodeHelper + { + /// + /// 验证码文本池 + /// + private static readonly string[] _cnTextArr = new string[] { "的", "一", "国", "在", "人", "了", "有", "中", "是", "年", "和", "大", "业", "不", "为", "发", "会", "工", "经", "上", "地", "市", "要", "个", "产", "这", "出", "行", "作", "生", "家", "以", "成", "到", "日", "民", "来", "我", "部", "对", "进", "多", "全", "建", "他", "公", "开", "们", "场", "展", "时", "理", "新", "方", "主", "企", "资", "实", "学", "报", "制", "政", "济", "用", "同", "于", "法", "高", "长", "现", "本", "月", "定", "化", "加", "动", "合", "品", "重", "关", "机", "分", "力", "自", "外", "者", "区", "能", "设", "后", "就", "等", "体", "下", "万", "元", "社", "过", "前", "面", "农", "也", "得", "与", "说", "之", "员", "而", "务", "利", "电", "文", "事", "可", "种", "总", "改", "三", "各", "好", "金", "第", "司", "其", "从", "平", "代", "当", "天", "水", "省", "提", "商", "十", "管", "内", "小", "技", "位", "目", "起", "海", "所", "立", "已", "通", "入", "量", "子", "问", "度", "北", "保", "心", "还", "科", "委", "都", "术", "使", "明", "着", "次", "将", "增", "基", "名", "向", "门", "应", "里", "美", "由", "规", "今", "题", "记", "点", "计", "去", "强", "两", "些", "表", "系", "办", "教 正", "条", "最", "达", "特", "革", "收", "二", "期", "并", "程", "厂", "如", "道", "际 及", "西", "口", "京", "华", "任", "调", "性", "导", "组", "东", "路", "活", "广", "意", "比", "投", "决", "交", "统", "党", "南", "安", "此", "领", "结", "营", "项", "情", "解", "议", "义", "山", "先", "车", "然", "价", "放", "世", "间", "因", "共", "院", "步", "物", "界", "集", "把", "持", "无", "但", "城", "相", "书", "村", "求", "治", "取", "原", "处", "府", "研", "质", "信", "四", "运", "县", "军", "件", "育", "局", "干", "队", "团", "又", "造", "形", "级", "标", "联", "专", "少", "费", "效", "据", "手", "施", "权", "江", "近", "深", "更", "认", "果", "格", "几", "看", "没", "职", "服", "台", "式", "益", "想", "数", "单", "样", "只", "被", "亿", "老", "受", "优", "常", "销", "志", "战", "流", "很", "接", "乡", "头", "给", "至", "难", "观", "指", "创", "证", "织", "论", "别", "五", "协", "变", "风", "批", "见", "究", "支", "那", "查", "张", "精", "每", "林", "转", "划", "准", "做", "需", "传", "争", "税", "构", "具", "百", "或", "才", "积", "势", "举", "必", "型", "易", "视", "快", "李", "参", "回", "引", "镇", "首", "推", "思", "完", "消", "值", "该", "走", "装", "众", "责", "备", "州", "供", "包", "副", "极", "整", "确", "知", "贸", "己", "环", "话", "反", "身", "选", "亚", "么", "带", "采", "王", "策", "真", "女", "谈", "严", "斯", "况", "色", "打", "德", "告", "仅", "它", "气", "料", "神", "率", "识", "劳", "境", "源", "青", "护", "列", "兴", "许", "户", "马", "港", "则", "节", "款", "拉", "直", "案", "股", "光", "较", "河", "花", "根", "布", "线", "土", "克", "再", "群", "医", "清", "速", "律", "她", "族", "历", "非", "感", "占", "续", "师", "何", "影", "功", "负", "验", "望", "财", "类", "货", "约", "艺", "售", "连", "纪", "按", "讯", "史", "示", "象", "养", "获", "石", "食", "抓", "富", "模", "始", "住", "赛", "客", "越", "闻", "央", "席", "坚" }; + + private static readonly string[] _enTextArr = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; + + /// + /// 验证码图片宽高 + /// + private readonly int _imageWidth = 120; + + private readonly int _imageHeight = 50; + + /// + /// 泡泡数量 + /// + private int _circleCount = 14; + + /// + /// 泡泡半径范围 + /// + private readonly int _miniCircleR = 2; + + private readonly int _maxCircleR = 8; + + /// + /// 颜色池,较深的颜色 + /// https://tool.oschina.net/commons?type=3 + /// + private static readonly string[] _colorHexArr = new string[] { "#00E5EE", "#000000", "#2F4F4F", "#000000", "#43CD80", "#191970", "#006400", "#458B00", "#8B7765", "#CD5B45" }; + + ///较浅的颜色 + private static readonly string[] _lightColorHexArr = new string[] { "#FFFACD", "#FDF5E6", "#F0FFFF", "#BBFFFF", "#FAFAD2", "#FFE4E1", "#DCDCDC", "#F0E68C" }; + + private static readonly Random _random = new Random(); + + /// + /// 字体池 + /// + private static Font[] _fontArr; + + public SecurityCodeHelper() + { + initFonts(_imageHeight); + } + + /// + /// 生成随机中文字符串 + /// + /// + /// + public string GetRandomCnText(int length) + { + StringBuilder sb = new StringBuilder(); + if (length > 0) + { + do + { + sb.Append(_cnTextArr[_random.Next(0, _cnTextArr.Length)]); + } + while (--length > 0); + } + return sb.ToString(); + } + + /// + /// 生成随机英文字母/数字组合字符串 + /// + /// + /// + public string GetRandomEnDigitalText(int length) + { + StringBuilder sb = new StringBuilder(); + if (length > 0) + { + do + { + if (_random.Next(0, 2) > 0) + { + sb.Append(_random.Next(2, 10)); + } + else + { + sb.Append(_enTextArr[_random.Next(0, _enTextArr.Length)]); + } + } + while (--length > 0); + } + return sb.ToString(); + } + + /// + /// 英文字母+数字组合验证码 + /// + /// + /// 验证码图片字节数组 + public byte[] GetEnDigitalCodeByte(string text) + { + using (Image img = getEnDigitalCodeImage(text)) + { + return img .ToGifArray(); + } + } + + + + /// + /// 生成一个数组组合验证码素材(Image) + /// + /// + /// + private Image getEnDigitalCodeImage(string text) + { + Image img = new Image(_imageWidth, _imageHeight); + var colorTextHex = _colorHexArr[_random.Next(0, _colorHexArr.Length)]; + var lignthColorHex = _lightColorHexArr[_random.Next(0, _lightColorHexArr.Length)]; + + img.Mutate(ctx => ctx + .Fill(Rgba32.ParseHex(_lightColorHexArr[_random.Next(0, _lightColorHexArr.Length)])) + .Glow(Rgba32.ParseHex(lignthColorHex)) + //.DrawingGrid(_imageWidth, _imageHeight, Rgba32.ParseHex(lignthColorHex), 8, 1) + .DrawText(text, _fontArr[0], Rgba32.ParseHex(_colorHexArr[0]),new PointF(0,0)) + //.DrawingEnText(, text, _colorHexArr, _fontArr) + .GaussianBlur(0.4f) + //.DrawingCircles(_imageWidth, _imageHeight, 15, _miniCircleR, _maxCircleR, Color.White) + ); + return img; + } + + /// + /// 初始化字体池 + /// + /// 一个初始大小 + private void initFonts(int fontSize) + { + if (_fontArr == null) + { + var assembly = Assembly.GetExecutingAssembly(); + var names = assembly.GetManifestResourceNames(); + + if (names?.Length > 0 == true) + { + var fontList = new List(); + var fontCollection = new FontCollection(); + + foreach (var name in names) + { + fontList.Add(new Font(fontCollection.Add(assembly.GetManifestResourceStream(name)), fontSize)); + } + + _fontArr = fontList.ToArray(); + } + else + { + throw new Exception($"绘制验证码字体文件加载失败"); + } + } + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/Candara.ttf b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/Candara.ttf new file mode 100644 index 00000000..dbc73697 Binary files /dev/null and b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/Candara.ttf differ diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/STCAIYUN.ttf b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/STCAIYUN.ttf new file mode 100644 index 00000000..f2c31b3a Binary files /dev/null and b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/STCAIYUN.ttf differ diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/impact.ttf b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/impact.ttf new file mode 100644 index 00000000..52701465 Binary files /dev/null and b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/impact.ttf differ diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/monbaiti.ttf b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/monbaiti.ttf new file mode 100644 index 00000000..64f759ff Binary files /dev/null and b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/HeiCaptcha/fonts/monbaiti.ttf differ diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/ImageSharpManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/ImageSharpManager.cs new file mode 100644 index 00000000..5c978345 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/ImageSharpManager.cs @@ -0,0 +1,64 @@ +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Processing; + +namespace Yi.Framework.ImageSharp; +public class ImageSharpManager +{ + public void ImageCompress(string fileName, Stream stream, string savePath) + { + var extensionName = Path.GetExtension(fileName).ToLower(); + if (extensionName == ".png") + { + PngImageCompress(stream, savePath); + } + else if (extensionName == ".jpg" || extensionName == ".jpeg") + { + JpgImageCompress(stream, savePath); + } + else + { + using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write)) + { + stream.CopyTo(fileStream); + } + } + + } + + public void PngImageCompress(Stream stream, string savePath) + { + using (var image = Image.Load(stream)) + { + var encoder = new PngEncoder() + { + CompressionLevel = PngCompressionLevel.Level6, + + }; + if (image.Width > 300) + { + image.Mutate(a => a.Resize(image.Width/2, image.Height/2)); + } + + image.Save(savePath, encoder); + } + } + public void JpgImageCompress(Stream stream, string savePath) + { + using (var image = Image.Load(stream)) + { + var encoder = new JpegEncoder() + { + Quality = 30 + }; + if (image.Width > 300) + { + image.Mutate(a => a.Resize(image.Width / 2, image.Height / 2)); + } + + + image.Save(savePath, encoder); + } + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/Yi.Framework.ImageSharp.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/Yi.Framework.ImageSharp.csproj new file mode 100644 index 00000000..dd60c1b7 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/Yi.Framework.ImageSharp.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/YiFrameworkImageSharpModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/YiFrameworkImageSharpModule.cs new file mode 100644 index 00000000..07a81b61 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.ImageSharp/YiFrameworkImageSharpModule.cs @@ -0,0 +1,25 @@ +using Hei.Captcha; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.ImageSharp +{ + public class YiFrameworkImageSharpModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddSingleton(); + services.AddHeiCaptcha(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/ExcelManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/ExcelManager.cs new file mode 100644 index 00000000..8241376c --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/ExcelManager.cs @@ -0,0 +1,47 @@ +using OEM.Core; + +namespace Yi.Framework.Office.Excel +{ + public class ExcelManager + { + private IExcelFactory _excelFactory; + public ExcelManager(IExcelFactory excelFactory) + { + _excelFactory = excelFactory; + } + + public List ReadListByNameManager(string path, string sheet) where T : class, new() + { + using (var excelAppService = _excelFactory.Create(System.IO.File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))) + { + return excelAppService.ReadListByNameManager(sheet); + } + } + + public T ReadByNameManager(string path, string sheet) where T : class, new() + { + using (var excelAppService = _excelFactory.Create(System.IO.File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))) + { + return excelAppService.ReadByNameManager(sheet); + } + } + + public void WriteListByNameManager(List objcts, string sheet, string oldPath, string newPath) where T : class, new() + { + using (var excelAppService = _excelFactory.Create(System.IO.File.Open(oldPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))) + { + excelAppService.WriteListByNameManager(objcts, sheet); + excelAppService.Write(newPath); + } + } + + public void WriteByNameManager(T objct, string sheet, string oldPath, string newPath) where T : class, new() + { + using (var excelAppService = _excelFactory.Create(System.IO.File.Open(oldPath, FileMode.OpenOrCreate, FileAccess.ReadWrite))) + { + excelAppService.WriteByNameManager(objct, sheet); + excelAppService.Write(newPath); + } + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/Yi.Framework.Office.Excel.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/Yi.Framework.Office.Excel.csproj new file mode 100644 index 00000000..4c47aa32 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/Yi.Framework.Office.Excel.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/YiFrameworkOfficeExcelModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/YiFrameworkOfficeExcelModule.cs new file mode 100644 index 00000000..8bf54446 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Office.Excel/YiFrameworkOfficeExcelModule.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; + +namespace Yi.Framework.Office.Excel +{ + [DependsOn( + typeof(YiFrameworkCoreModule) + )] + public class YiFrameworkOfficeExcelModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddExcelToObjectNpoiService(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/GlobalOperLogAttribute.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/GlobalOperLogAttribute.cs new file mode 100644 index 00000000..97ce9b78 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/GlobalOperLogAttribute.cs @@ -0,0 +1,99 @@ +using IPTools.Core; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.AspNetCore.Extensions; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Helper; +using Yi.Framework.Ddd.Repositories; + + +namespace Yi.Framework.OperLogManager +{ + public class GlobalOperLogAttribute : ActionFilterAttribute + { + private ILogger _logger; + private IRepository _repository; + private ICurrentUser _currentUser; + //注入一个日志服务 + public GlobalOperLogAttribute(ILogger logger, IRepository repository, ICurrentUser currentUser) + { + _logger = logger; + _repository = repository; + _currentUser = currentUser; + } + + public override async void OnResultExecuted(ResultExecutedContext context) + { + //判断标签是在方法上 + if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return; + + //查找标签,获取标签对象 + OperLogAttribute? operLogAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) + .FirstOrDefault(a => a.GetType().Equals(typeof(OperLogAttribute))) as OperLogAttribute; + //空对象直接返回 + if (operLogAttribute is null) return; + + ////获取控制器名 + //string controller = context.RouteData.Values["Controller"].ToString(); + + ////获取方法名 + //string action = context.RouteData.Values["Action"].ToString(); + + //获取Ip + string ip = context.HttpContext.GetClientIp(); + + //根据ip获取地址 + + var ipTool = IpTool.Search(ip); + string location = ipTool.Province + " " + ipTool.City; + + //日志服务插入一条操作记录即可 + + var logEntity = new OperationLogEntity(); + logEntity.Id = SnowflakeHelper.NextId; + logEntity.OperIp = ip; + //logEntity.OperLocation = location; + logEntity.OperType = operLogAttribute.OperType; + logEntity.Title = operLogAttribute.Title; + logEntity.RequestMethod = context.HttpContext.Request.Method; + logEntity.Method = context.HttpContext.Request.Path.Value; + logEntity.OperLocation = location; + + + logEntity.OperUser = _currentUser.UserName; + if (operLogAttribute.IsSaveResponseData) + { + if (context.Result is ContentResult result && result.ContentType == "application/json") + { + logEntity.RequestResult = result.Content?.Replace("\r\n", "").Trim(); + } + if (context.Result is JsonResult result2) + { + logEntity.RequestResult = result2.Value?.ToString(); + } + + if (context.Result is ObjectResult result3) + { + logEntity.RequestResult = JsonHelper.ObjToStr(result3.Value); + } + + } + + if (operLogAttribute.IsSaveRequestData) + { + //logEntity.RequestParam = context.HttpContext.GetRequestValue(logEntity.RequestMethod); + } + + await _repository.InsertAsync(logEntity); + + + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/IOperationLogService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/IOperationLogService.cs new file mode 100644 index 00000000..ccb3019b --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/IOperationLogService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Framework.OperLogManager +{ + /// + /// OperationLog服务抽象 + /// + public interface IOperationLogService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperEnum.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperEnum.cs new file mode 100644 index 00000000..1c8d0a13 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperEnum.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.OperLogManager +{ + public enum OperEnum + { + Insert = 1, + Update = 2, + Delete = 3, + Auth = 4, + Export = 5, + Import = 6, + ForcedOut = 7, + GenerateCode = 8, + ClearData = 9 + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperLogAttribute.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperLogAttribute.cs new file mode 100644 index 00000000..d9d3e4b9 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperLogAttribute.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.OperLogManager +{ + [AttributeUsage(AttributeTargets.Method)] + public class OperLogAttribute : Attribute + { + /// + /// 操作类型 + /// + public OperEnum OperType { get; set; } + + /// + /// 日志标题(模块) + /// + public string Title { get; set; } + + /// + /// 是否保存请求数据 + /// + public bool IsSaveRequestData { get; set; } = true; + + /// + /// 是否保存返回数据 + /// + public bool IsSaveResponseData { get; set; } = true; + + public OperLogAttribute(string title, OperEnum operationType) + { + Title = title; + OperType = operationType; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogEntity.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogEntity.cs new file mode 100644 index 00000000..7abf9962 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogEntity.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Framework.OperLogManager +{ + /// + /// 操作日志表 + /// + [SugarTable("OperationLog")] + public class OperationLogEntity : IEntity, ICreationAuditedObject + { + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] + public long Id { get; set; } + /// + /// 操作模块 + /// + [SugarColumn(ColumnName = "Title")] + public string? Title { get; set; } + /// + /// 操作类型 + /// + [SugarColumn(ColumnName = "OperType")] + public OperEnum OperType { get; set; } + /// + /// 请求方法 + /// + [SugarColumn(ColumnName = "RequestMethod")] + public string? RequestMethod { get; set; } + /// + /// 操作人员 + /// + [SugarColumn(ColumnName = "OperUser")] + public string? OperUser { get; set; } + /// + /// 操作Ip + /// + [SugarColumn(ColumnName = "OperIp")] + public string? OperIp { get; set; } + /// + /// 操作地点 + /// + [SugarColumn(ColumnName = "OperLocation")] + public string? OperLocation { get; set; } + /// + /// 操作方法 + /// + [SugarColumn(ColumnName = "Method")] + public string? Method { get; set; } + /// + /// 请求参数 + /// + [SugarColumn(ColumnName = "RequestParam")] + public string? RequestParam { get; set; } + /// + /// 请求结果 + /// + [SugarColumn(ColumnName = "RequestResult",Length =9999)] + public string? RequestResult { get; set; } + + public DateTime CreationTime { get; set; } + + public long? CreatorId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListInputVo.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListInputVo.cs new file mode 100644 index 00000000..7fecb292 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListInputVo.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.OperLogManager +{ + public class OperationLogGetListInputVo : PagedAllResultRequestDto + { + public OperEnum? OperType { get; set; } + public string? OperUser { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListOutputDto.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListOutputDto.cs new file mode 100644 index 00000000..11af25a2 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogGetListOutputDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Framework.OperLogManager +{ + public class OperationLogGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public string? Title { get; set; } + public OperEnum OperType { get; set; } + public string? RequestMethod { get; set; } + public string? OperUser { get; set; } + public string? OperIp { get; set; } + public string? OperLocation { get; set; } + public string? Method { get; set; } + public string? RequestParam { get; set; } + public string? RequestResult { get; set; } + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogService.cs new file mode 100644 index 00000000..de954789 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/OperationLogService.cs @@ -0,0 +1,36 @@ +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Core.Attributes; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Cike.AutoWebApi.Setting; + +namespace Yi.Framework.OperLogManager +{ + /// + /// OperationLog服务实现 + /// + //[AppService] + public class OperationLogService : CrudAppService, + IOperationLogService, IAutoApiService + { + public override async Task> GetListAsync(OperationLogGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.OperUser), x => x.OperUser.Contains(input.OperUser!)) + .WhereIF(input.OperType is not null, x => x.OperType==input.OperType) + .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + + [NonAction] + public override Task UpdateAsync(long id, OperationLogGetListOutputDto input) + { + return base.UpdateAsync(id, input); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/Yi.Framework.OperLogManager.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/Yi.Framework.OperLogManager.csproj new file mode 100644 index 00000000..a77b0b8f --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/Yi.Framework.OperLogManager.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/YiFrameworkOperLogManagerModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/YiFrameworkOperLogManagerModule.cs new file mode 100644 index 00000000..4c641b5d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.OperLogManager/YiFrameworkOperLogManagerModule.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Ddd; + +namespace Yi.Framework.OperLogManager +{ + [DependsOn( + typeof(YiFrameworkDddModule) + )] + public class YiFrameworkOperLogManagerModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + + services.AddControllers(options => + { + options.Filters.Add(); + }); + //services.AddAutoApiService(opt => + //{ + // //NETServiceTest所在程序集添加进动态api配置 + // opt.CreateConventional(typeof(YiFrameworkOperLogManagerModule).Assembly, option => option.RootPath = string.Empty); + + //}); + + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunManager.cs new file mode 100644 index 00000000..3884740b --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunManager.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AlibabaCloud.SDK.Dysmsapi20170525; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Tea; + +namespace Yi.Framework.Sms.Aliyun +{ + public class SmsAliyunManager + { + public Client AliyunClient { get; set; } + private ILogger _logger; + private SmsAliyunOptions Options { get; set; } + public SmsAliyunManager(ILogger logger, IOptions options) + { + Options = options.Value; + if (Options.EnableFeature) + { + _logger = logger; + AliyunClient = CreateClient(Options.AccessKeyId, Options.AccessKeySecret); + } + + } + + private static Client CreateClient(string accessKeyId, string accessKeySecret) + { + AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config + { + // 必填,您的 AccessKey ID + AccessKeyId = accessKeyId, + // 必填,您的 AccessKey Secret + AccessKeySecret = accessKeySecret, + }; + // 访问的域名 + config.Endpoint = "dysmsapi.aliyuncs.com"; + return new Client(config); + } + + + /// + /// 发送短信 + /// + /// + /// + /// + public async Task Send(string phoneNumbers, string code) + { + try + { + AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest + { + PhoneNumbers = phoneNumbers, + SignName = Options.SignName, + TemplateCode = Options.TemplateCode, + TemplateParam = System.Text.Json.JsonSerializer.Serialize(new { code }) + }; + + var response = await AliyunClient.SendSmsAsync(sendSmsRequest); + } + + catch (Exception _error) + { + _logger.LogError(_error, _error.Message); + } + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunOptions.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunOptions.cs new file mode 100644 index 00000000..3d5c2d7a --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/SmsAliyunOptions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Sms.Aliyun +{ + public class SmsAliyunOptions + { + public string AccessKeyId { get; set; } + public string AccessKeySecret { get; set; } + + public string SignName { get; set; } + + + public string TemplateCode { get; set; } + public bool EnableFeature { get; set; } = true; + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/Yi.Framework.Sms.Aliyun.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/Yi.Framework.Sms.Aliyun.csproj new file mode 100644 index 00000000..bb4208eb --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/Yi.Framework.Sms.Aliyun.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/YiFrameworkSmsAliyunModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/YiFrameworkSmsAliyunModule.cs new file mode 100644 index 00000000..049a5d33 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Sms.Aliyun/YiFrameworkSmsAliyunModule.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Configuration; + +namespace Yi.Framework.Sms.Aliyun +{ + [DependsOn(typeof(YiFrameworkCoreModule))] + public class YiFrameworkSmsAliyunModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.Configure(Appsettings.appConfiguration("SmsAliyunOptions")); + services.AddSingleton(); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/AbstractTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/AbstractTemplateProvider.cs new file mode 100644 index 00000000..cf35c614 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/AbstractTemplateProvider.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Template.Abstract +{ + public abstract class AbstractTemplateProvider : ITemplateProvider + { + public virtual string? BuildPath { get; set; } + public string? TemplatePath { get; set; } + public string? BakPath { get; set; } + protected Dictionary TemplateDic { get; set; } = new Dictionary(); + + public abstract void Bak(); + + public abstract void Build(); + + + protected virtual string GetTemplateData() + { + if (TemplatePath is null) + { + throw new ArgumentNullException(nameof(TemplatePath)); + } + return File.ReadAllText(TemplatePath); + } + + protected void AddTemplateDic(string oldStr, string newStr) + { + + TemplateDic.Add(oldStr, newStr); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ITemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ITemplateProvider.cs new file mode 100644 index 00000000..5ac81801 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ITemplateProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Template.Abstract +{ + public interface ITemplateProvider + { + /// + /// 构建生成路径 + /// + string? BuildPath { get; set; } + + /// + /// 模板文件路径 + /// + string? TemplatePath { get; set; } + + /// + /// 备份文件路径 + /// + string? BakPath { get; set; } + + + /// + /// 开始构建 + /// + /// + void Build(); + + /// + /// 生成备份 + /// + /// + void Bak(); + + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ModelTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ModelTemplateProvider.cs new file mode 100644 index 00000000..c538a61b --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ModelTemplateProvider.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Abstract +{ + public abstract class ModelTemplateProvider : ProgramTemplateProvider + { + + public ModelTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + AddIgnoreEntityField(/*"Id", */"TenantId", "IsDeleted", "LastModifierId", "LastModificationTime", "CreatorId"); + } + + private string entityPath=string.Empty; + + /// + /// 实体路径,该类生成需要实体与模板两个同时构建成 + /// + public string EntityPath + { + get => this.entityPath; + set + { + value = value!.Replace(TemplateConst.EntityName, EntityName); + value = value.Replace(TemplateConst.ModelName, ModelName); + this.entityPath = value; + } + } + + + /// + /// 生成模板忽略实体字段 + /// + private List IgnoreEntityFields { get; set; } = new(); + + public override void Build() + { + if (BuildPath is null) + { + throw new ArgumentNullException(nameof(BuildPath)); + } + //模板信息 + var templateData = GetTemplateData(); + + //实体信息 + var enetityDatas = GetEntityData().ToList(); + + //获取全部属性字段 + for (var i = enetityDatas.Count() - 1; i >= 0; i--) + { + //不是字段属性直接删除跳过 + if (!enetityDatas[i].Contains("{ get; set; }")) + { + enetityDatas.RemoveAt(i); + continue; + } + //是字段属性,同时还包含忽略字段 + bool IsSkip = false; + + foreach (var IgnoreEntityField in IgnoreEntityFields) + { + if (enetityDatas[i].Contains(IgnoreEntityField)) + { + enetityDatas.RemoveAt(i); + IsSkip=true; + break;; + } + } + + if (!IsSkip) + { + //以}结尾,不包含get不是属性,代表类结尾 + if (enetityDatas[i].EndsWith("}") && !enetityDatas[i].Contains("get")) + { + break; + } + } + + } + + //拼接实体字段 + var entityFieldsbuild = string.Join("\r\n", enetityDatas); + + + //模板替换属性字段 + templateData = templateData.Replace(TemplateConst.EntityField, entityFieldsbuild); + + templateData = base.ReplaceTemplateDic(templateData); + + if (!Directory.Exists(Path.GetDirectoryName(BuildPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(BuildPath)!); + } + File.WriteAllText(BuildPath, templateData); + } + + /// + /// 获取实体信息 + /// + /// + /// + public virtual string[] GetEntityData() + { + if (TemplatePath is null) + { + throw new ArgumentNullException(nameof(entityPath)); + } + if (!File.Exists(entityPath)) + { + throw new FileNotFoundException($"请检查路径:{entityPath}\r\n未包含实体:{EntityName}"); + } + + return File.ReadAllLines(entityPath); + } + + /// + /// 添加忽略实体字段 + /// + /// + public void AddIgnoreEntityField(params string[] field) + { + IgnoreEntityFields.AddRange(field); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ProgramTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ProgramTemplateProvider.cs new file mode 100644 index 00000000..f518eebe --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Abstract/ProgramTemplateProvider.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Abstract +{ + + public abstract class ProgramTemplateProvider : AbstractTemplateProvider + { + public ProgramTemplateProvider(string modelName, string entityName,string nameSpaces) + { + ModelName = modelName; + EntityName = entityName; + NameSpaces = nameSpaces; + base.AddTemplateDic(TemplateConst.NameSpaces, NameSpaces); + base.AddTemplateDic(TemplateConst.EntityName, EntityName); + base.AddTemplateDic(TemplateConst.ModelName, ModelName); + base.AddTemplateDic(TemplateConst.LowerEntityName, EntityName.Substring(0, 1).ToLower() + EntityName.Substring(1)); + base.AddTemplateDic(TemplateConst.LowerModelName, ModelName.ToLower()); + } + + + /// + /// 命名空间 + /// + public string NameSpaces { get; set; } + /// + /// 实体名称 + /// + public string EntityName { get; set; } + /// + /// 模块名称 + /// + public string ModelName { get; set; } + + /// + /// 重写构建路径,替换实体名称与模块名称 + /// + public override string? BuildPath + { + get => base.BuildPath; + set + { + value = ReplaceTemplateDic(value!); + + base.BuildPath = value; + } + } + + public string ReplaceTemplateDic(string str) + { + foreach (var ky in TemplateDic) + { + str = str.Replace(ky.Key, ky.Value); + } + return str; + } + + + public override void Build() + { + if (BuildPath is null) + { + throw new ArgumentNullException(nameof(BuildPath)); + } + var templateData = GetTemplateData(); + templateData = ReplaceTemplateDic(templateData); + if (!Directory.Exists(Path.GetDirectoryName(BuildPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(BuildPath)!); + } + File.WriteAllText(BuildPath, templateData); + } + + public override void Bak() + { + throw new NotImplementedException(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/ConstClasses/TemplateConst.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/ConstClasses/TemplateConst.cs new file mode 100644 index 00000000..fe8a32b4 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/ConstClasses/TemplateConst.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Template.ConstClasses +{ + public class TemplateConst + { + /// + /// 模块名称大写 + /// + public const string ModelName = "#ModelName#"; + + /// + /// 模块名称小写 + /// + public const string LowerModelName = "#LowerModelName#"; + + /// + /// 实体名称大驼峰 + /// + public const string EntityName = "#EntityName#"; + + /// + /// 实体名称小驼峰 + /// + public const string LowerEntityName = "#LowerEntityName#"; + + /// + /// 实体字段 + /// + public const string EntityField = "#EntityField#"; + + //public const string BuildRootPath = "../../../_Code"; + + + public const string NameSpaces = "#NameSpaces#"; + + public const string BuildRootPath = "../../../../../project/rbac"; + public const string BuildEntityPath = "../../../../../project/rbac"; + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Program.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Program.cs new file mode 100644 index 00000000..fa3bb2e9 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Program.cs @@ -0,0 +1,56 @@ +using Yi.Framework.Core.Helper; +using Yi.Framework.Template; +using Yi.Framework.Template.Provider.Server; +using Yi.Framework.Template.Provider.Site; + +TemplateFactory templateFactory = new(); + +//选择需要生成的模板提供者 + +//string modelName = "GlobalSetting"; +//string nameSpaces = "Yi.BBS"; +//List entityNames = new() { "Setting" }; + +//string modelName = "Exhibition"; +//string nameSpaces = "Yi.BBS"; +//List entityNames = new() { "Banner" }; +//string modelName = "Identity"; +//string nameSpaces = "Yi.RBAC"; +//List entityNames = new() { "_" }; +//string modelName = "Dictionary"; +//string nameSpaces = "Yi.RBAC"; +//List entityNames = new() { "_", "_" }; +//string modelName = "Setting"; +//string nameSpaces = "Yi.RBAC"; +//List entityNames = new() { "File" }; +string modelName = "Exhibition"; +string nameSpaces = "Yi.BBS"; +List entityNames = new() { "Agree" }; + +foreach (var entityName in entityNames) +{ + templateFactory.CreateTemplateProviders((option) => + { + option.Add(new ServiceTemplateProvider(modelName, entityName, nameSpaces)); + option.Add(new IServiceTemplateProvider(modelName, entityName, nameSpaces)); + + option.Add(new CreateInputVoTemplateProvider(modelName, entityName, nameSpaces)); + option.Add(new UpdateInputVoTemplateProvider(modelName, entityName, nameSpaces)); + option.Add(new GetListInputVoTemplateProvider(modelName, entityName, nameSpaces)); + option.Add(new GetListOutputDtoTemplateProvider(modelName, entityName, nameSpaces)); + option.Add(new GetOutputDtoTemplateProvider(modelName, entityName, nameSpaces)); + + option.Add(new ConstTemplateProvider(modelName, entityName, nameSpaces)); + //option.Add(new ApiTemplateProvider(modelName, entityName)); + }); + //开始构建模板 + templateFactory.BuildTemplate(); + Console.WriteLine($"Yi.Framework.Template:{entityName}构建完成!"); +} + +Console.WriteLine("Yi.Framework.Template:模板全部生成完成!"); +Console.ReadKey(); + +//根据模板文件生成项目文件 +//var template = "D:\\C#\\Yi\\Yi.Framework.Net6\\src\\project\\rbac"; +//FileHelper.AllInfoReplace(template, "Template", "RBAC"); \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ConstTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ConstTemplateProvider.cs new file mode 100644 index 00000000..d62cc481 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ConstTemplateProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + internal class ConstTemplateProvider : ProgramTemplateProvider + { + public ConstTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Domain.Shared\{TemplateConst.ModelName}\ConstClasses\{TemplateConst.EntityName}Const.cs"; + TemplatePath = $@"..\..\..\Template\Server\ConstTemplate.txt"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/CreateInputVoTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/CreateInputVoTemplateProvider.cs new file mode 100644 index 00000000..77ae54aa --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/CreateInputVoTemplateProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class CreateInputVoTemplateProvider : ModelTemplateProvider + { + public CreateInputVoTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\Dtos\{TemplateConst.EntityName}\{TemplateConst.EntityName}CreateInputVo.cs"; + TemplatePath = $@"..\..\..\Template\Server\CreateInputVoTemplate.txt"; + EntityPath = $@"{TemplateConst.BuildEntityPath}\{nameSpaces}.Domain\{TemplateConst.ModelName}\Entities\{TemplateConst.EntityName}Entity.cs"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListInputVoTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListInputVoTemplateProvider.cs new file mode 100644 index 00000000..01b31e5c --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListInputVoTemplateProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class GetListInputVoTemplateProvider : ModelTemplateProvider + { + public GetListInputVoTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\Dtos\{TemplateConst.EntityName}\{TemplateConst.EntityName}GetListInputVo.cs"; + TemplatePath = $@"..\..\..\Template\Server\GetListInputVoTemplate.txt"; + EntityPath = $@"{TemplateConst.BuildEntityPath}\{nameSpaces}.Domain\{TemplateConst.ModelName}\Entities\{TemplateConst.EntityName}Entity.cs"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListOutputDtoTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListOutputDtoTemplateProvider.cs new file mode 100644 index 00000000..b36f9f97 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetListOutputDtoTemplateProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class GetListOutputDtoTemplateProvider : ModelTemplateProvider + { + public GetListOutputDtoTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\Dtos\{TemplateConst.EntityName}\{TemplateConst.EntityName}GetListOutputDto.cs"; + TemplatePath = $@"..\..\..\Template\Server\GetListOutputDtoTemplate.txt"; + EntityPath = $@"{TemplateConst.BuildEntityPath}\{nameSpaces}.Domain\{TemplateConst.ModelName}\Entities\{TemplateConst.EntityName}Entity.cs"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetOutputDtoTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetOutputDtoTemplateProvider.cs new file mode 100644 index 00000000..79ba9a0d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/GetOutputDtoTemplateProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class GetOutputDtoTemplateProvider : ModelTemplateProvider + { + public GetOutputDtoTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\Dtos\{TemplateConst.EntityName}\{TemplateConst.EntityName}GetOutputDto.cs"; + TemplatePath = $@"..\..\..\Template\Server\GetOutputDtoTemplate.txt"; + EntityPath = $@"{TemplateConst.BuildEntityPath}\{nameSpaces}.Domain\{TemplateConst.ModelName}\Entities\{TemplateConst.EntityName}Entity.cs"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/IServiceTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/IServiceTemplateProvider.cs new file mode 100644 index 00000000..2228dbc4 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/IServiceTemplateProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class IServiceTemplateProvider : ProgramTemplateProvider + { + public IServiceTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\I{TemplateConst.EntityName}Service.cs"; + TemplatePath = $@"..\..\..\Template\Server\IServiceTemplate.txt"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ServiceTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ServiceTemplateProvider.cs new file mode 100644 index 00000000..6bdcaa61 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/ServiceTemplateProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class ServiceTemplateProvider : ProgramTemplateProvider + { + public ServiceTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application\{TemplateConst.ModelName}\{TemplateConst.EntityName}Service.cs"; + TemplatePath = $@"..\..\..\Template\Server\ServiceTemplate.txt"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/UpdateInputVoTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/UpdateInputVoTemplateProvider.cs new file mode 100644 index 00000000..981a9449 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Server/UpdateInputVoTemplateProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Server +{ + public class UpdateInputVoTemplateProvider : ModelTemplateProvider + { + public UpdateInputVoTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"{TemplateConst.BuildRootPath}\{nameSpaces}.Application.Contracts\{TemplateConst.ModelName}\Dtos\{TemplateConst.EntityName}\{TemplateConst.EntityName}UpdateInputVo.cs"; + TemplatePath = $@"..\..\..\Template\Server\UpdateInputVoTemplate.txt"; + EntityPath = $@"{TemplateConst.BuildEntityPath}\{nameSpaces}.Domain\{TemplateConst.ModelName}\Entities\{TemplateConst.EntityName}Entity.cs"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Site/ApiTemplateProvider.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Site/ApiTemplateProvider.cs new file mode 100644 index 00000000..b0865456 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Provider/Site/ApiTemplateProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.ConstClasses; + +namespace Yi.Framework.Template.Provider.Site +{ + public class ApiTemplateProvider : ProgramTemplateProvider + { + public ApiTemplateProvider(string modelName, string entityName, string nameSpaces) : base(modelName, entityName, nameSpaces) + { + BuildPath = $@"..\..\..\Code_Site\src\api\{TemplateConst.LowerModelName}\{TemplateConst.LowerEntityName}Api.js"; + TemplatePath = $@"..\..\..\Template\Site\ApiTemplate.txt"; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ConstTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ConstTemplate.txt new file mode 100644 index 00000000..8a30baa2 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ConstTemplate.txt @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace #NameSpaces#.Domain.Shared.#ModelName#.ConstClasses +{ + /// + /// 常量定义 + /// + + public class #EntityName#Const + { + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/CreateInputVoTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/CreateInputVoTemplate.txt new file mode 100644 index 00000000..1b9740eb --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/CreateInputVoTemplate.txt @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace #NameSpaces#.Application.Contracts.#ModelName#.Dtos +{ + /// + /// #EntityName#输入创建对象 + /// + public class #EntityName#CreateInputVo + { +#EntityField# + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListInputVoTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListInputVoTemplate.txt new file mode 100644 index 00000000..0a5224ac --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListInputVoTemplate.txt @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace #NameSpaces#.Application.Contracts.#ModelName#.Dtos +{ + public class #EntityName#GetListInputVo : PagedAndSortedResultRequestDto + { +#EntityField# + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListOutputDtoTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListOutputDtoTemplate.txt new file mode 100644 index 00000000..5c44adec --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetListOutputDtoTemplate.txt @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace #NameSpaces#.Application.Contracts.#ModelName#.Dtos +{ + public class #EntityName#GetListOutputDto : IEntityDto + { +#EntityField# + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetOutputDtoTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetOutputDtoTemplate.txt new file mode 100644 index 00000000..05eda43a --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/GetOutputDtoTemplate.txt @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace #NameSpaces#.Application.Contracts.#ModelName#.Dtos +{ + public class #EntityName#GetOutputDto : IEntityDto + { +#EntityField# + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/IServiceTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/IServiceTemplate.txt new file mode 100644 index 00000000..1142b1b5 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/IServiceTemplate.txt @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using #NameSpaces#.Application.Contracts.#ModelName#.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace #NameSpaces#.Application.Contracts.#ModelName# +{ + /// + /// #EntityName#服务抽象 + /// + public interface I#EntityName#Service : ICrudAppService<#EntityName#GetOutputDto, #EntityName#GetListOutputDto, long, #EntityName#GetListInputVo, #EntityName#CreateInputVo, #EntityName#UpdateInputVo> + { + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ProfileTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ProfileTemplate.txt new file mode 100644 index 00000000..95ea4f7d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ProfileTemplate.txt @@ -0,0 +1,23 @@ +using AutoMapper; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using #NameSpaces#.Application.Contracts.#ModelName#.Dtos; +using #NameSpaces#.Domain.#ModelName#.Entities; + +namespace #NameSpaces#.Application.#ModelName#.MapperConfig +{ + public class #EntityName#Profile: Profile + { + public #EntityName#Profile() + { + CreateMap<#EntityName#GetListInputVo, #EntityName#Entity>(); + CreateMap<#EntityName#CreateInputVo, #EntityName#Entity>(); + CreateMap<#EntityName#UpdateInputVo, #EntityName#Entity>(); + CreateMap<#EntityName#Entity, #EntityName#GetListOutputDto>(); + CreateMap<#EntityName#Entity, #EntityName#GetOutputDto>(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ServiceTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ServiceTemplate.txt new file mode 100644 index 00000000..9daff1d8 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/ServiceTemplate.txt @@ -0,0 +1,17 @@ +using #NameSpaces#.Application.Contracts.#ModelName#; +using Cike.AutoWebApi.Setting; +using #NameSpaces#.Application.Contracts.#ModelName#.Dtos; +using #NameSpaces#.Domain.#ModelName#.Entities; +using Yi.Framework.Ddd.Services; + +namespace #NameSpaces#.Application.#ModelName# +{ + /// + /// #EntityName#服务实现 + /// + [AppService] + public class #EntityName#Service : CrudAppService<#EntityName#Entity, #EntityName#GetOutputDto, #EntityName#GetListOutputDto, long, #EntityName#GetListInputVo, #EntityName#CreateInputVo, #EntityName#UpdateInputVo>, + I#EntityName#Service, IAutoApiService + { + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/UpdateInputVoTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/UpdateInputVoTemplate.txt new file mode 100644 index 00000000..c727b790 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Server/UpdateInputVoTemplate.txt @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace #NameSpaces#.Application.Contracts.#ModelName#.Dtos +{ + public class #EntityName#UpdateInputVo + { +#EntityField# + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Site/ApiTemplate.txt b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Site/ApiTemplate.txt new file mode 100644 index 00000000..dc12e694 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Template/Site/ApiTemplate.txt @@ -0,0 +1,45 @@ +import request from '@/utils/request' + +// 分页查询 +export function listData(query) { + return request({ + url: '/#LowerEntityName#/pageList', + method: 'get', + params: query + }) +} + +// id查询 +export function getData(code) { + return request({ + url: '/#LowerEntityName#/getById/' + code, + method: 'get' + }) +} + +// 新增 +export function addData(data) { + return request({ + url: '/#LowerEntityName#/create', + method: 'post', + data: data + }) +} + +// 修改 +export function updateData(id,data) { + return request({ + url: `/#LowerEntityName#/update/${id}`, + method: 'put', + data: data + }) +} + +// 删除 +export function delData(code) { + return request({ + url: '/#LowerEntityName#/del', + method: 'delete', + data:"string"==typeof(code)?[code]:code + }) +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/TemplateFactory.cs b/Yi.Framework.Net6/src/module/Yi.Framework.Template/TemplateFactory.cs new file mode 100644 index 00000000..2196a913 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/TemplateFactory.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Template.Abstract; +using Yi.Framework.Template.Provider; + +namespace Yi.Framework.Template +{ + public class TemplateFactory + { + private List _templateProviders=new List(); + + public void CreateTemplateProviders(Action> action) + { + action(_templateProviders); + } + + public void BuildTemplate() + { + foreach (var provider in _templateProviders) + { + provider.Build(); + } + } + + public void BakTemplate() + { + foreach (var provider in _templateProviders) + { + provider.Bak(); + } + } + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.Template/Yi.Framework.Template.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Yi.Framework.Template.csproj new file mode 100644 index 00000000..c350d3b8 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.Template/Yi.Framework.Template.csproj @@ -0,0 +1,47 @@ + + + + net6.0 + enable + enable + Exe + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/IPayConfig.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/IPayConfig.cs new file mode 100644 index 00000000..ebb47aea --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/IPayConfig.cs @@ -0,0 +1,67 @@ +using System; + +namespace Yi.Framework.WeChatPay.Domain.Config +{ + /// + /// IConfig + /// + public interface IPayConfig + { + + //=======【基本信息设置】===================================== + /* 微信公众号信息配置 + * APPID:绑定支付的APPID(必须配置) + * MCHID:商户号(必须配置) + * KEY:商户支付密钥,参考开户邮件设置(必须配置),请妥善保管,避免密钥泄露 + * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置),请妥善保管,避免密钥泄露 + */ + + string GetAppID(); + string GetMchID(); + string GetKey(); + string GetAppSecret(); + + + + //=======【证书路径设置】===================================== + /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要) + * 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载; + * 2.建议将证书文件名改为复杂且不容易猜测的文件 + * 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。 + */ + string GetSSlCertPath(); + string GetSSlCertPassword(); + + + + //=======【支付结果通知url】===================================== + /* 支付结果通知回调url,用于商户接收支付结果 + */ + string GetNotifyUrl(); + + //=======【商户系统后台机器IP】===================================== + /* 此参数可手动配置也可在程序中自动获取 + */ + string GetIp(); + + + //=======【代理服务器设置】=================================== + /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置) + */ + string GetProxyUrl(); + + + //=======【上报信息配置】=================================== + /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报 + */ + int GetReportLevel(); + + + //=======【日志级别】=================================== + /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息 + */ + int GetLogLevel(); + + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/PayConfig.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/PayConfig.cs new file mode 100644 index 00000000..5f4caa96 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Config/PayConfig.cs @@ -0,0 +1,108 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using Microsoft.Extensions.Configuration; +using Yi.Framework.WeChatPay.Options; + +namespace Yi.Framework.WeChatPay.Domain.Config +{ + public class PayConfig : IPayConfig + { + public static PayConfig Current = null; + + public PayConfig(PayOptions payOptions) + { + Current = this; + _BasicConfig = payOptions; + } + + private static PayOptions _BasicConfig = null; + + + //=======【基本信息设置】===================================== + /* 微信公众号信息配置 + * APPID:绑定支付的APPID(必须配置) + * MCHID:商户号(必须配置) + * KEY:商户支付密钥,参考开户邮件设置(必须配置),请妥善保管,避免密钥泄露 + * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置),请妥善保管,避免密钥泄露 + */ + + public string GetAppID() + { + return _BasicConfig.AppID; + } + public string GetMchID() + { + return _BasicConfig.MchID; + } + public string GetKey() + { + return _BasicConfig.Key; + } + public string GetAppSecret() + { + return ""; + } + + + + //=======【证书路径设置】===================================== + /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要) + * 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载; + * 2.建议将证书文件名改为复杂且不容易猜测的文件 + * 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。 + */ + public string GetSSlCertPath() + { + return ""; + } + public string GetSSlCertPassword() + { + return ""; + } + + + + //=======【支付结果通知url】===================================== + /* 支付结果通知回调url,用于商户接收支付结果 + */ + public string GetNotifyUrl() + { + return _BasicConfig.NotifyUrl; + } + + //=======【商户系统后台机器IP】===================================== + /* 此参数可手动配置也可在程序中自动获取 + */ + public string GetIp() + { + return "0.0.0.0"; + } + + //=======【代理服务器设置】=================================== + /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置) + */ + public string GetProxyUrl() + { + return ""; + } + + + //=======【上报信息配置】=================================== + /* 测速上报等级,0.关闭上报; 1.仅错误时上报; 2.全量上报 + */ + public int GetReportLevel() + { + return 1; + } + + + //=======【日志级别】=================================== + /* 日志等级,0.不输出日志;1.只输出错误信息; 2.输出错误和正常信息; 3.输出错误信息、正常信息和调试信息 + */ + public int GetLogLevel() + { + return 1; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/IPayManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/IPayManager.cs new file mode 100644 index 00000000..d4014eeb --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/IPayManager.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Helper; + +namespace Yi.Framework.WeChatPay.Domain +{ + public interface IPayManager + { + /// + /// 获取WX支付链接的方法 + /// 然后发布定时同步状态任务 + /// + /// 订单ID + /// 用户信息 + /// 请求上下文 + /// 返回生成的支持链接 + string GenerateUrl(long orderId, long totalPay); + /// + /// 处理微信支付回调 + /// + /// + /// + PayData HandleNotify(); + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/AbstractNotify.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/AbstractNotify.cs new file mode 100644 index 00000000..b682fb64 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/AbstractNotify.cs @@ -0,0 +1,73 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Exceptions; +using Yi.Framework.WeChatPay.Helper; + +namespace Yi.Framework.WeChatPay.Domain.Notify +{ + public abstract class AbstractNotify + { + protected HttpContext _httpContext; + + public AbstractNotify(IHttpContextAccessor httpContextAccessor) + { + _httpContext = httpContextAccessor.HttpContext; + } + + /// + /// 从请求对象中获取信息 + /// + /// + /// + /// + private async Task GetRawBodyStringAsync(HttpRequest request, Encoding encoding = null) + { + if (encoding is null) + { + encoding = Encoding.UTF8; + } + var stream = new MemoryStream(); + await request.Body.CopyToAsync(stream); + stream.Seek(0, 0); + using (var reader = new StreamReader(stream, encoding)) + { + var result = await reader.ReadToEndAsync(); + return result; + } + } + + /// + /// 接收从微信支付后台发送过来的数据并验证签名 + /// + /// 微信支付后台返回的数据 + public PayData GetNotifyData() + { + //接收从微信后台POST过来的数据 + string content = GetRawBodyStringAsync(_httpContext.Request).Result; + Console.WriteLine(GetType().ToString(), "Receive data from WeChat : " + content); + + //转换数据格式并验证签名 + PayData data = new PayData(); + try + { + data.FromXml(content); + } + catch (PayException ex) + { + throw new Exception("验签失败", ex); + } + + Console.WriteLine(GetType().ToString(), "Check sign success"); + return data; + } + + //派生类需要重写这个方法,进行不同的回调处理 + public abstract PayData ProcessNotify(); + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/ResultNotify.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/ResultNotify.cs new file mode 100644 index 00000000..8b967b33 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/Notify/ResultNotify.cs @@ -0,0 +1,102 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Yi.Framework.WeChatPay.Helper; + +namespace Yi.Framework.WeChatPay.Domain.Notify +{ + public class ResultNotify : AbstractNotify + { + private readonly PayApi _PayApi; + private readonly ILogger _logger; + public ResultNotify(PayApi PayApi, ILogger logger, IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor) + { + _PayApi = PayApi; + _logger = logger; + } + + /// + /// 处理支付回调 + /// + /// + public override PayData ProcessNotify() + { + PayData notifyData = GetNotifyData(); + //解析数据 + string totalFee = notifyData.GetValue("total_fee").ToString(); //订单金额 + string outTradeNo = notifyData.GetValue("out_trade_no").ToString(); //订单编号 + string transactionId = notifyData.GetValue("transaction_id").ToString(); //商户订单号 + string bankType = notifyData.GetValue("bank_type").ToString(); //银行类型 + + _logger.LogInformation($"======支付回调参数:{totalFee}=={outTradeNo}=={transactionId}=={bankType}"); + if (totalFee.Equals("") || outTradeNo.Equals("") || transactionId.Equals("") || bankType.Equals("")) + { + PayData res = new(); + res.SetValue("return_code", "FAIL"); + res.SetValue("return_msg", "支付回调返回数据不正确"); + _logger.LogInformation("支付错误结果 : " + res.ToXml()); + return res; + } + + //检查支付结果中transaction_id是否存在--流水号 + if (!notifyData.IsSet("transaction_id")) + { + //若transaction_id不存在,则立即返回结果给微信支付后台 + PayData res = new(); + res.SetValue("return_code", "FAIL"); + res.SetValue("return_msg", "支付结果中微信订单号不存在"); + _logger.LogInformation("支付错误结果 : " + res.ToXml()); + + return res; + } + + //查询订单,判断订单真实性 + if (!QueryOrder(transactionId)) + { + //若订单查询失败,则立即返回结果给微信支付后台 + PayData res = new(); + res.SetValue("return_code", "FAIL"); + res.SetValue("return_msg", "订单查询失败"); + _logger.LogInformation("订单查询失败 : " + res.ToXml()); + + return res; + } + //查询订单成功 + else + { + // 打印结果 (仅打印) + PayData res = new PayData(); + res.SetValue("return_code", "SUCCESS"); + res.SetValue("return_msg", "OK"); + res.SetValue("transaction_id", transactionId); + _logger.LogInformation("订单查成功: " + res.ToXml()); + + // 设置返回响应结果 + notifyData.SetValue("return_code", "SUCCESS"); + notifyData.SetValue("return_msg", "OK"); + + return notifyData; + } + } + + /// + /// 根据流水号查询订单信息 + /// + /// + /// + private bool QueryOrder(string transaction_id) + { + PayData req = new PayData(); + req.SetValue("transaction_id", transaction_id); + PayData res = _PayApi.OrderQuery(req, _httpContext); + if (res.GetValue("return_code").ToString() == "SUCCESS" && + res.GetValue("result_code").ToString() == "SUCCESS") + { + return true; + } + else + { + return false; + } + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/PayManager.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/PayManager.cs new file mode 100644 index 00000000..901e1843 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Domain/PayManager.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Domain.Notify; +using Yi.Framework.WeChatPay.Helper; +using Yi.Framework.WeChatPay.Options; + +namespace Yi.Framework.WeChatPay.Domain +{ + public class PayManager : IPayManager + { + private readonly PayHelper _payHelper; + private readonly ILogger _logger; + private readonly AbstractNotify _notify; + + public PayManager(PayHelper payHelper, ILogger logger, AbstractNotify notify) + { + _payHelper = payHelper; + _logger = logger; + _notify = notify; + } + + /// + /// 获取WX支付链接的方法 + /// 然后发布定时同步状态任务 + /// + /// 订单ID + /// 用户信息 + /// 请求上下文 + /// 返回生成的支持链接 + public string GenerateUrl(long orderId, long totalPay) + { + string payUrl = null; + _logger.LogInformation("准备生成支付链接....."); + payUrl = _payHelper.CreatePayUrl(orderId, "微信支付链接", totalPay); + _logger.LogInformation("生成支付链接为:{payUrl}", payUrl); + return payUrl; + } + + /// + /// 处理微信支付回调 + /// + /// + /// + public PayData HandleNotify() + { + PayData wxPayData = _notify.ProcessNotify(); + + return wxPayData; + } + + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Exceptions/PayException.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Exceptions/PayException.cs new file mode 100644 index 00000000..2aafe37d --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Exceptions/PayException.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Serialization; + +namespace Yi.Framework.WeChatPay.Exceptions +{ + [Serializable] + public class PayException : Exception + { + public PayException() + { + } + + public PayException(string message) : base(message) + { + } + + public PayException(string message, Exception innerException) : base(message, innerException) + { + } + + protected PayException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Extensions/PayServiceExtensions.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Extensions/PayServiceExtensions.cs new file mode 100644 index 00000000..f8451a7e --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Extensions/PayServiceExtensions.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Domain; +using Yi.Framework.WeChatPay.Domain.Config; +using Yi.Framework.WeChatPay.Domain.Notify; +using Yi.Framework.WeChatPay.Exceptions; +using Yi.Framework.WeChatPay.Helper; +using Yi.Framework.WeChatPay.Options; + +namespace Yi.Framework.WeChatPay.Extensions +{ + public static class PayServiceExtensions + { + public static IServiceCollection AddWeChatPayServer(this IServiceCollection services, Action configure) + { + var option = new PayOptions(); + configure(option); + if (option.IsFileConfig) + { + option = PayHelper.GetPayOptions(option.ConfigPath); + } + if (option.AppID == null) + { + throw new PayException("AppId为空值"); + } + if (option.MchID == null) + { + throw new PayException("MchID为空值"); + } + if (option.Key == null) + { + throw new PayException("Key为空值"); + } + if (option.NotifyUrl == null) + { + throw new PayException("NotifyUrl为空值"); + } + services.AddSingleton(option); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddHttpContextAccessor(); + return services; + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayApi.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayApi.cs new file mode 100644 index 00000000..855cf373 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayApi.cs @@ -0,0 +1,139 @@ +using FizzWare.NBuilder; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Domain.Config; +using Yi.Framework.WeChatPay.Exceptions; + +namespace Yi.Framework.WeChatPay.Helper +{ + public class PayApi + { + private readonly IPayConfig _IPayConfig = null; + private readonly PayHttpService _PayHttpService = null; + public PayApi(IPayConfig payConfig, PayHttpService payHttpService) + { + _IPayConfig = payConfig; + _PayHttpService = payHttpService; + } + + /** + * + * 统一下单 + * @param WxPaydata inputObj 提交给统一下单API的参数 + * @param int timeOut 超时时间 + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public PayData UnifiedOrder(PayData inputObj, int timeOut = 6) + { + string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + //检测必填参数 + if (!inputObj.IsSet("out_trade_no")) + { + throw new PayException("缺少统一支付接口必填参数out_trade_no!"); + } + else if (!inputObj.IsSet("body")) + { + throw new PayException("缺少统一支付接口必填参数body!"); + } + else if (!inputObj.IsSet("total_fee")) + { + throw new PayException("缺少统一支付接口必填参数total_fee!"); + } + else if (!inputObj.IsSet("trade_type")) + { + throw new PayException("缺少统一支付接口必填参数trade_type!"); + } + + //关联参数 + if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid")) + { + throw new PayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); + } + if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id")) + { + throw new PayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); + } + + //异步通知url未设置,则使用配置文件中的url + /*if (!inputObj.IsSet("notify_url")) + { + inputObj.SetValue("notify_url", this._IWxPayConfig().GetNotifyUrl());//异步通知url + }*/ + + inputObj.SetValue("appid", _IPayConfig.GetAppID());//公众账号ID + inputObj.SetValue("mch_id", _IPayConfig.GetMchID());//商户号 + inputObj.SetValue("spbill_create_ip", _IPayConfig.GetIp());//终端ip + inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 + inputObj.SetValue("sign_type", PayData.SIGN_TYPE_HMAC_SHA256);//签名类型 + + //签名 + inputObj.SetValue("sign", inputObj.MakeSign()); + string xml = inputObj.ToXml(); + // 发起http请求 + string response = _PayHttpService.Post(xml, url, false, timeOut); + PayData result = new PayData(); + result.FromXml(response); + + return result; + } + + /** + * + * 查询订单 + * @param WxPayData inputObj 提交给查询订单API的参数 + * @param int timeOut 超时时间 + * @throws WxPayException + * @return 成功时返回订单查询结果,其他抛异常 + */ + public PayData OrderQuery(PayData inputObj, HttpContext httpContext, int timeOut = 6) + { + string url = "https://api.mch.weixin.qq.com/pay/orderquery"; + //检测必填参数 + if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id")) + { + throw new PayException("订单查询接口中,out_trade_no、transaction_id至少填一个!"); + } + + inputObj.SetValue("appid", _IPayConfig.GetAppID());//公众账号ID + inputObj.SetValue("mch_id", _IPayConfig.GetMchID());//商户号 + inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串 + inputObj.SetValue("sign_type", PayData.SIGN_TYPE_HMAC_SHA256);//签名类型 + inputObj.SetValue("sign", inputObj.MakeSign());//签名 + string xml = inputObj.ToXml(); + //Log.Debug("WxPayApi", "OrderQuery request : " + xml); + string response = _PayHttpService.Post(xml, url, false, timeOut);//调用HTTP通信接口提交数据 + //Log.Debug("WxPayApi", "OrderQuery response : " + response); + + //将xml格式的数据转化为对象以返回 + PayData result = new PayData(); + result.FromXml(response); + + return result; + } + + /** + * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 + * @return 时间戳 + */ + public static string GenerateTimeStamp() + { + TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); + return Convert.ToInt64(ts.TotalSeconds).ToString(); + } + + /** + * 生成随机串,随机串包含字母或数字 + * @return 随机串 + */ + public static string GenerateNonceStr() + { + RandomGenerator randomGenerator = new RandomGenerator(); + return randomGenerator.Int().ToString(); + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayData.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayData.cs new file mode 100644 index 00000000..92164ba5 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayData.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Xml; +using System.Security.Cryptography; +using System.Text; +using System.Linq; +using Newtonsoft.Json; +using Yi.Framework.WeChatPay.Domain.Config; + +namespace Yi.Framework.WeChatPay.Helper +{ + /// + /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构, + /// 在调用接口之前先填充各个字段的值,然后进行接口通信, + /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构, + /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构 + /// + public class PayData + { + public const string SIGN_TYPE_MD5 = "MD5"; + public const string SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256"; + + + //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序 + private SortedDictionary m_values = new SortedDictionary(); + + /** + * 设置某个字段的值 + * @param key 字段名 + * @param value 字段值 + */ + public void SetValue(string key, object value) + { + m_values[key] = value; + } + + /** + * 根据字段名获取某个字段的值 + * @param key 字段名 + * @return key对应的字段值 + */ + public object GetValue(string key) + { + object o = null; + m_values.TryGetValue(key, out o); + return o; + } + + /** + * 判断某个字段是否已设置 + * @param key 字段名 + * @return 若字段key已被设置,则返回true,否则返回false + */ + public bool IsSet(string key) + { + object o = null; + m_values.TryGetValue(key, out o); + if (null != o && !o.Equals("")) + return true; + else + return false; + } + + /** + * @将Dictionary转成xml + * @return 经转换得到的xml串 + * @throws WxPayException + **/ + public string ToXml() + { + //数据为空时不能转化为xml格式 + if (0 == m_values.Count) + { + throw new Exception("WxPayData数据为空!"); + } + + string xml = ""; + foreach (KeyValuePair pair in m_values) + { + //字段值不能为null,会影响后续流程 + if (pair.Value == null) + { + throw new Exception("WxPayData内部含有值为null的字段!"); + } + + if (pair.Value.GetType() == typeof(int)) + { + xml += "<" + pair.Key + ">" + pair.Value + ""; + } + else if (pair.Value.GetType() == typeof(string)) + { + xml += "<" + pair.Key + ">" + ""; + } + else//除了string和int类型不能含有其他数据类型 + { + throw new Exception("WxPayData字段数据类型错误!"); + } + } + xml += ""; + return xml; + } + + /** + * @将xml转为WxPayData对象并返回对象内部的数据 + * @param string 待转换的xml串 + * @return 经转换得到的Dictionary + * @throws WxPayException + */ + public SortedDictionary FromXml(string xml) + { + if (string.IsNullOrEmpty(xml)) + { + throw new Exception("将空的xml串转换为WxPayData不合法!"); + } + + + SafeXmlDocument xmlDoc = new SafeXmlDocument(); + xmlDoc.LoadXml(xml); + XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点 + XmlNodeList nodes = xmlNode.ChildNodes; + foreach (XmlNode xn in nodes) + { + XmlElement xe = (XmlElement)xn; + m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中 + } + + try + { + //2015-06-29 错误是没有签名 + if (m_values["return_code"].ToString() != "SUCCESS") + { + return m_values; + } + //验证签名,不通过会抛异常 + CheckSign(); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + return m_values; + } + + /** + * @Dictionary格式转化成url参数格式 + * @ return url格式串, 该串不包含sign字段值 + */ + public string ToUrl() + { + string buff = ""; + foreach (KeyValuePair pair in m_values) + { + if (pair.Value == null) + { + throw new Exception("WxPayData内部含有值为null的字段!"); + } + + if (pair.Key != "sign" && pair.Value.ToString() != "") + { + buff += pair.Key + "=" + pair.Value + "&"; + } + } + + buff = buff.Trim('&'); + return buff; + } + + + /** + * @Dictionary格式化成Json + * @return json串数据 + */ + public string ToJson() + { + string jsonStr = JsonConvert.SerializeObject(m_values); + return jsonStr; + + } + + /** + * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串) + */ + public string ToPrintStr() + { + string str = ""; + foreach (KeyValuePair pair in m_values) + { + if (pair.Value == null) + { + throw new Exception("WxPayData内部含有值为null的字段!"); + } + + + str += string.Format("{0}={1}\n", pair.Key, pair.Value.ToString()); + } + str = HttpUtility.HtmlEncode(str); + return str; + } + + + /** + * @生成签名,详见签名生成算法 + * @return 签名, sign字段不参加签名 + */ + public string MakeSign(string signType) + { + //转url格式 + string str = ToUrl(); + //在string后加入API KEY + string apiKey = PayConfig.Current.GetKey(); + str += "&key=" + apiKey; + if (signType == SIGN_TYPE_MD5) + { + var md5 = MD5.Create(); + var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); + var sb = new StringBuilder(); + foreach (byte b in bs) + { + sb.Append(b.ToString("x2")); + } + //所有字符转为大写 + return sb.ToString().ToUpper(); + } + else if (signType == SIGN_TYPE_HMAC_SHA256) + { + return CalcHMACSHA256Hash(str, apiKey); + } + else + { + throw new Exception("sign_type 不合法"); + } + } + + /** + * @生成签名,详见签名生成算法 + * @return 签名, sign字段不参加签名 SHA256 + */ + public string MakeSign() + { + return MakeSign(SIGN_TYPE_HMAC_SHA256); + } + + + + /** + * + * 检测签名是否正确 + * 正确返回true,错误抛异常 + */ + public bool CheckSign(string signType) + { + //如果没有设置签名,则跳过检测 + if (!IsSet("sign")) + { + throw new Exception("WxPayData签名存在但不合法!"); + } + //如果设置了签名但是签名为空,则抛异常 + else if (GetValue("sign") == null || GetValue("sign").ToString() == "") + { + throw new Exception("WxPayData签名存在但不合法!"); + } + + //获取接收到的签名 + string return_sign = GetValue("sign").ToString(); + + //在本地计算新的签名 + string cal_sign = MakeSign(signType); + + if (cal_sign == return_sign) + { + return true; + } + + throw new Exception("WxPayData签名验证错误!"); + } + + + + /** + * + * 检测签名是否正确 + * 正确返回true,错误抛异常 + */ + public bool CheckSign() + { + return CheckSign(SIGN_TYPE_HMAC_SHA256); + } + + /** + * @获取Dictionary + */ + public SortedDictionary GetValues() + { + return m_values; + } + + + private string CalcHMACSHA256Hash(string plaintext, string salt) + { + string result = ""; + var enc = Encoding.Default; + byte[] + baText2BeHashed = enc.GetBytes(plaintext), + baSalt = enc.GetBytes(salt); + HMACSHA256 hasher = new HMACSHA256(baSalt); + byte[] baHashedText = hasher.ComputeHash(baText2BeHashed); + result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray()); + return result.ToUpper(); + } + + + private class SafeXmlDocument : XmlDocument + { + public SafeXmlDocument() + { + XmlResolver = null; + } + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHelper.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHelper.cs new file mode 100644 index 00000000..95d075be --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHelper.cs @@ -0,0 +1,179 @@ +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WeChatPay.Domain.Config; +using Yi.Framework.WeChatPay.Options; + +namespace Yi.Framework.WeChatPay.Helper +{ + public class PayHelper + { + public static readonly string KEY_PAY_PREFIX = "order:pay:url:"; + private readonly IPayConfig _IPayConfig = null; + private readonly PayApi _PayApi = null; + + private HttpContext _httpContext; + public PayHelper(IPayConfig PayConfig, PayApi PayApi, IHttpContextAccessor httpContextAccessor) + { + _IPayConfig = PayConfig; + _PayApi = PayApi; + _httpContext = httpContextAccessor.HttpContext; + } + + /// + /// 创建支付连接 + /// + /// + /// + /// + /// + /// + public string CreatePayUrl(long orderId, string description, long totalPay) + { + // 定义返回的支付连接 + string url; + try + { + // 构建支付需要的参数对象 + PayData data = new PayData(); + //描述 + data.SetValue("body", description); + //订单号 + data.SetValue("out_trade_no", orderId.ToString()); + data.SetValue("product_id", orderId.ToString()); + //货币(默认就是人民币) + data.SetValue("fee_type", "CNY"); + //TODO 总金额 (模拟1分钱, 线上环境换成真实价格) + data.SetValue("total_fee", /*totalPay.ToString()*/ 1); // 单位是分 + //调用微信支付的终端ip + data.SetValue("spbill_create_ip", "0.0.0.0"); + //回调地址 + data.SetValue("notify_url", _IPayConfig.GetNotifyUrl()); + //交易类型为扫码支付 + data.SetValue("trade_type", "NATIVE"); + + PayData result = _PayApi.UnifiedOrder(data);//调用统一下单接口 + url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接 + } + catch (Exception e) + { + throw new Exception("生成支付链接连接失败", e); + } + + return url; + } + + + /// + /// (调用微信API)根据订单ID查询订单信息,全部信息 + /// + /// + /// + public PayData QueryOrderById(long orderId) + { + PayData req = new PayData(); + req.SetValue("out_trade_no", orderId.ToString()); + PayData res = _PayApi.OrderQuery(req, _httpContext); + return res;// 返回查询数据 + } + + + + + public static PayOptions GetPayOptions(string path) + { + string config = File.ReadAllText(path); + var option = JsonConvert.DeserializeObject(config); + Console.WriteLine($"configPath={path} AppID={option.AppID}"); + return option; + } + + /// + /// 生成二维码方法 + /// + /// 输入的字符串 + /// 二维码宽度 + /// 二维码高度 + /// + public static string QRcode(string text, int width = 360, int height = 360) + { + + //这里要感谢一下http://old.wwei.cn/ + Dictionary dic = new() + { + { "qrid", "0" }, + { "data[type]", "index" }, + { "data[text]", text }, + { "moban_id", "0" }, + { "size", "300" }, + { "level", "M" }, + { "moban_type", "qrcpu" }, + { "style_setting[protype]", "1" }, + { "style_setting[ptcolor]", "#000000" }, + { "style_setting[inptcolor]", "#000000" }, + { "style_setting[fcolor]", "#000000" }, + { "style_setting[bcolor]", "#ffffff" }, + { "style_setting[mbtype_hb]", "0" }, + { "style_setting[logo_id]", "" }, + { "style_setting[logo_width]", "46" }, + { "style_setting[logo_height]", "46" }, + { "style_setting[logo_border]", "0" } + + }; + + + StringBuilder builder = new StringBuilder(); + int i = 0; + if (dic.Count > 0) + { + foreach (var item in dic) + { + if (i > 0) + builder.Append("&"); + builder.AppendFormat("{0}={1}", item.Key, item.Value); + i++; + } + } + + string postDataStr = builder.ToString(); + + +#pragma warning disable SYSLIB0014 // 类型或成员已过时 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://old.wwei.cn/qrcode-wwei_create.html"); +#pragma warning restore SYSLIB0014 // 类型或成员已过时 + + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr); + request.Headers.Add("Host", "old.wwei.cn"); + request.Headers.Add("User-Agent", "PostmanRuntime/6.66.6"); + request.Headers.Add("Origin", "http://old.wwei.cn"); + request.Headers.Add("Referer", "http://old.wwei.cn/"); + + Stream myRequestStream = request.GetRequestStream(); + StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("utf-8")); + myStreamWriter.Write(postDataStr); + myStreamWriter.Close(); + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + + Stream myResponseStream = response.GetResponseStream(); + StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); + string retString = myStreamReader.ReadToEnd(); + myStreamReader.Close(); + myResponseStream.Close(); + + var json = Newtonsoft.Json.JsonConvert.DeserializeObject(retString); + var data = json["data"].ToString(); + + return data; + + } + } +} diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHttpService.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHttpService.cs new file mode 100644 index 00000000..cfe529b8 --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Helper/PayHttpService.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Net; +using System.IO; +using System.Text; +using System.Net.Security; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using Microsoft.AspNetCore.Http; +using Yi.Framework.WeChatPay.Exceptions; +using Yi.Framework.WeChatPay.Domain.Config; + +namespace Yi.Framework.WeChatPay.Helper +{ + /// + /// http连接基础类,负责底层的http通信 + /// + public class PayHttpService + { + private readonly IPayConfig _IPayConfig = null; + private readonly HttpContext _httpContext = null; + public PayHttpService(IPayConfig PayConfig, IHttpContextAccessor httpContextAccessor) + { + _IPayConfig = PayConfig; + _httpContext = httpContextAccessor.HttpContext; + } + + public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) + { + //直接确认,否则打不开 + return true; + } + + public string Post(string xml, string url, bool isUseCert, int timeout) + { + GC.Collect();//垃圾回收,回收没有正常关闭的http连接 + + string result = "";//返回结果 + + + HttpWebRequest request = null; + HttpWebResponse response = null; + Stream reqStream = null; + + try + { + //设置最大连接数 + ServicePointManager.DefaultConnectionLimit = 200; + //设置https验证方式 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = + new RemoteCertificateValidationCallback(CheckValidationResult); + } + + /*************************************************************** + * 下面设置HttpWebRequest的相关属性 + * ************************************************************/ +#pragma warning disable SYSLIB0014 // 类型或成员已过时 + request = (HttpWebRequest)WebRequest.Create(url); +#pragma warning restore SYSLIB0014 // 类型或成员已过时 + request.UserAgent = string.Format("WXPaySDK/{3} ({0}) .net/{1} {2}", Environment.OSVersion, Environment.Version, _IPayConfig.GetMchID(), typeof(PayHttpService).Assembly.GetName().Version); + request.Method = "POST"; + request.Timeout = timeout * 1000; + + //设置POST的数据类型和长度 + request.ContentType = "text/xml"; + byte[] data = Encoding.UTF8.GetBytes(xml); + request.ContentLength = data.Length; + + + if (isUseCert)//是否使用证书--没用证书 + { + string path = _httpContext.Request.Path; + X509Certificate2 cert = new X509Certificate2(path + _IPayConfig.GetSSlCertPath(), _IPayConfig.GetSSlCertPassword()); + request.ClientCertificates.Add(cert); + } + + //往服务器写入数据 + reqStream = request.GetRequestStream(); + reqStream.Write(data, 0, data.Length); + reqStream.Close(); + + //获取服务端返回 + response = (HttpWebResponse)request.GetResponse(); + + //获取服务端返回数据 + StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + result = sr.ReadToEnd().Trim(); + sr.Close(); + } + catch (ThreadAbortException) + { +#pragma warning disable SYSLIB0006 // 类型或成员已过时 + Thread.ResetAbort(); +#pragma warning restore SYSLIB0006 // 类型或成员已过时 + } + catch (WebException e) + { + if (e.Status == WebExceptionStatus.ProtocolError) + { + throw new PayException(e.ToString()); + } + + } + catch (Exception e) + { + throw new PayException(e.ToString()); + } + finally + { + //关闭连接和流 + if (response != null) + { + response.Close(); + } + if (request != null) + { + request.Abort(); + } + } + return result; + } + + /// + /// 处理http GET请求,返回数据 + /// + /// 请求的url地址 + /// http GET成功后返回的数据,失败抛WebException异常 + public string Get(string url) + { + GC.Collect(); + string result = ""; + + HttpWebRequest request = null; + HttpWebResponse response = null; + + //请求url以获取数据 + try + { + //设置最大连接数 + ServicePointManager.DefaultConnectionLimit = 200; + //设置https验证方式 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = + new RemoteCertificateValidationCallback(CheckValidationResult); + } + + /*************************************************************** + * 下面设置HttpWebRequest的相关属性 + * ************************************************************/ +#pragma warning disable SYSLIB0014 // 类型或成员已过时 + request = (HttpWebRequest)WebRequest.Create(url); +#pragma warning restore SYSLIB0014 // 类型或成员已过时 + request.UserAgent = string.Format("WXPaySDK/{3} ({0}) .net/{1} {2}", Environment.OSVersion, Environment.Version, _IPayConfig.GetMchID(), typeof(PayHttpService).Assembly.GetName().Version); + request.Method = "GET"; + + //获取服务器返回 + response = (HttpWebResponse)request.GetResponse(); + + //获取HTTP返回数据 + StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + result = sr.ReadToEnd().Trim(); + sr.Close(); + } + catch (ThreadAbortException) + { +#pragma warning disable SYSLIB0006 // 类型或成员已过时 + Thread.ResetAbort(); +#pragma warning restore SYSLIB0006 // 类型或成员已过时 + } + catch (WebException e) + { + throw new PayException(e.ToString()); + } + catch (Exception e) + { + throw new PayException(e.ToString()); + } + finally + { + //关闭连接和流 + if (response != null) + { + response.Close(); + } + if (request != null) + { + request.Abort(); + } + } + return result; + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Options/PayOptions.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Options/PayOptions.cs new file mode 100644 index 00000000..861266da --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Options/PayOptions.cs @@ -0,0 +1,14 @@ +namespace Yi.Framework.WeChatPay.Options +{ + public class PayOptions + { + public string AppID { get; set; } + public string MchID { get; set; } + public string Key { get; set; } + public string NotifyUrl { get; set; } + + public bool IsFileConfig { get; set; } = false; + + public string ConfigPath { get; set; } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Yi.Framework.WeChatPay.csproj b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Yi.Framework.WeChatPay.csproj new file mode 100644 index 00000000..b861774e --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/Yi.Framework.WeChatPay.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/YiFrameworkWeChatPayModule.cs b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/YiFrameworkWeChatPayModule.cs new file mode 100644 index 00000000..1a85048b --- /dev/null +++ b/Yi.Framework.Net6/src/module/Yi.Framework.WeChatPay/YiFrameworkWeChatPayModule.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Configuration; +using Yi.Framework.WeChatPay.Extensions; +using Yi.Framework.WeChatPay.Options; + +namespace Yi.Framework.WeChatPay +{ + [DependsOn( + typeof(YiFrameworkCoreModule) + )] + public class YiFrameworkWeChatPayModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + services.AddWeChatPayServer(option => + { + option = Appsettings.app(nameof(PayOptions)); + }); + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/GlobalUsings.cs b/Yi.Framework.Net6/src/project/BBS/GlobalUsings.cs new file mode 100644 index 00000000..d6ecb816 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Yi.Framework.Core.Attributes; +global using Yi.Framework.Core.Helper; +global using Yi.Framework.Core.Model; +global using Yi.Framework.Core.Exceptions; \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Argee/AgreeDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Argee/AgreeDto.cs new file mode 100644 index 00000000..a2a1465d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Argee/AgreeDto.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos.Argee +{ + public class AgreeDto + { + public AgreeDto(bool isAgree) + { + IsAgree = isAgree; + if (isAgree) + { + + Message = "点赞成功,点赞+1"; + } + else + { + + Message = "取消点赞,点赞-1"; + } + + } + + public bool IsAgree { get; set; } + public string Message { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerCreateInputVo.cs new file mode 100644 index 00000000..74bde802 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerCreateInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner +{ + /// + /// Banner输入创建对象 + /// + public class BannerCreateInputVo + { + public string Name { get; set; } + public string? Logo { get; set; } + public string? Color { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListInputVo.cs new file mode 100644 index 00000000..e2fa88af --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListInputVo.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner +{ + public class BannerGetListInputVo : PagedAndSortedResultRequestDto + { + public string Name { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListOutputDto.cs new file mode 100644 index 00000000..e45f7700 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetListOutputDto.cs @@ -0,0 +1,21 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner +{ + public class BannerGetListOutputDto : IEntityDto + { + + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Color { get; set; } + + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetOutputDto.cs new file mode 100644 index 00000000..18bb227b --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerGetOutputDto.cs @@ -0,0 +1,21 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos +{ + public class BannerGetOutputDto : IEntityDto + { + + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Color { get; set; } + + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerUpdateInputVo.cs new file mode 100644 index 00000000..a4fef3ae --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/Dtos/Banner/BannerUpdateInputVo.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner +{ + public class BannerUpdateInputVo + { + public string? Name { get; set; } + public string? Logo { get; set; } + public string? Color { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/IBannerService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/IBannerService.cs new file mode 100644 index 00000000..a488e4fd --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Exhibition/IBannerService.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Exhibition.Dtos; +using Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Exhibition +{ + /// + /// Banner抽象 + /// + public interface IBannerService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleAllOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleAllOutputDto.cs new file mode 100644 index 00000000..eff34670 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleAllOutputDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class ArticleAllOutputDto : IEntityDto + { + public long Id { get; set; } + + //批量查询,不给内容,性能考虑 + //public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + public long ParentId { get; set; } + + public List Children { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleCreateInputVo.cs new file mode 100644 index 00000000..2372df66 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleCreateInputVo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + /// + /// Article输入创建对象 + /// + public class ArticleCreateInputVo + { + public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListInputVo.cs new file mode 100644 index 00000000..85ea760a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class ArticleGetListInputVo : PagedAndSortedResultRequestDto + { + public long Id { get; set; } + public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListOutputDto.cs new file mode 100644 index 00000000..569097ed --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetListOutputDto.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class ArticleGetListOutputDto : IEntityDto + { + public long Id { get; set; } + //ѯݣܿ + //public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + + public List Children { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetOutputDto.cs new file mode 100644 index 00000000..8d3acff7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleGetOutputDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class ArticleGetOutputDto : IEntityDto + { + public long Id { get; set; } + public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleUpdateInputVo.cs new file mode 100644 index 00000000..a9877566 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Article/ArticleUpdateInputVo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class ArticleUpdateInputVo + { + public string Content { get; set; } + public string Name { get; set; } + public long DiscussId { get; set; } + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentCreateInputVo.cs new file mode 100644 index 00000000..02002a15 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentCreateInputVo.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + /// + /// Comment输入创建对象 + /// + public class CommentCreateInputVo + { + + /// + /// 评论id + /// + public string Content { get; set; } + + /// + /// 主题id + /// + public long DiscussId { get; set; } + + /// + /// 第一层评论id,第一层为0 + /// + public long RootId { get; set; } + + /// + /// 被回复的CommentId,第一层为0 + /// + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListInputVo.cs new file mode 100644 index 00000000..64a4c0ea --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListInputVo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class CommentGetListInputVo + { + public DateTime? creationTime { get; set; } + public string? Content { get; set; } + + //ӦѡĪѯ + public long? DiscussId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListOutputDto.cs new file mode 100644 index 00000000..156180bd --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetListOutputDto.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Application.Contracts.Identity.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + /// + /// ۶෴ + /// + public class CommentGetListOutputDto : IEntityDto + { + public long Id { get; set; } + + + public DateTime? CreationTime { get; set; } + + + + + public string Content { get; set; } + + + /// + /// id + /// + public long DiscussId { get; set; } + + public long ParentId { get; set; } + + public long RootId { get; set; } + + /// + /// û,ûϢ + /// + public UserGetOutputDto CreateUser { get; set; } + + /// + /// ۵ûϢ + /// + public UserGetOutputDto CommentedUser { get; set; } + + + /// + /// һΣǴһά飬Childrenֻڶʱֻһ + /// + public List Children { get; set; } = new List(); + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetOutputDto.cs new file mode 100644 index 00000000..962aa71d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentGetOutputDto.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Application.Contracts.Identity.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + /// + /// أصۼ + /// + public class CommentGetOutputDto : IEntityDto + { + public long Id { get; set; } + + public DateTime? CreateTime { get; set; } + public string Content { get; set; } + + public long DiscussId { get; set; } + + + /// + /// ûidΪû + /// + + public UserGetOutputDto User { get; set; } + /// + /// ڵid + /// + public long RootId { get; set; } + + /// + /// ظCommentId + /// + public long ParentId { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentUpdateInputVo.cs new file mode 100644 index 00000000..24186997 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Comment/CommentUpdateInputVo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class CommentUpdateInputVo + { + + public string Content { get; set; } + + //²ܽת + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussCreateInputVo.cs new file mode 100644 index 00000000..4e3093e5 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussCreateInputVo.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss +{ + /// + /// Discuss输入创建对象 + /// + public class DiscussCreateInputVo + { + public string Title { get; set; } + public string? Types { get; set; } + public string? Introduction { get; set; } + public DateTime? CreateTime { get; set; } = DateTime.Now; + public string Content { get; set; } + public string? Color { get; set; } + + public long PlateId { get; set; } + + /// + /// 默认公开 + /// + public DiscussPermissionTypeEnum PermissionType { get; set; } = DiscussPermissionTypeEnum.Public; + /// + /// 封面 + /// + public string? Cover { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListInputVo.cs new file mode 100644 index 00000000..b336ed17 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListInputVo.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss +{ + public class DiscussGetListInputVo : PagedAndSortedResultRequestDto + { + public string? Title { get; set; } + + public long? PlateId { get; set; } + + //Ĭϲѯö + public bool IsTop { get; set; } = false; + + + //ѯʽ + public QueryDiscussTypeEnum Type { get; set; } = QueryDiscussTypeEnum.New; + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListOutputDto.cs new file mode 100644 index 00000000..7042feb7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetListOutputDto.cs @@ -0,0 +1,99 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Application.Contracts.Identity.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss +{ + public class DiscussGetListOutputDto : IEntityDto + { + /// + /// Ƿѵ + /// + public bool IsAgree { get; set; } + public long Id { get; set; } + public string Title { get; set; } + public string Types { get; set; } + public string? Introduction { get; set; } + + public int AgreeNum { get; set; } + public int SeeNum { get; set; } + + //ѯݣܿ + //public string Content { get; set; } + public string? Color { get; set; } + + public long PlateId { get; set; } + + //ǷöĬfalse + public bool IsTop { get; set; } + + public DiscussPermissionTypeEnum PermissionType { get; set; } + //ǷֹĬfalse + public bool IsBan { get; set; } + + + /// + /// + /// + public string? Cover { get; set; } + + //˽ҪжcodeȨ + public string? PrivateCode { get; set; } + public DateTime CreationTime { get; set; } + + public List PermissionUserIds { get; set; } + + public UserGetListOutputDto User { get; set; } + + public void SetBan() + { + this.Title = DiscussConst.˽; + this.Introduction = ""; + this.Cover = null; + //ֹ + this.IsBan = true; + } + } + + + public static class DiscussGetListOutputDtoExtension + { + + public static void ApplyPermissionTypeFilter(this List dtos, long userId) + { + dtos?.ForEach(dto => + { + switch (dto.PermissionType) + { + case DiscussPermissionTypeEnum.Public: + break; + case DiscussPermissionTypeEnum.Oneself: + //ǰǽԼɼͬʱǵǰ¼û + if (dto.User.Id != userId) + { + dto.SetBan(); + } + break; + case DiscussPermissionTypeEnum.User: + //ǰΪֿɼͬʱǵǰ¼û Ҳ ڿɼûб + if (dto.User.Id != userId && !dto.PermissionUserIds.Contains(userId)) + { + dto.SetBan(); + } + break; + default: + break; + } + }); + } + + } + +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetOutputDto.cs new file mode 100644 index 00000000..57eb36b2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussGetOutputDto.cs @@ -0,0 +1,44 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Application.Contracts.Identity.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class DiscussGetOutputDto : IEntityDto + { + + public long Id { get; set; } + public string Title { get; set; } + public string? Types { get; set; } + public string? Introduction { get; set; } + public int AgreeNum { get; set; } + public int SeeNum { get; set; } + public string Content { get; set; } + public string? Color { get; set; } + + public long PlateId { get; set; } + //ǷöĬfalse + public bool IsTop { get; set; } + + /// + /// + /// + public string? Cover { get; set; } + //Ƿ˽УĬfalse + public bool IsPrivate { get; set; } + + //˽ҪжcodeȨ + public string? PrivateCode { get; set; } + public DateTime CreationTime { get; set; } + public DiscussPermissionTypeEnum PermissionType { get; set; } + + public List PermissionUserIds { get; set; } + public UserGetListOutputDto User { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussUpdateInputVo.cs new file mode 100644 index 00000000..b6e53d15 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Discuss/DiscussUpdateInputVo.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss +{ + public class DiscussUpdateInputVo + { + public string Title { get; set; } + public string? Types { get; set; } + public string? Introduction { get; set; } + public int AgreeNum { get; set; } + public int SeeNum { get; set; } + public string Content { get; set; } + public string? Color { get; set; } + + public List PermissionUserIds { get; set; } + + public DiscussPermissionTypeEnum PermissionType { get; set; } + + /// + /// + /// + public string? Cover { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeCreateInputVo.cs new file mode 100644 index 00000000..8b23c3b0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeCreateInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + /// + /// Label输入创建对象 + /// + public class MyTypeCreateInputVo + { + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListInputVo.cs new file mode 100644 index 00000000..c81f294a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class MyTypeGetListInputVo : PagedAndSortedResultRequestDto + { + public long Id { get; set; } + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListOutputDto.cs new file mode 100644 index 00000000..93180425 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeGetListOutputDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class MyTypeGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeOutputDto.cs new file mode 100644 index 00000000..b25fd998 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeOutputDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class MyTypeOutputDto : IEntityDto + { + public long Id { get; set; } + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeUpdateInputVo.cs new file mode 100644 index 00000000..1adc2969 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/MyType/MyTypeUpdateInputVo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class MyTypeUpdateInputVo + { + public long Id { get; set; } + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateCreateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateCreateInputVo.cs new file mode 100644 index 00000000..faa6dace --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateCreateInputVo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Plate +{ + /// + /// Plate输入创建对象 + /// + public class PlateCreateInputVo + { + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListInputVo.cs new file mode 100644 index 00000000..b814da0d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListInputVo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Plate +{ + public class PlateGetListInputVo : PagedAndSortedResultRequestDto + { + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListOutputDto.cs new file mode 100644 index 00000000..14841038 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetListOutputDto.cs @@ -0,0 +1,19 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Plate +{ + public class PlateGetListOutputDto : IEntityDto + { + + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetOutputDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetOutputDto.cs new file mode 100644 index 00000000..8bc031f1 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateGetOutputDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos +{ + public class PlateGetOutputDto : IEntityDto + { + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateUpdateInputVo.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateUpdateInputVo.cs new file mode 100644 index 00000000..c033bd3d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/Dtos/Plate/PlateUpdateInputVo.cs @@ -0,0 +1,18 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.Forum.Dtos.Plate +{ + public class PlateUpdateInputVo + { + + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IArticleService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IArticleService.cs new file mode 100644 index 00000000..c1c8a411 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IArticleService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Forum +{ + /// + /// Article服务抽象 + /// + public interface IArticleService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ICommentService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ICommentService.cs new file mode 100644 index 00000000..eccbc829 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ICommentService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Forum +{ + /// + /// Comment服务抽象 + /// + public interface ICommentService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IDiscussService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IDiscussService.cs new file mode 100644 index 00000000..21710f40 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IDiscussService.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Application.Contracts.Forum.Dtos.Discuss; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Forum +{ + /// + /// Discuss服务抽象 + /// + public interface IDiscussService : ICrudAppService + { + Task VerifyDiscussPermissionAsync(long discussId); + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ILabelService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ILabelService.cs new file mode 100644 index 00000000..bcbacbec --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/ILabelService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Forum +{ + /// + /// Label服务抽象 + /// + public interface ILabelService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IPlateService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IPlateService.cs new file mode 100644 index 00000000..3fe9452c --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Forum/IPlateService.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Application.Contracts.Forum.Dtos.Plate; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.Forum +{ + /// + /// Plate服务抽象 + /// + public interface IPlateService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/ActionJwtDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/ActionJwtDto.cs new file mode 100644 index 00000000..1abc63bb --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/ActionJwtDto.cs @@ -0,0 +1,18 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.GlobalSetting.Dtos.Temp +{ + public class ActionJwtDto + { + + public long Id { get; set; } + public string ActionName { get; set; } + public string Router { get; set; } + public string Icon { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/LoginDto.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/LoginDto.cs new file mode 100644 index 00000000..416fdb9e --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/Dtos/Temp/LoginDto.cs @@ -0,0 +1,31 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Application.Contracts.GlobalSetting.Dtos.Temp +{ + public class LoginDto + { + public LoginDto(string token) + { + Token = token; + } + public string Token { get; set; } + public LoginUserInfoDto User{get;set;} + } + + public class LoginUserInfoDto + { + + public long Id { get; set; } + + public string UserName { get; set; } + + public int Level { get; set; } + + public string Icon { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/ISettingService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/ISettingService.cs new file mode 100644 index 00000000..8820dc26 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/GlobalSetting/ISettingService.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.BBS.Application.Contracts.GlobalSetting +{ + /// + /// Setting应用抽象 + /// + public interface ISettingService : IApplicationService + { + /// + /// 获取配置标题 + /// + /// + Task GetTitleAsync(); + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.Contracts.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.Contracts.csproj new file mode 100644 index 00000000..260aff7a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.Contracts.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.ContractsSwaggerDoc.xml b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.ContractsSwaggerDoc.xml new file mode 100644 index 00000000..dfaac78a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/Yi.BBS.Application.ContractsSwaggerDoc.xml @@ -0,0 +1,174 @@ + + + + Yi.BBS.Application.Contracts + + + + + Banner输入创建对象 + + + + + Banner抽象 + + + + + Article输入创建对象 + + + + + Comment输入创建对象 + + + + + 评论id + + + + + 主题id + + + + + 第一层评论id,第一层为0 + + + + + 被回复的CommentId,第一层为0 + + + + + 评论多反 + + + + + 主题id + + + + + 用户,评论人用户信息 + + + + + 被评论的用户信息 + + + + + 这个不是一个树形,而是存在一个二维数组,该Children只有在顶级时候,只有一层 + + + + + 单返回,返回单条评论即可 + + + + + 用户id联表为用户对象 + + + + + 根节点的评论id + + + + + 被回复的CommentId + + + + + Discuss输入创建对象 + + + + + 默认公开 + + + + + 封面 + + + + + 是否已点赞 + + + + + 封面 + + + + + 封面 + + + + + 封面 + + + + + Label输入创建对象 + + + + + Plate输入创建对象 + + + + + Article服务抽象 + + + + + Comment服务抽象 + + + + + Discuss服务抽象 + + + + + Label服务抽象 + + + + + Plate服务抽象 + + + + + Setting应用抽象 + + + + + 获取配置标题 + + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/YiBBSApplicationContractsModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/YiBBSApplicationContractsModule.cs new file mode 100644 index 00000000..d968104f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application.Contracts/YiBBSApplicationContractsModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.BBS.Domain.Shared; + +namespace Yi.BBS.Application.Contracts +{ + [DependsOn( + typeof(YiBBSDomainSharedModule) + )] + public class YiBBSApplicationContractsModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/AgreeService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/AgreeService.cs new file mode 100644 index 00000000..fb41f751 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/AgreeService.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Exhibition.Dtos.Argee; +using Yi.BBS.Domain.Exhibition.Entities; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Services.Abstract; +using Yi.Framework.Uow; + +namespace Yi.BBS.Application.Exhibition +{ + /// + /// 点赞功能 + /// + [AppService] + public class AgreeService : ApplicationService, IApplicationService, IAutoApiService + { + + [Autowired] + private IRepository _repository { get; set; } + + [Autowired] + private IRepository _discssRepository { get; set; } + [Autowired] + private ICurrentUser _currentUser { get; set; } + + [Autowired] + private IUnitOfWorkManager _unitOfWorkManager { get; set; } + + /// + /// 点赞,返回true为点赞+1,返回false为点赞-1 + /// + /// + public async Task PostOperateAsync(long discussId) + { + var entity = await _repository.GetFirstAsync(x => x.DiscussId == discussId && x.CreatorId == _currentUser.Id); + //判断是否已经点赞过 + if (entity is null) + { + using (var uow = _unitOfWorkManager.CreateContext()) + { + //没点赞过,添加记录即可,,修改总点赞数量 + await _repository.InsertAsync(new AgreeEntity(discussId)); + var discussEntity = await _discssRepository.GetByIdAsync(discussId); + if (discussEntity is null) + { + throw new UserFriendlyException("主题为空"); + } + discussEntity.AgreeNum += 1; + await _discssRepository.UpdateAsync(discussEntity); + uow.Commit(); + } + return new AgreeDto(true); + + } + else + { + using (var uow = _unitOfWorkManager.CreateContext()) + { + //点赞过,删除即可,修改总点赞数量 + await _repository.DeleteByIdAsync(entity.Id); + var discussEntity = await _discssRepository.GetByIdAsync(discussId); + if (discussEntity is null) + { + throw new UserFriendlyException("主题为空"); + } + discussEntity.AgreeNum -= 1; + await _discssRepository.UpdateAsync(discussEntity); + uow.Commit(); + } + + return new AgreeDto(false); + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/BannerService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/BannerService.cs new file mode 100644 index 00000000..94b25c30 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Exhibition/BannerService.cs @@ -0,0 +1,18 @@ +using Yi.BBS.Application.Contracts.Exhibition; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Exhibition.Dtos; +using Yi.BBS.Domain.Exhibition.Entities; +using Yi.Framework.Ddd.Services; +using Yi.BBS.Application.Contracts.Exhibition.Dtos.Banner; + +namespace Yi.BBS.Application.Exhibition +{ + /// + /// Banner服务实现 + /// + [AppService] + public class BannerService : CrudAppService, + IBannerService, IAutoApiService + { + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/ArticleService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/ArticleService.cs new file mode 100644 index 00000000..b69cd865 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/ArticleService.cs @@ -0,0 +1,113 @@ +using Yi.BBS.Application.Contracts.Forum; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using Microsoft.AspNetCore.Mvc; +using Yi.BBS.Domain.Forum.Repositories; +using Yi.Framework.Ddd.Repositories; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Core.CurrentUsers; +using Yi.RBAC.Domain.Shared.Identity.ConstClasses; + +namespace Yi.BBS.Application.Forum +{ + /// + /// Article服务实现 + /// + [AppService] + + public class ArticleService : CrudAppService, + IArticleService, IAutoApiService + { + [Autowired] + private IArticleRepository _articleRepository { get; set; } + + + [Autowired] + private IRepository _discussRepository { get; set; } + + [Autowired] + private ICurrentUser _currentUser { get; set; } + + [Autowired] + private IDiscussService _discussService { get; set; } + /// + /// 获取文章全部平铺信息 + /// + /// + /// + /// + [Route("/api/article/all/discuss-id/{discussId}")] + public async Task> GetAllAsync([FromRoute] long discussId) + { + await _discussService.VerifyDiscussPermissionAsync(discussId); + + + var entities = await _articleRepository.GetTreeAsync(x => x.DiscussId == discussId); + //var result = entities.Tile(); + var items = _mapper.Map>(entities); + return items; + } + + /// + /// 查询文章 + /// + /// + /// + /// + public async Task> GetDiscussIdAsync([FromRoute] long discussId) + { + if (!await _discussRepository.IsAnyAsync(x => x.Id == discussId)) + { + throw new UserFriendlyException(DiscussConst.主题不存在); + } + + var entities = await _articleRepository.GetTreeAsync(x => x.DiscussId == discussId); + var items = await MapToGetListOutputDtosAsync(entities); + return items; + } + + /// + /// 发表文章 + /// + /// + /// + /// + public async override Task CreateAsync(ArticleCreateInputVo input) + { + var discuss = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId); + if (discuss is null) + { + throw new UserFriendlyException(DiscussConst.主题不存在); + } + if (input.ParentId != 0 && !await _repository.IsAnyAsync(x => x.Id == input.ParentId)) + { + throw new UserFriendlyException(ArticleConst.文章不存在); + } + await VerifyDiscussCreateIdAsync(discuss.CreatorId); + return await base.CreateAsync(input); + } + + + /// + /// 效验创建权限 + /// + /// + /// + public async Task VerifyDiscussCreateIdAsync(long? userId) + { + //只有文章是特殊的,不能在其他主题下创建 + //主题的创建者不是当前用户,同时,没有权限或者超级管理 + + //false & true & false ,三个条件任意满意一个,即可成功使用||,最后取反,一个都不满足 + // + if (userId != _currentUser.Id && !UserConst.Admin.Equals( _currentUser.UserName)&& !_currentUser.Permission.Contains("bbs:discuss:add")) + { + throw new UserFriendlyException("无权限在其他用户主题中创建子文章"); + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/CommentService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/CommentService.cs new file mode 100644 index 00000000..6dd7b8cc --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/CommentService.cs @@ -0,0 +1,109 @@ +using Yi.BBS.Application.Contracts.Forum; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Services; +using Microsoft.AspNetCore.Mvc; +using Yi.BBS.Domain.Forum; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Ddd.Repositories; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.BBS.Application.Contracts.Forum.Dtos.Discuss; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using System.Security.AccessControl; +using System.Linq; +using System.Xml.Linq; +using System.Collections.Generic; + +namespace Yi.BBS.Application.Forum +{ + /// + /// 评论 + /// + [AppService] + public class CommentService : CrudAppService, + ICommentService, IAutoApiService + { + [Autowired] + private ForumManager _forumManager { get; set; } + + [Autowired] + private ICurrentUser _currentUser { get; set; } + + [Autowired] + private IRepository _discussRepository { get; set; } + + [Autowired] + private IDiscussService _discussService { get; set; } + /// + /// 获取改主题下的评论,结构为二维列表,该查询无分页 + /// + /// + /// + /// + public async Task> GetDiscussIdAsync([FromRoute] long discussId, [FromQuery] CommentGetListInputVo input) + { + await _discussService.VerifyDiscussPermissionAsync(discussId); + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Content), x => x.Content.Contains(input.Content)) + .Where(x => x.DiscussId == discussId) + .Includes(x=>x.CreateUser) + .ToListAsync(); + + //结果初始值,第一层等于全部根节点 + var outPut = entities.Where(x => x.ParentId == 0).OrderByDescending(x=>x.CreationTime).ToList(); + + //将全部数据进行hash + var dic = entities.ToDictionary(x => x.Id); + + + foreach (var comment in entities) + { + //不是根节点,需要赋值 被评论者用户信息等 + if (comment.ParentId != 0) + { + var parentComment = dic[comment.ParentId]; + comment.CommentedUser = parentComment.CreateUser; + } + + //root或者parent id,根节点都是等于0的 + var id = comment.RootId; + if (id is not 0) + { + dic[id].Children.Add(comment); + } + + } + + //子类需要排序 + outPut.ForEach(x => + { + x.Children = x.Children.OrderByDescending(x => x.CreationTime).ToList(); + + }); + + //获取全量主题评论, 先获取顶级的,将其他子组合到顶级下,形成一个二维,先转成dto + List? items = await MapToGetListOutputDtosAsync(outPut); + return new PagedResultDto(entities.Count(), items); + } + + + /// + /// 发表评论 + /// + /// + /// + /// + public override async Task CreateAsync(CommentCreateInputVo input) + { + if (!await _discussRepository.IsAnyAsync(x => x.Id == input.DiscussId)) + { + throw new UserFriendlyException(DiscussConst.主题不存在); + } + var entity = await _forumManager.CreateCommentAsync(input.DiscussId, input.ParentId,input.RootId, input.Content); + return await MapToGetOutputDtoAsync(entity); + } + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/DiscussService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/DiscussService.cs new file mode 100644 index 00000000..2009a82c --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/DiscussService.cs @@ -0,0 +1,154 @@ +using Yi.BBS.Application.Contracts.Forum; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Services; +using Yi.BBS.Application.Contracts.Forum.Dtos.Discuss; +using Microsoft.AspNetCore.Mvc; +using Yi.Framework.Ddd.Dtos; +using Yi.BBS.Domain.Forum; +using MapsterMapper; +using SqlSugar; +using Microsoft.AspNetCore.Routing; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Cike.EventBus.DistributedEvent; +using Yi.BBS.Domain.Shared.Forum.Etos; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Core.CurrentUsers; +using Yi.BBS.Domain.Exhibition.Entities; + +namespace Yi.BBS.Application.Forum +{ + /// + /// Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息 + /// + [AppService] + public class DiscussService : CrudAppService, + IDiscussService, IAutoApiService + { + public DiscussService(ICurrentUser currentUser) + { + _currentUser = currentUser; + } + [Autowired] + private ForumManager _forumManager { get; set; } + + [Autowired] + private IRepository _plateEntityRepository { get; set; } + + [Autowired] + private IDistributedEventBus _distributedEventBus { get; set; } + + //[Autowired] + private ICurrentUser _currentUser { get; set; } + /// + /// 单查 + /// + /// + /// + public async override Task GetAsync(long id) + { + + //查询主题发布 浏览主题 事件,浏览数+1 + var item = await _DbQueryable.LeftJoin((discuss, user) => discuss.CreatorId == user.Id) + .Select((discuss, user) => new DiscussGetOutputDto + { + User = new UserGetListOutputDto() { UserName = user.UserName, Nick = user.Nick, Icon = user.Icon } + }, true).SingleAsync(discuss => discuss.Id == id); + + await VerifyDiscussPermissionAsync(item.Id); + + if (item is not null) + { + _distributedEventBus.PublishAsync(new SeeDiscussEventArgs { DiscussId = item.Id, OldSeeNum = item.SeeNum }); + } + + return item; + } + + + /// + /// 查询 + /// + /// + /// + + public override async Task> GetListAsync([FromQuery] DiscussGetListInputVo input) + { + //需要关联创建者用户 + RefAsync total = 0; + var items = await _DbQueryable + .WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title.Contains(input.Title)) + .WhereIF(input.PlateId is not null, x => x.PlateId == input.PlateId) + .Where(x => x.IsTop == input.IsTop) + + .LeftJoin((discuss, user) => discuss.CreatorId == user.Id) + .OrderByIF(input.Type == QueryDiscussTypeEnum.New, discuss => discuss.CreationTime, OrderByType.Desc) + .OrderByIF(input.Type == QueryDiscussTypeEnum.Host, discuss => discuss.SeeNum, OrderByType.Desc) + .OrderByIF(input.Type == QueryDiscussTypeEnum.Suggest, discuss => discuss.AgreeNum, OrderByType.Desc) + .Select((discuss, user) => new DiscussGetListOutputDto + { + Id=discuss.Id, + IsAgree = SqlFunc.Subqueryable().Where(x => x.CreatorId == _currentUser.Id && x.DiscussId == discuss.Id).Any(), + + User = new UserGetListOutputDto() { Id=user.Id, UserName = user.UserName, Nick = user.Nick, Icon = user.Icon } + + }, true) + .ToPageListAsync(input.PageNum, input.PageSize, total); + + //查询完主题之后,要过滤一下私有的主题信息 + items.ApplyPermissionTypeFilter(_currentUser.Id); + return new PagedResultDto(total, items); + } + + /// + /// 创建主题 + /// + /// + /// + public override async Task CreateAsync(DiscussCreateInputVo input) + { + if (!await _plateEntityRepository.IsAnyAsync(x => x.Id == input.PlateId)) + { + throw new UserFriendlyException(PlateConst.板块不存在); + } + var entity = await _forumManager.CreateDiscussAsync(await MapToEntityAsync(input)); + return await MapToGetOutputDtoAsync(entity); + } + + + + + /// + /// 效验主题查询权限 + /// + /// + /// + /// + public async Task VerifyDiscussPermissionAsync(long discussId) + { + var discuss = await _repository.GetFirstAsync(x => x.Id == discussId); + if (discuss is null) + { + throw new UserFriendlyException(DiscussConst.主题不存在); + } + if (discuss.PermissionType == DiscussPermissionTypeEnum.Oneself) + { + if (discuss.CreatorId != _currentUser.Id) + { + throw new UserFriendlyException(DiscussConst.私密); + } + } + if (discuss.PermissionType == DiscussPermissionTypeEnum.User) + { + if (discuss.CreatorId != _currentUser.Id && !discuss.PermissionUserIds.Contains(_currentUser.Id)) + { + throw new UserFriendlyException(DiscussConst.私密); + } + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/MyTypeService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/MyTypeService.cs new file mode 100644 index 00000000..ac557727 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/MyTypeService.cs @@ -0,0 +1,53 @@ +using Yi.BBS.Application.Contracts.Forum; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Core.CurrentUsers; +using SqlSugar; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Data.Filters; + +namespace Yi.BBS.Application.Forum +{ + /// + /// Label服务实现 + /// + [AppService] + public class MyTypeService : CrudAppService, + ILabelService, IAutoApiService + { + [Autowired] + private ICurrentUser _currentUser { get; set; } + + [Autowired] + private IDataFilter _dataFilter { get; set; } + + /// + /// 获取当前用户的主题类型 + /// + /// + /// + public Task> GetListCurrentAsync(MyTypeGetListInputVo input) + { + + _dataFilter.AddFilter(x => x.UserId == _currentUser.Id); + return base.GetListAsync(input); + } + + /// + /// 创建 + /// + /// + /// + public override async Task CreateAsync(MyTypeCreateInputVo input) + { + var entity = await MapToEntityAsync(input); + entity.Id = SnowflakeHelper.NextId; + entity.UserId = _currentUser.Id; + entity.IsDeleted = false; + var outputEntity = await _repository.InsertReturnEntityAsync(entity); + return await MapToGetOutputDtoAsync(outputEntity); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/PlateService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/PlateService.cs new file mode 100644 index 00000000..43a67b8a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Forum/PlateService.cs @@ -0,0 +1,18 @@ +using Yi.BBS.Application.Contracts.Forum; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Application.Contracts.Forum.Dtos; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Services; +using Yi.BBS.Application.Contracts.Forum.Dtos.Plate; + +namespace Yi.BBS.Application.Forum +{ + /// + /// Plate服务实现 + /// + [AppService] + public class PlateService : CrudAppService, + IPlateService, IAutoApiService + { + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/SettingService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/SettingService.cs new file mode 100644 index 00000000..0e759e92 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/SettingService.cs @@ -0,0 +1,25 @@ +using Yi.BBS.Application.Contracts.GlobalSetting; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Domain.GlobalSetting.Entities; +using Yi.Framework.Ddd.Services; + +namespace Yi.BBS.Application.GlobalSetting +{ + /// + /// Setting服务实现 + /// + [AppService] + public class SettingService : ApplicationService, + ISettingService, IAutoApiService + { + /// + /// 获取配置标题 + /// + /// + /// + public Task GetTitleAsync() + { + return Task.FromResult("你好世界"); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/TempService.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/TempService.cs new file mode 100644 index 00000000..803c8d3f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/GlobalSetting/TempService.cs @@ -0,0 +1,81 @@ +using Yi.BBS.Application.Contracts.GlobalSetting; +using Cike.AutoWebApi.Setting; +using Yi.BBS.Domain.GlobalSetting.Entities; +using Yi.Framework.Ddd.Services; +using Microsoft.AspNetCore.Mvc; +using Yi.BBS.Application.Contracts.GlobalSetting.Dtos.Temp; +using Yi.BBS.Domain.Shared; +using Yi.Framework.Data.DataSeeds; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.BBS.Application.GlobalSetting +{ + /// + ///临时服务,之后用其他模块代替 + /// + [AppService] + public class TempService : ApplicationService, IAutoApiService + { + + public TempService() { + } + ///// + ///// 登录 + ///// + ///// + ///// + //[Route("/api/account/login")] + //public Task PostLoginAsync() + //{ + // bool loginSucces = true; + // if (!loginSucces) + // { + // throw new UserFriendlyException("登录失败", (int)BbsHttpStatusEnum.LoginFailed, "用户或者密码错误"); + // } + // var dto = new LoginDto("token"); + // dto.User = new LoginUserInfoDto { Icon = "", Id = 0, Level = 1, UserName = "橙子" }; + // return Task.FromResult(dto); + //} + + ///// + ///// 判断是否有登录 + ///// + ///// + //[Route("/api/account/logged")] + //public Task PostLogged() + //{ + // return Task.FromResult(true); + //} + + ///// + ///// 退出登录 + ///// + ///// + //[Route("/api/account/logout")] + //public Task PostlogOut() + //{ + // return Task.CompletedTask; + //} + + /// + /// 获取用户信息 + /// + /// + /// + [Route("/api/account/user/{id}")] + public Task> GetUserInfoByIdAsync(long id) + { + var dto = new List(); + dto.Add(new ActionJwtDto { Router = "/index", ActionName = "首页" }); + //dto.Add(new ActionJwtDto { Router = "/admLable", ActionName = "标签管理" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + //dto.Add(new ActionJwtDto { Router = "", ActionName = "" }); + return Task.FromResult(dto); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.Application.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.Application.csproj new file mode 100644 index 00000000..71a2b0ec --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.Application.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.ApplicationSwaggerDoc.xml b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.ApplicationSwaggerDoc.xml new file mode 100644 index 00000000..0b2ebd1d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/Yi.BBS.ApplicationSwaggerDoc.xml @@ -0,0 +1,163 @@ + + + + Yi.BBS.Application + + + + + 点赞功能 + + + + + 点赞,返回true为点赞+1,返回false为点赞-1 + + + + + + Banner服务实现 + + + + + Article服务实现 + + + + + 获取文章全部平铺信息 + + + + + + + + 查询文章 + + + + + + + + 发表文章 + + + + + + + + 效验创建权限 + + + + + + + 评论 + + + + + 获取改主题下的评论,结构为二维列表,该查询无分页 + + + + + + + + 发表评论 + + + + + + + + Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息 + + + + + 单查 + + + + + + + 查询 + + + + + + + 创建主题 + + + + + + + 效验主题查询权限 + + + + + + + + Label服务实现 + + + + + 获取当前用户的主题类型 + + + + + + + 创建 + + + + + + + Plate服务实现 + + + + + Setting服务实现 + + + + + 获取配置标题 + + + + + + + 临时服务,之后用其他模块代替 + + + + + 获取用户信息 + + + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/YiBBSApplicationModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/YiBBSApplicationModule.cs new file mode 100644 index 00000000..0f87fe5f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Application/YiBBSApplicationModule.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Application.Contracts; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.Framework.Ddd; +using Yi.BBS.Domain; +using Yi.RBAC.Application; + +namespace Yi.BBS.Application +{ + [DependsOn( + + typeof(YiBBSApplicationContractsModule), + typeof(YiBBSDomainModule), + typeof(YiFrameworkAuthJwtBearerModule), + typeof(YiRBACApplicationModule) + )] + public class YiBBSApplicationModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/BbsHttpStatusEnum.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/BbsHttpStatusEnum.cs new file mode 100644 index 00000000..565409f3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/BbsHttpStatusEnum.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared +{ + public enum BbsHttpStatusEnum + { + LoginFailed=1900 + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Exhibition/ConstClasses/BannerConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Exhibition/ConstClasses/BannerConst.cs new file mode 100644 index 00000000..1df938a8 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Exhibition/ConstClasses/BannerConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Exhibition.ConstClasses +{ + /// + /// 常量定义 + /// + + public class BannerConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/ArticleConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/ArticleConst.cs new file mode 100644 index 00000000..2f676c81 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/ArticleConst.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.ConstClasses +{ + /// + /// 常量定义 + /// + + public class ArticleConst + { + public const string 文章不存在 = "传入的文章id不存在"; + + public const string 文章无权限 = "该文章无权限"; + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/CommentConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/CommentConst.cs new file mode 100644 index 00000000..c661d369 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/CommentConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.ConstClasses +{ + /// + /// 常量定义 + /// + + public class CommentConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/DiscussConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/DiscussConst.cs new file mode 100644 index 00000000..99cad730 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/DiscussConst.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.ConstClasses +{ + /// + /// 常量定义 + /// + + public class DiscussConst + { + public const string 主题不存在 = "传入的主题id不存在"; + + public const string 私密 = "【私密】您无该主题权限,可联系作者申请开放"; + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/LabelConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/LabelConst.cs new file mode 100644 index 00000000..e0fd6841 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/LabelConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.ConstClasses +{ + /// + /// 常量定义 + /// + + public class LabelConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/PlateConst.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/PlateConst.cs new file mode 100644 index 00000000..92acf486 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/ConstClasses/PlateConst.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.ConstClasses +{ + /// + /// 常量定义 + /// + + public class PlateConst + { + public const string 板块不存在 = "传入的板块id不存在"; + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/DiscussPermissionTypeEnum.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/DiscussPermissionTypeEnum.cs new file mode 100644 index 00000000..625a66a2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/DiscussPermissionTypeEnum.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.EnumClasses +{ + public enum DiscussPermissionTypeEnum + { + /// + /// 默认:公开 + /// + Public = 0, + + /// + /// 仅自己可见 + /// + Oneself, + + /// + /// 部分用户可见 + /// + User + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/QueryDiscussTypeEnum.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/QueryDiscussTypeEnum.cs new file mode 100644 index 00000000..08d9063a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/EnumClasses/QueryDiscussTypeEnum.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.EnumClasses +{ + public enum QueryDiscussTypeEnum + { + New, + Suggest, + Host + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/Etos/SeeDiscussEventArgs.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/Etos/SeeDiscussEventArgs.cs new file mode 100644 index 00000000..3381d4e0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Forum/Etos/SeeDiscussEventArgs.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.BBS.Domain.Shared.Forum.Etos +{ + public class SeeDiscussEventArgs + { + public long DiscussId { get; set; } + public int OldSeeNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Yi.BBS.Domain.Shared.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Yi.BBS.Domain.Shared.csproj new file mode 100644 index 00000000..692994fe --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/Yi.BBS.Domain.Shared.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/YiBBSDomainSharedModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/YiBBSDomainSharedModule.cs new file mode 100644 index 00000000..5f37e09e --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain.Shared/YiBBSDomainSharedModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Ddd; + +namespace Yi.BBS.Domain.Shared +{ + [DependsOn( + typeof(YiFrameworkDddModule) + )] + public class YiBBSDomainSharedModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsConfigDataSeed.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsConfigDataSeed.cs new file mode 100644 index 00000000..1e4aac53 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsConfigDataSeed.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Setting.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.BBS.Domain.DataSeed +{ + [AppService(typeof(IDataSeed))] + public class BbsConfigDataSeed : AbstractDataSeed + { + public BbsConfigDataSeed(IRepository repository) : base(repository) + { + } + + public override async Task IsInvoker() + { + return !await _repository.IsAnyAsync(x => x.ConfigKey == "bbs.site.name"); + } + public override List GetSeedData() + { + List entities = new List() + { + new ConfigEntity { Id = SnowflakeHelper.NextId, ConfigKey = "bbs.site.name", ConfigValue = "Yi意社区", ConfigName = "bbs站点名称" }, + new ConfigEntity { Id = SnowflakeHelper.NextId, ConfigKey = "bbs.site.author", ConfigValue = "橙子", ConfigName = "bbs站点作者" }, + new ConfigEntity { Id = SnowflakeHelper.NextId, ConfigKey = "bbs.site.icp", ConfigValue = "2023 意社区 | 赣ICP备xxxxxx号-4", ConfigName = "bbs备案号" }, + new ConfigEntity { Id = SnowflakeHelper.NextId, ConfigKey = "bbs.site.bottom", ConfigValue = "YiFramework意框架", ConfigName = "bbs底部信息" }, + }; + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsMenuDataSeed.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsMenuDataSeed.cs new file mode 100644 index 00000000..381192ca --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/DataSeeds/BbsMenuDataSeed.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.BBS.Domain.DataSeed +{ + [AppService(typeof(IDataSeed))] + public class BbsMenuDataSeed : AbstractDataSeed + { + public BbsMenuDataSeed(IRepository repository) : base(repository) + { + } + + public override async Task IsInvoker() + { + return !await _repository.IsAnyAsync(x => x.MenuName == "BBS"); + } + public override List GetSeedData() + { + List entities = new List(); + + //BBS + MenuEntity bbs = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "BBS", + MenuType = MenuTypeEnum.Catalogue, + Router = "/bbs", + IsShow = true, + IsLink = false, + MenuIcon = "international", + OrderNum = 97, + ParentId = 0, + IsDeleted = false + }; + entities.Add(bbs); + + + //评论管理 + MenuEntity comment = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "评论管理", + PermissionCode = "bbs:comment:list", + MenuType = MenuTypeEnum.Menu, + Router = "comment", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "bbs/comment/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = bbs.Id, + IsDeleted = false + }; + entities.Add(comment); + + MenuEntity commentQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "评论查询", + PermissionCode = "bbs:comment:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = comment.Id, + IsDeleted = false + }; + entities.Add(commentQuery); + + MenuEntity commentAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "评论新增", + PermissionCode = "bbs:comment:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = comment.Id, + IsDeleted = false + }; + entities.Add(commentAdd); + + MenuEntity commentEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "评论修改", + PermissionCode = "bbs:comment:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = comment.Id, + IsDeleted = false + }; + entities.Add(commentEdit); + + MenuEntity commentRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "评论删除", + PermissionCode = "bbs:comment:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = comment.Id, + IsDeleted = false + }; + entities.Add(commentRemove); + + + //文章管理 + MenuEntity article = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "文章管理", + PermissionCode = "bbs:article:list", + MenuType = MenuTypeEnum.Menu, + Router = "article", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "bbs/article/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = bbs.Id, + IsDeleted = false + }; + entities.Add(article); + + MenuEntity articleQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "文章查询", + PermissionCode = "bbs:article:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = article.Id, + IsDeleted = false + }; + entities.Add(articleQuery); + + MenuEntity articleAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "文章新增", + PermissionCode = "bbs:article:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = article.Id, + IsDeleted = false + }; + entities.Add(articleAdd); + + MenuEntity articleEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "文章修改", + PermissionCode = "bbs:article:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = article.Id, + IsDeleted = false + }; + entities.Add(articleEdit); + + MenuEntity articleRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "文章删除", + PermissionCode = "bbs:article:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = article.Id, + IsDeleted = false + }; + entities.Add(articleRemove); + + + //主题管理 + MenuEntity discuss = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "主题管理", + PermissionCode = "bbs:discuss:list", + MenuType = MenuTypeEnum.Menu, + Router = "discuss", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "bbs/discuss/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = bbs.Id, + IsDeleted = false + }; + entities.Add(discuss); + + MenuEntity discussQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "主题查询", + PermissionCode = "bbs:discuss:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = discuss.Id, + IsDeleted = false + }; + entities.Add(discussQuery); + + MenuEntity discussAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "主题新增", + PermissionCode = "bbs:discuss:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = discuss.Id, + IsDeleted = false + }; + entities.Add(discussAdd); + + MenuEntity discussEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "主题修改", + PermissionCode = "bbs:discuss:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = discuss.Id, + IsDeleted = false + }; + entities.Add(discussEdit); + + MenuEntity discussRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "主题删除", + PermissionCode = "bbs:discuss:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = discuss.Id, + IsDeleted = false + }; + entities.Add(discussRemove); + + + + //板块管理 + MenuEntity plate = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "板块管理", + PermissionCode = "bbs:plate:list", + MenuType = MenuTypeEnum.Menu, + Router = "plate", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "bbs/plate/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = bbs.Id, + IsDeleted = false + }; + entities.Add(plate); + + MenuEntity plateQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "板块查询", + PermissionCode = "bbs:plate:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = plate.Id, + IsDeleted = false + }; + entities.Add(plateQuery); + + MenuEntity plateAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "板块新增", + PermissionCode = "bbs:plate:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = plate.Id, + IsDeleted = false + }; + entities.Add(plateAdd); + + MenuEntity plateEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "板块修改", + PermissionCode = "bbs:plate:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = plate.Id, + IsDeleted = false + }; + entities.Add(plateEdit); + + MenuEntity plateRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "板块删除", + PermissionCode = "bbs:plate:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = plate.Id, + IsDeleted = false + }; + entities.Add(plateRemove); + + //默认值 + entities.ForEach(m => + { + m.IsDeleted = false; + m.State = true; + }); + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/AgreeEntity .cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/AgreeEntity .cs new file mode 100644 index 00000000..37ab217f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/AgreeEntity .cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Exhibition.Entities +{ + [SugarTable("Agree")] + public class AgreeEntity : IEntity, ICreationAuditedObject + { + public AgreeEntity() + { + } + + public AgreeEntity(long discussId) + { + DiscussId = discussId; + } + + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } = SnowflakeHelper.NextId; + public DateTime CreationTime { get; set; } + + /// + /// 主题id + /// + public long DiscussId { get; set; } + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/BannerEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/BannerEntity.cs new file mode 100644 index 00000000..828fb743 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Exhibition/Entities/BannerEntity.cs @@ -0,0 +1,30 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Exhibition.Entities +{ + [SugarTable("Banner")] + public class BannerEntity : IEntity, ISoftDelete, IAuditedObject + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Color { get; set; } + public bool IsDeleted { get; set; } + public DateTime CreationTime { get; set; } + + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/ArticleEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/ArticleEntity.cs new file mode 100644 index 00000000..f4700fb9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/ArticleEntity.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Http; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + [SugarTable("Article")] + public class ArticleEntity : IEntity, ISoftDelete + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public bool IsDeleted { get; set; } + + [SugarColumn(Length = 999999)] + public string Content { get; set; } + public string Name { get; set; } + + + public long DiscussId { get; set; } + + public long ParentId { get; set; } + + [SugarColumn(IsIgnore =true)] + + public List Children { get; set; } + } + + public static class ArticleEntityExtensions + { + /// + /// 平铺自己 + /// + /// + /// + public static List Tile(this List entities) + { + if(entities is null)return new List(); + var result = new List(); + return StartRecursion(entities, result); + } + + private static List StartRecursion(List entities, List result) + { + foreach (var entity in entities) + { + result.Add(entity); + if (entity.Children is not null && entity.Children.Where(x => x.IsDeleted == false).Count() > 0) + { + StartRecursion(entity.Children, result); + } + } + return result; + } + + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/CommentEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/CommentEntity.cs new file mode 100644 index 00000000..21372609 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/CommentEntity.cs @@ -0,0 +1,70 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + + /// + /// 评论表 + /// + [SugarTable("Comment")] + public class CommentEntity : IEntity, ISoftDelete,IAuditedObject + { + /// + /// 采用二维数组方式,不使用树形方式 + /// + public CommentEntity() + { + } + + internal CommentEntity(long discussId) + { + DiscussId= discussId; + } + + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public bool IsDeleted { get; set; } + public string Content { get; set; } + + public long DiscussId { get; set; } + + /// + /// 被回复的CommentId + /// + public long ParentId { get; set; } + public DateTime CreationTime { get; set; } + + public long RootId { get; set; } + + [SugarColumn(IsIgnore = true)] + public List Children { get; set; } = new(); + + + /// + /// 用户,评论人用户信息 + /// + [Navigate(NavigateType.OneToOne, nameof(CreatorId))] + public UserEntity CreateUser { get; set; } + + /// + /// 被评论的用户信息 + /// + [SugarColumn(IsIgnore = true)] + public UserEntity CommentedUser { get; set; } + + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussEntity.cs new file mode 100644 index 00000000..c14ecc64 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussEntity.cs @@ -0,0 +1,67 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Yi.BBS.Domain.Shared.Forum.EnumClasses; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + [SugarTable("Discuss")] + public class DiscussEntity : IEntity, ISoftDelete, IAuditedObject + { + public DiscussEntity() + { + } + public DiscussEntity(long plateId) + { + PlateId = plateId; + } + + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public string Title { get; set; } + public string? Types { get; set; } + public string? Introduction { get; set; } + public int AgreeNum { get; set; } + public int SeeNum { get; set; } + /// + /// 封面 + /// + public string? Cover { get; set; } + + [SugarColumn(Length =999999)] + public string Content { get; set; } + + public string? Color { get; set; } + + public bool IsDeleted { get; set; } + + //是否置顶,默认false + public bool IsTop { get; set; } + + + public DiscussPermissionTypeEnum PermissionType { get; set; } + + public long PlateId { get; set; } + public DateTime CreationTime { get; set; } + + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + + + /// + /// 当PermissionType为部分用户时候,以下列表中的用户+创建者 代表拥有权限 + /// + [SugarColumn(IsJson = true)]//使用json处理 + public List? PermissionUserIds { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussMyTypeEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussMyTypeEntity.cs new file mode 100644 index 00000000..56440647 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/DiscussMyTypeEntity.cs @@ -0,0 +1,21 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + [SugarTable("DiscussMyType")] + public class DiscussMyTypeEntity : IEntity + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + public long DiscussId { get; set; } + + public long MyTypeId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/MyTypeEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/MyTypeEntity.cs new file mode 100644 index 00000000..3dee5b65 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/MyTypeEntity.cs @@ -0,0 +1,25 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + [SugarTable("MyType")] + public class MyTypeEntity : IEntity, ISoftDelete + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public bool IsDeleted { get; set; } + + public string Name { get; set; } + public string? Color { get; set; } + public string? BackgroundColor { get; set; } + + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/PlateEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/PlateEntity.cs new file mode 100644 index 00000000..f2901366 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Entities/PlateEntity.cs @@ -0,0 +1,23 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.Forum.Entities +{ + [SugarTable("Plate")] + public class PlateEntity : IEntity, ISoftDelete + { + + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public string Name { get; set; } + public string? Logo { get; set; } + public string? Introduction { get; set; } + public bool IsDeleted { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Event/SeeDiscussEventHandler.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Event/SeeDiscussEventHandler.cs new file mode 100644 index 00000000..e1e18b47 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Event/SeeDiscussEventHandler.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cike.EventBus.EventHandlerAbstracts; +using Yi.BBS.Domain.Forum.Entities; +using Yi.BBS.Domain.Shared.Forum.Etos; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Shared.Identity.Etos; + +namespace Yi.BBS.Domain.Forum.Event +{ + public class SeeDiscussEventHandler : IDistributedEventHandler + { + private IRepository _repository; + public SeeDiscussEventHandler(IRepository repository) + { + _repository = repository; + } + public async Task HandlerAsync(SeeDiscussEventArgs eventData) + { + var entity= await _repository.GetByIdAsync(eventData.DiscussId); + if (entity is not null) { + entity.SeeNum += 1; + await _repository.UpdateAsync(entity); + } + + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/ForumManager.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/ForumManager.cs new file mode 100644 index 00000000..1e713008 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/ForumManager.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Forum.Entities; +using Yi.BBS.Domain.Shared.Forum.ConstClasses; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.BBS.Domain.Forum +{ + /// + /// 论坛模块的领域服务 + /// + [AppService] + public class ForumManager + { + private readonly IRepository _discussRepository; + private readonly IRepository _plateEntityRepository; + private readonly IRepository _commentRepository; + public ForumManager(IRepository discussRepository, IRepository plateEntityRepository, IRepository commentRepository) + { + _discussRepository = discussRepository; + _plateEntityRepository = plateEntityRepository; + _commentRepository = commentRepository; + } + + //主题是不能直接创建的,需要由领域服务统一创建 + public async Task CreateDiscussAsync(DiscussEntity entity) + { + entity.Id = SnowflakeHelper.NextId; + entity.CreationTime = DateTime.Now; + entity.AgreeNum = 0; + entity.SeeNum = 0; + return await _discussRepository.InsertReturnEntityAsync(entity); + } + + public async Task CreateCommentAsync(long discussId,long parentId,long rootId, string content) + { + var entity = new CommentEntity(discussId); + entity.Id = SnowflakeHelper.NextId; + entity.Content = content; + entity.ParentId = parentId; + entity.RootId = rootId; + return await _commentRepository.InsertReturnEntityAsync(entity); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Repositories/IArticleRepository.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Repositories/IArticleRepository.cs new file mode 100644 index 00000000..c8056a9f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Forum/Repositories/IArticleRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Forum.Entities; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.BBS.Domain.Forum.Repositories +{ + public interface IArticleRepository:IRepository + { + Task> GetTreeAsync(Expression> where); + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/GlobalSetting/Entities/SettingEntity.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/GlobalSetting/Entities/SettingEntity.cs new file mode 100644 index 00000000..69433035 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/GlobalSetting/Entities/SettingEntity.cs @@ -0,0 +1,24 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.BBS.Domain.GlobalSetting.Entities +{ + [SugarTable("Setting")] + public class SettingEntity : IEntity + { + + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + public int CommentPage { get; set; } + public int DiscussPage { get; set; } + public int CommentExperience { get; set; } + public int DiscussExperience { get; set; } + public string Title { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.Domain.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.Domain.csproj new file mode 100644 index 00000000..0bf41efa --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.Domain.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.DomainSwaggerDoc.xml b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.DomainSwaggerDoc.xml new file mode 100644 index 00000000..1882b0e9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/Yi.BBS.DomainSwaggerDoc.xml @@ -0,0 +1,65 @@ + + + + Yi.BBS.Domain + + + + + 主题id + + + + + 创建者 + + + + + 平铺自己 + + + + + + + 评论表 + + + + + 采用二维数组方式,不使用树形方式 + + + + + 被回复的CommentId + + + + + 用户,评论人用户信息 + + + + + 被评论的用户信息 + + + + + 封面 + + + + + 当PermissionType为部分用户时候,以下列表中的用户+创建者 代表拥有权限 + + + + + 论坛模块的领域服务 + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/YiBBSDomainModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/YiBBSDomainModule.cs new file mode 100644 index 00000000..c9520e98 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Domain/YiBBSDomainModule.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.BBS.Domain.Shared; + +namespace Yi.BBS.Domain +{ + [DependsOn( + typeof(YiBBSDomainSharedModule) + )] + public class YiBBSDomainModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Repositories/ArticleRepository.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Repositories/ArticleRepository.cs new file mode 100644 index 00000000..0b23a30a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Repositories/ArticleRepository.cs @@ -0,0 +1,27 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Yi.BBS.Domain.Forum.Entities; +using Yi.BBS.Domain.Forum.Repositories; +using Yi.Framework.Core.Sqlsugar.Repositories; +using Yi.Framework.Ddd.Repositories; + +namespace Yi.BBS.Sqlsugar.Repositories +{ + [AppService] + public class ArticleRepository : SqlsugarRepository, IArticleRepository + { + public ArticleRepository(ISqlSugarClient context) : base(context) + { + } + + public async Task> GetTreeAsync(Expression> where) + { + return await _DbQueryable.Where(where).ToTreeAsync(x => x.Children, x => x.ParentId, 0); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Yi.BBS.Sqlsugar.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Yi.BBS.Sqlsugar.csproj new file mode 100644 index 00000000..96d709be --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/Yi.BBS.Sqlsugar.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/YiBBSSqlsugarModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/YiBBSSqlsugarModule.cs new file mode 100644 index 00000000..82f1798a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Sqlsugar/YiBBSSqlsugarModule.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Sqlsugar; +using Yi.BBS.Domain; +using Yi.RBAC.Sqlsugar; +using SqlSugar; + +namespace Yi.BBS.Sqlsugar +{ + [DependsOn(typeof(YiFrameworkCoreSqlsugarModule), + typeof(YiBBSDomainModule), + typeof(YiRBACSqlsugarModule))] + public class YiBBSSqlsugarModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //services.AddTransient(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/.config/dotnet-tools.json b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/.config/dotnet-tools.json new file mode 100644 index 00000000..3aca4744 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.4", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Program.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Program.cs new file mode 100644 index 00000000..208cd696 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Program.cs @@ -0,0 +1,34 @@ +using AspNetCore.Microsoft.AspNetCore.Hosting; +using Yi.Framework.Core.Autofac.Extensions; +using Yi.Framework.Core.Autofac.Modules; +using Yi.Framework.Core.Extensions; +using Yi.BBS.Web; +using Yi.Framework.Core.Module; +using NLog.Extensions.Logging; +using NLog; +using SqlSugar; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddLogging(builder => { builder.ClearProviders().AddNLog("nlog.config").SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); }); +Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(Program).Assembly).GetCurrentClassLogger(); +_logger.Info("-----( ¯ □ ¯ )YiFrameowrk框架启动-----"); + +builder.WebHost.UseStartUrlsServer(builder.Configuration); + +builder.UseYiModules(typeof(YiBBSWebModule)); + +//添加autofac模块,需要添加模块 +builder.Host.ConfigureAutoFacContainer(container => +{ + container.RegisterYiModule(AutoFacModuleEnum.PropertiesAutowiredModule, ModuleAssembly.Assemblies); +}); + +var app = builder.Build(); +var db = app.Services.GetService(); +app.UseErrorHandlingServer(); + +app.UseAuthentication(); +app.UseAuthorization(); +app.MapControllers(); + +app.Run(); diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Properties/launchSettings.json b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Properties/launchSettings.json new file mode 100644 index 00000000..f6eca37f --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "Yi.BBS.Web": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:19001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Yi.BBS.Web.csproj b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Yi.BBS.Web.csproj new file mode 100644 index 00000000..cbfa880b --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/Yi.BBS.Web.csproj @@ -0,0 +1,52 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + + + + Always + + + Always + + + Always + + + Always + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/YiBBSWebModule.cs b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/YiBBSWebModule.cs new file mode 100644 index 00000000..490917be --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/YiBBSWebModule.cs @@ -0,0 +1,60 @@ +using AspNetCore.Microsoft.AspNetCore.Builder; +using StartupModules; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.BBS.Application; +using Yi.BBS.Sqlsugar; +using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection; +using Yi.Framework.Core.Autofac; +using Yi.RBAC.Application; +using Yi.Framework.AspNetCore; +using Yi.Framework.Data.Json; +using Yi.Framework.OperLogManager; +using Yi.Framework.Core.Module; +using Microsoft.Extensions.Options; +using System.Text.Json.Serialization; + +namespace Yi.BBS.Web +{ + [DependsOn( + typeof(YiBBSSqlsugarModule), + typeof(YiFrameworkAspNetCoreModule), + typeof(YiFrameworkCoreAutofacModule), + typeof(YiBBSApplicationModule) + )] + public class YiBBSWebModule : IStartupModule + { + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //添加控制器与动态api + services.AddControllers().AddJsonOptions(opt => { + opt.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + opt.JsonSerializerOptions.Converters.Add(new LongToStringConverter()); + opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + + services.AddAutoApiService(opt => + { + //NETServiceTest所在程序集添加进动态api配置 + opt.CreateConventional(ModuleAssembly.Assemblies, option => option.RootPath = string.Empty); + }); + + //添加swagger + services.AddSwaggerServer(); + } + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + //if (app.Environment.IsDevelopment()) + { + app.UseSwaggerServer(); + } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + app.UseRouting(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/appsettings.json b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/appsettings.json new file mode 100644 index 00000000..43792456 --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/appsettings.json @@ -0,0 +1,48 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "Microsoft.AspNetCore": "Information" + } + }, + "AllowedHosts": "*", + + //程序启动地址,*代表全部网口 + "StartUrl": "http://*:19001", + + //数据库类型列表 + "DbList": [ "Sqlite", "Mysql", "Sqlserver", "Oracle" ], + + "DbConnOptions": { + "Url": "DataSource=yi-sqlsugar-dev.db", + "DbType": "Sqlite", + "EnabledReadWrite": false, + "EnabledCodeFirst": false, + "EntityAssembly": null, + "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 + ] + }, + + //授权 + "JwtTokenOptions": { + "Audience": "yi", + "Issuer": "localhost:19002", + "Subject": "yiframwork", + "ExpSecond": 259200 + }, + + //开启种子数据 + "EnabledDataSeed": false, + + //阿里云短信 + "SmsAliyunOptions": { + "AccessKeyId": "", + "AccessKeySecret": "", + "SignName": "", + "TemplateCode": "", + "EnableFeature": false + } +} diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/ip2region.db b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/ip2region.db new file mode 100644 index 00000000..0fc60e6c Binary files /dev/null and b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/ip2region.db differ diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/key.pem b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/key.pem new file mode 100644 index 00000000..3314ab6e --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj +MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu +NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ +qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg +p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR +ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi +VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV +laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8 +sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H +mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY +dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw +ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ +DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T +N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t +0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv +t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU +AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk +48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL +DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK +xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA +mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh +2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz +et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr +VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD +TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc +dn/RsYEONbwQSjIfMPkvxF+8HQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/nlog.config b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/nlog.config new file mode 100644 index 00000000..d4224b1a --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/nlog.config @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/public.pem b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/public.pem new file mode 100644 index 00000000..1c9b622d --- /dev/null +++ b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo +4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u ++qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh +kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ +0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg +cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc +mwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/yi-sqlsugar-dev.db b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/yi-sqlsugar-dev.db new file mode 100644 index 00000000..32705633 Binary files /dev/null and b/Yi.Framework.Net6/src/project/BBS/Yi.BBS.Web/yi-sqlsugar-dev.db differ diff --git a/Yi.Framework.Net6/src/project/Template/GlobalUsings.cs b/Yi.Framework.Net6/src/project/Template/GlobalUsings.cs new file mode 100644 index 00000000..d6ecb816 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Yi.Framework.Core.Attributes; +global using Yi.Framework.Core.Helper; +global using Yi.Framework.Core.Model; +global using Yi.Framework.Core.Exceptions; \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/ApplicationContractsSwaggerDoc.xml b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/ApplicationContractsSwaggerDoc.xml new file mode 100644 index 00000000..b9705a65 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/ApplicationContractsSwaggerDoc.xml @@ -0,0 +1,18 @@ + + + + Yi.Template.Application.Contracts + + + + + Student输入创建对象 + + + + + Student + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentCreateInputVo.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentCreateInputVo.cs new file mode 100644 index 00000000..749e9f76 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentCreateInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Template.Application.Contracts.School.Dtos +{ + /// + /// Student输入创建对象 + /// + public class StudentCreateInputVo + { + public string Name { get; set; } + public int? Height { get; set; } + public string? Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListInputVo.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListInputVo.cs new file mode 100644 index 00000000..2dc834cc --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListInputVo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Template.Application.Contracts.School.Dtos +{ + public class StudentGetListInputVo : PagedAndSortedResultRequestDto + { + public string Name { get; set; } + public int? Height { get; set; } + public string? Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListOutputDto.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListOutputDto.cs new file mode 100644 index 00000000..009102ba --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetListOutputDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Template.Application.Contracts.School.Dtos +{ + public class StudentGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public string Name { get; set; } + public int? Height { get; set; } + public string? Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetOutputDto.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetOutputDto.cs new file mode 100644 index 00000000..22afda93 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentGetOutputDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.Template.Application.Contracts.School.Dtos +{ + public class StudentGetOutputDto : IEntityDto + { + public long Id { get; set; } + public string Name { get; set; } + public int? Height { get; set; } + public string? Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentUpdateInputVo.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentUpdateInputVo.cs new file mode 100644 index 00000000..4121fbb6 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/Dtos/Student/StudentUpdateInputVo.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Template.Application.Contracts.School.Dtos +{ + public class StudentUpdateInputVo + { + public string Name { get; set; } + public int? Height { get; set; } + public string? Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/IStudentService.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/IStudentService.cs new file mode 100644 index 00000000..a721c5e3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/School/IStudentService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Template.Application.Contracts.School.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.Template.Application.Contracts.School +{ + /// + /// Student + /// + public interface IStudentService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/Yi.Template.Application.Contracts.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/Yi.Template.Application.Contracts.csproj new file mode 100644 index 00000000..ea141dde --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/Yi.Template.Application.Contracts.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + True + ./ApplicationContractsSwaggerDoc.xml + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/YiTemplateApplicationContractsModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/YiTemplateApplicationContractsModule.cs new file mode 100644 index 00000000..d2ea5d76 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application.Contracts/YiTemplateApplicationContractsModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Template.Domain.Shared; + +namespace Yi.Template.Application.Contracts +{ + [DependsOn( + typeof(YiTemplateDomainSharedModule) + )] + public class YiTemplateApplicationContractsModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/ApplicationSwaggerDoc.xml b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/ApplicationSwaggerDoc.xml new file mode 100644 index 00000000..da7b20a5 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/ApplicationSwaggerDoc.xml @@ -0,0 +1,13 @@ + + + + Yi.Template.Application + + + + + Student服务实现 + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/School/StudentService.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/School/StudentService.cs new file mode 100644 index 00000000..cd961206 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/School/StudentService.cs @@ -0,0 +1,17 @@ +using Yi.Template.Application.Contracts.School; +using Cike.AutoWebApi.Setting; +using Yi.Template.Application.Contracts.School.Dtos; +using Yi.Template.Domain.School.Entities; +using Yi.Framework.Ddd.Services; + +namespace Yi.Template.Application.School +{ + /// + /// Student服务实现 + /// + [AppService] + public class StudentService : CrudAppService, + IStudentService, IAutoApiService + { + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/Yi.Template.Application.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/Yi.Template.Application.csproj new file mode 100644 index 00000000..0a5bab98 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/Yi.Template.Application.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + True + ./ApplicationSwaggerDoc.xml + + + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/YiTemplateApplicationModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/YiTemplateApplicationModule.cs new file mode 100644 index 00000000..c58eb473 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Application/YiTemplateApplicationModule.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Template.Application.Contracts; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.Framework.Ddd; +using Yi.Template.Domain; + +namespace Yi.Template.Application +{ + [DependsOn( + typeof(YiTemplateApplicationContractsModule), + typeof(YiTemplateDomainModule), + typeof(YiFrameworkAuthJwtBearerModule) + )] + public class YiTemplateApplicationModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/School/ConstClasses/StudentConst.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/School/ConstClasses/StudentConst.cs new file mode 100644 index 00000000..f22c18ed --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/School/ConstClasses/StudentConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Template.Domain.Shared.School.ConstClasses +{ + /// + /// 常量定义 + /// + + public class StudentConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/Yi.Template.Domain.Shared.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/Yi.Template.Domain.Shared.csproj new file mode 100644 index 00000000..692994fe --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/Yi.Template.Domain.Shared.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/YiTemplateDomainSharedModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/YiTemplateDomainSharedModule.cs new file mode 100644 index 00000000..4e14cee3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain.Shared/YiTemplateDomainSharedModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Ddd; + +namespace Yi.Template.Domain.Shared +{ + [DependsOn( + typeof(YiFrameworkDddModule) + )] + public class YiTemplateDomainSharedModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/DomainSwaggerDoc.xml b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/DomainSwaggerDoc.xml new file mode 100644 index 00000000..01f6d524 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/DomainSwaggerDoc.xml @@ -0,0 +1,8 @@ + + + + Yi.Template.Domain + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/DataSeeds/StudentDataSeed.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/DataSeeds/StudentDataSeed.cs new file mode 100644 index 00000000..bb3092b9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/DataSeeds/StudentDataSeed.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.Template.Domain.School.Entities; + +namespace Yi.Template.Domain.School.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class StudentDataSeed : AbstractDataSeed + { + public StudentDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + return new List() { new StudentEntity { Id = SnowflakeHelper.NextId, Name = "你好", Phone = "123", Height = 188, IsDeleted = false } , + new StudentEntity { Id = SnowflakeHelper.NextId, Name = "你好1", Phone = "123", Height = 188, IsDeleted = false }, + new StudentEntity { Id = SnowflakeHelper.NextId, Name = "你好2", Phone = "123", Height = 188, IsDeleted = false } + }; + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/Entities/StudentEntity.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/Entities/StudentEntity.cs new file mode 100644 index 00000000..61245c3e --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/School/Entities/StudentEntity.cs @@ -0,0 +1,25 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.Template.Domain.School.Entities +{ + [SugarTable("Student")] + public class StudentEntity : IEntity,ISoftDelete + { + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + public string Name { get; set; } + + public int? Height { get; set; } + + public string? Phone { get; set; } + public bool IsDeleted { get; set; } = false; + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/Yi.Template.Domain.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/Yi.Template.Domain.csproj new file mode 100644 index 00000000..71936c72 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/Yi.Template.Domain.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + enable + enable + True + ./DomainSwaggerDoc.xml + + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/YiTemplateDomainModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/YiTemplateDomainModule.cs new file mode 100644 index 00000000..e94138cd --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Domain/YiTemplateDomainModule.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.Template.Domain.Shared; + +namespace Yi.Template.Domain +{ + [DependsOn( + typeof(YiTemplateDomainSharedModule), + typeof(YiFrameworkDataModule) + )] + public class YiTemplateDomainModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //services.AddTransient(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/Yi.Template.Sqlsugar.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/Yi.Template.Sqlsugar.csproj new file mode 100644 index 00000000..8f842da8 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/Yi.Template.Sqlsugar.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/YiTemplateSqlsugarModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/YiTemplateSqlsugarModule.cs new file mode 100644 index 00000000..6176073a --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Sqlsugar/YiTemplateSqlsugarModule.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Sqlsugar; +using Yi.Template.Domain; + +namespace Yi.Template.Sqlsugar +{ + [DependsOn(typeof(YiFrameworkCoreSqlsugarModule), + typeof(YiTemplateDomainModule))] + public class YiTemplateSqlsugarModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //services.AddTransient(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Program.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Program.cs new file mode 100644 index 00000000..86c4b3d2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Program.cs @@ -0,0 +1,37 @@ +using AspNetCore.Microsoft.AspNetCore.Hosting; +using NLog; +using NLog.Extensions.Logging; +using Yi.Framework.Core.Autofac.Extensions; +using Yi.Framework.Core.Autofac.Modules; +using Yi.Framework.Core.Extensions; +using Yi.Framework.Core.Module; +using Yi.Template.Web; + + +var builder = WebApplication.CreateBuilder(args); +//配置日志 +builder.Services.AddLogging(builder => { builder.ClearProviders().AddNLog("nlog.config").SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); }); +Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(Program).Assembly).GetCurrentClassLogger(); +_logger.Info("-----( ¯ □ ¯ )YiFrameowrk框架启动-----"); +//设置启动url +builder.WebHost.UseStartUrlsServer(builder.Configuration); + +//添加模块 +builder.UseYiModules(typeof(YiTemplateWebModule)); + +//添加autofac模块,需要添加模块 +builder.Host.ConfigureAutoFacContainer(container => +{ + container.RegisterYiModule(AutoFacModuleEnum.PropertiesAutowiredModule, ModuleAssembly.Assemblies); +}); + +var app = builder.Build(); + +//全局错误中间件,需要放在最早 +app.UseErrorHandlingServer(); + +app.UseAuthentication(); +app.UseAuthorization(); +app.MapControllers(); + +app.Run(); diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Properties/launchSettings.json b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Properties/launchSettings.json new file mode 100644 index 00000000..1384d89f --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "Yi.Template.Web": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:19002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Yi.Template.Web.csproj b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Yi.Template.Web.csproj new file mode 100644 index 00000000..97d143a9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/Yi.Template.Web.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + Always + + + + + + Always + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/YiTemplateWebModule.cs b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/YiTemplateWebModule.cs new file mode 100644 index 00000000..194428a6 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/YiTemplateWebModule.cs @@ -0,0 +1,52 @@ +using AspNetCore.Microsoft.AspNetCore.Builder; +using StartupModules; +using Yi.Framework.AspNetCore; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Autofac; +using Yi.Framework.Core.Module; +using Yi.Framework.Data.Json; +using Yi.Template.Application; +using Yi.Template.Sqlsugar; + +namespace Yi.Template.Web +{ + [DependsOn( + typeof(YiFrameworkAspNetCoreModule), + typeof(YiFrameworkCoreAutofacModule), + typeof(YiTemplateSqlsugarModule), + typeof(YiTemplateApplicationModule) + )] + public class YiTemplateWebModule : IStartupModule + { + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //添加控制器与动态api + services.AddControllers().AddJsonOptions(opt => { + opt.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + }); + services.AddAutoApiService(opt => + { + //NETServiceTest所在程序集添加进动态api配置 + opt.CreateConventional(ModuleAssembly.Assemblies, option => option.RootPath = string.Empty); + }); + + //添加swagger + services.AddSwaggerServer(); + } + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + //if (app.Environment.IsDevelopment()) + { + app.UseSwaggerServer(); + } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + app.UseRouting(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/appsettings.json b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/appsettings.json new file mode 100644 index 00000000..ddf70ea3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/appsettings.json @@ -0,0 +1,41 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + //"Default": "Debug", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + + //程序启动地址,*代表全部网口 + "StartUrl": "http://*:19002", + + //数据库类型列表 + "DbList": [ "Sqlite", "Mysql", "Sqlserver", "Oracle" ], + + "DbConnOptions": { + "Url": "DataSource=yi-sqlsugar-dev.db", + "DbType": "Sqlite", + "EnabledDbSeed": false, + "EnabledReadWrite": false, + "EnabledCodeFirst": true, + "EntityAssembly": null, + "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 + ] + }, + + //授权 + "JwtTokenOptions": { + "Audience": "yi", + "Issuer": "localhost:19002", + "Subject": "yiframwork", + "ExpSecond": 3600 + }, + + //开启种子数据 + "EnabledDataSeed": true +} diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/key.pem b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/key.pem new file mode 100644 index 00000000..3314ab6e --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj +MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu +NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ +qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg +p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR +ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi +VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV +laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8 +sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H +mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY +dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw +ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ +DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T +N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t +0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv +t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU +AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk +48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL +DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK +xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA +mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh +2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz +et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr +VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD +TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc +dn/RsYEONbwQSjIfMPkvxF+8HQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/nlog.config b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/nlog.config new file mode 100644 index 00000000..8d73d112 --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/nlog.config @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/public.pem b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/public.pem new file mode 100644 index 00000000..1c9b622d --- /dev/null +++ b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo +4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u ++qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh +kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ +0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg +cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc +mwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/yi-sqlsugar-dev.db b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/yi-sqlsugar-dev.db new file mode 100644 index 00000000..a53c9587 Binary files /dev/null and b/Yi.Framework.Net6/src/project/Template/Yi.Template.Web/yi-sqlsugar-dev.db differ diff --git a/Yi.Framework.Net6/src/project/rbac/GlobalUsings.cs b/Yi.Framework.Net6/src/project/rbac/GlobalUsings.cs new file mode 100644 index 00000000..d6ecb816 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Yi.Framework.Core.Attributes; +global using Yi.Framework.Core.Helper; +global using Yi.Framework.Core.Model; +global using Yi.Framework.Core.Exceptions; \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/CaptchaImageDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/CaptchaImageDto.cs new file mode 100644 index 00000000..9e71ced7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/CaptchaImageDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class CaptchaImageDto + { + public string Code { get; set; } = string.Empty; + public Guid Uuid { get; set; } = Guid.Empty; + public byte[] Img { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/LoginInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/LoginInputVo.cs new file mode 100644 index 00000000..729e184c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/LoginInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class LoginInputVo + { + public string UserName { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + + public string Uuid { get; set; } + + public string Code { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/PhoneCaptchaImageDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/PhoneCaptchaImageDto.cs new file mode 100644 index 00000000..ddd7ee4f --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/PhoneCaptchaImageDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class PhoneCaptchaImageDto + { + public string Phone { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RegisterDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RegisterDto.cs new file mode 100644 index 00000000..a8f7f1d2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RegisterDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class RegisterDto + { + + //电话号码,根据code的表示来获取 + + /// + /// 账号 + /// + public string UserName { get; set; } = string.Empty; + + /// + /// 密码 + /// + public string Password { get; set; } = string.Empty; + + /// + /// 唯一标识码 + /// + public string? Uuid { get; set; } + + /// + /// 电话 + /// + public long Phone { get; set; } + + /// + /// 验证码 + /// + public string? Code { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RestPasswordDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RestPasswordDto.cs new file mode 100644 index 00000000..22d40ec5 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/RestPasswordDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class RestPasswordDto + { + public string Password = string.Empty; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdateIconDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdateIconDto.cs new file mode 100644 index 00000000..c0e0e2a3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdateIconDto.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class UpdateIconDto + { + public string? Icon { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdatePasswordDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdatePasswordDto.cs new file mode 100644 index 00000000..132cd43b --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Account/UpdatePasswordDto.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.Account +{ + public class UpdatePasswordDto + { + public string NewPassword { get; set; } = string.Empty; + public string OldPassword { get; set; } = string.Empty; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptCreateInputVo.cs new file mode 100644 index 00000000..7ed81542 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptCreateInputVo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + /// + /// Dept输入创建对象 + /// + public class DeptCreateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string DeptName { get; set; }=string.Empty; + public string DeptCode { get; set; } = string.Empty; + public string? Leader { get; set; } + public long ParentId { get; set; } + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListInputVo.cs new file mode 100644 index 00000000..c414ccdb --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListInputVo.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Enums; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + [QueryParameter] + public class DeptGetListInputVo : PagedAllResultRequestDto + { + [QueryParameter(QueryOperatorEnum.Equal)] + public long Id { get; set; } + [QueryParameter(QueryOperatorEnum.Equal, ColumnType = ColumnTypeEnum.@bool)] + public bool? State { get; set; } + [QueryParameter(QueryOperatorEnum.Like)] + public string? DeptName { get; set; } + [QueryParameter(QueryOperatorEnum.Equal)] + public string? DeptCode { get; set; } + [QueryParameter(QueryOperatorEnum.Equal)] + public string? Leader { get; set; } + + [QueryParameter(QueryOperatorEnum.GreaterThanOrEqual, ColumnName = "CreationTime",ColumnType =ColumnTypeEnum.datetime)] + public DateTime? StartTime { get; set; } + [QueryParameter(QueryOperatorEnum.LessThanOrEqual, ColumnName = "CreationTime", ColumnType = ColumnTypeEnum.datetime)] + public DateTime? EndTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListOutputDto.cs new file mode 100644 index 00000000..ab227da0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetListOutputDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class DeptGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string DeptName { get; set; }=string.Empty; + public string DeptCode { get; set; } = string.Empty; + public string? Leader { get; set; } + public long ParentId { get; set; } + public string? Remark { get; set; } + + public int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetOutputDto.cs new file mode 100644 index 00000000..12fcd95f --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptGetOutputDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class DeptGetOutputDto : IEntityDto + { + public long Id { get; set; } + public bool State { get; set; } + public string DeptName { get; set; }=string.Empty; + public string DeptCode { get; set; } = string.Empty; + public string? Leader { get; set; } + public string? Remark { get; set; } + + public long? deptId { get; set; } + + public int OrderNum { get; set; } + + public long ParentId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptUpdateInputVo.cs new file mode 100644 index 00000000..89b53f79 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Dept/DeptUpdateInputVo.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class DeptUpdateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string DeptName { get; set; }=string.Empty; + public string DeptCode { get; set; } = string.Empty; + public string? Leader { get; set; } + public long ParentId { get; set; } + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuCreateInputVo.cs new file mode 100644 index 00000000..73ee70df --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuCreateInputVo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + /// + /// Menu输入创建对象 + /// + public class MenuCreateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string MenuName { get; set; } = string.Empty; + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Menu; + public string? PermissionCode { get; set; } + public long ParentId { get; set; } + public string? MenuIcon { get; set; } + public string? Router { get; set; } + public bool IsLink { get; set; } + public bool IsCache { get; set; } + public bool IsShow { get; set; } = true; + public string? Remark { get; set; } + public string? Component { get; set; } + public string? Query { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListInputVo.cs new file mode 100644 index 00000000..31a42e8e --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class MenuGetListInputVo : PagedAndSortedResultRequestDto + { + + public bool? State { get; set; } + public string? MenuName { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListOutputDto.cs new file mode 100644 index 00000000..5a4eec02 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetListOutputDto.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class MenuGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string MenuName { get; set; } = string.Empty; + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Menu; + public string? PermissionCode { get; set; } + public long ParentId { get; set; } + public string? MenuIcon { get; set; } + public string? Router { get; set; } + public bool IsLink { get; set; } + public bool IsCache { get; set; } + public bool IsShow { get; set; } = true; + public string? Remark { get; set; } + public string? Component { get; set; } + public string? Query { get; set; } + + public int OrderNum { get; set; } + //public List? Children { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetOutputDto.cs new file mode 100644 index 00000000..cbfc8a2c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuGetOutputDto.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class MenuGetOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string MenuName { get; set; } = string.Empty; + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Menu; + public string? PermissionCode { get; set; } + public long ParentId { get; set; } + public string? MenuIcon { get; set; } + public string? Router { get; set; } + public bool IsLink { get; set; } + public bool IsCache { get; set; } + public bool IsShow { get; set; } = true; + public string? Remark { get; set; } + public string? Component { get; set; } + public string? Query { get; set; } + + public int OrderNum { get; set; } + + //public List? Children { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuUpdateInputVo.cs new file mode 100644 index 00000000..30bd9042 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Menu/MenuUpdateInputVo.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class MenuUpdateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string MenuName { get; set; } = string.Empty; + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Menu; + public string? PermissionCode { get; set; } + public long ParentId { get; set; } + public string? MenuIcon { get; set; } + public string? Router { get; set; } + public bool IsLink { get; set; } + public bool IsCache { get; set; } + public bool IsShow { get; set; } = true; + public string? Remark { get; set; } + public string? Component { get; set; } + public string? Query { get; set; } + //public List? Children { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostCreateInputVo.cs new file mode 100644 index 00000000..7683c3c2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostCreateInputVo.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + /// + /// Post输入创建对象 + /// + public class PostCreateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string PostCode { get; set; }=string.Empty; + public string PostName { get; set; } = string.Empty; + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListInputVo.cs new file mode 100644 index 00000000..94741ff2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListInputVo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class PostGetListInputVo : PagedAndSortedResultRequestDto + { + public bool? State { get; set; } + //public string? PostCode { get; set; }=string.Empty; + public string? PostName { get; set; } = string.Empty; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListOutputDto.cs new file mode 100644 index 00000000..86402f91 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetListOutputDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class PostGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public bool State { get; set; } + public string PostCode { get; set; }=string.Empty; + public string PostName { get; set; } = string.Empty; + public string? Remark { get; set; } + + public int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetOutputDto.cs new file mode 100644 index 00000000..0392c796 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostGetOutputDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class PostGetOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string PostCode { get; set; }=string.Empty; + public string PostName { get; set; } = string.Empty; + public string? Remark { get; set; } + + public int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostUpdateInputVo.cs new file mode 100644 index 00000000..5f63aec9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Post/PostUpdateInputVo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class PostUpdateInputVo + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public bool State { get; set; } + public string PostCode { get; set; }=string.Empty; + public string PostName { get; set; } = string.Empty; + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleCreateInputVo.cs new file mode 100644 index 00000000..16eaf991 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleCreateInputVo.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + /// + /// Role输入创建对象 + /// + public class RoleCreateInputVo + { + public string? RoleName { get; set; } + public string? RoleCode { get; set; } + public string? Remark { get; set; } + public DataScopeEnum DataScope { get; set; } = DataScopeEnum.ALL; + public bool State { get; set; } = true; + + public int OrderNum { get; set; } + + public List DeptIds { get; set; } + + public List MenuIds { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListInputVo.cs new file mode 100644 index 00000000..36189532 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListInputVo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class RoleGetListInputVo : PagedAllResultRequestDto + { + public string? RoleName { get; set; } + public string? RoleCode { get; set; } + public bool? State { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListOutputDto.cs new file mode 100644 index 00000000..4b88acb7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetListOutputDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class RoleGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? RoleName { get; set; } + public string? RoleCode { get; set; } + public string? Remark { get; set; } + public DataScopeEnum DataScope { get; set; } = DataScopeEnum.ALL; + public bool State { get; set; } + + public int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetOutputDto.cs new file mode 100644 index 00000000..8b843468 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleGetOutputDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class RoleGetOutputDto : IEntityDto + { + public long Id { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + public string? RoleName { get; set; } + public string? RoleCode { get; set; } + public string? Remark { get; set; } + public DataScopeEnum DataScope { get; set; } = DataScopeEnum.ALL; + public bool State { get; set; } + + public int OrderNum { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleUpdateInputVo.cs new file mode 100644 index 00000000..a70f10c1 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/Role/RoleUpdateInputVo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class RoleUpdateInputVo + { + public string? RoleName { get; set; } + public string? RoleCode { get; set; } + public string? Remark { get; set; } + public DataScopeEnum DataScope { get; set; } = DataScopeEnum.ALL; + public bool State { get; set; } + + public int OrderNum { get; set; } + + public List DeptIds { get; set; } + + public List MenuIds { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/ProfileUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/ProfileUpdateInputVo.cs new file mode 100644 index 00000000..8a3b77d4 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/ProfileUpdateInputVo.cs @@ -0,0 +1,23 @@ +using Mapster; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos.User +{ + public class ProfileUpdateInputVo + { + public string? Name { get; set; } + public int? Age { get; set; } + public string? Nick { get; set; } + public string? Email { get; set; } + public string? Address { get; set; } + public long? Phone { get; set; } + public string? Introduction { get; set; } + public string? Remark { get; set; } + public SexEnum? Sex { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserCreateInputVo.cs new file mode 100644 index 00000000..c5f0ac0b --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserCreateInputVo.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + /// + /// User输入创建对象 + /// + public class UserCreateInputVo + { + public string? Name { get; set; } + public int? Age { get; set; } + public string UserName { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + public string? Icon { get; set; } + public string? Nick { get; set; } + public string? Email { get; set; } + public string? Address { get; set; } + public long? Phone { get; set; } + public string? Introduction { get; set; } + public string? Remark { get; set; } + public SexEnum Sex { get; set; } = SexEnum.Unknown; + public List? RoleIds { get; set; } + public List? PostIds { get; set; } + public long? DeptId { get; set; } + public bool State { get; set; } = true; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListInputVo.cs new file mode 100644 index 00000000..5a3ffc49 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListInputVo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class UserGetListInputVo : PagedAllResultRequestDto + { + public string? Name { get; set; } + public string? UserName { get; set; } + public long? Phone { get; set; } + + public bool? State { get; set; } + + public long? DeptId { get; set; } + + public string? Ids { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListOutputDto.cs new file mode 100644 index 00000000..b9f4ac6d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetListOutputDto.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class UserGetListOutputDto : IEntityDto + { + public long Id { get; set; } + public string? Name { get; set; } + public int? Age { get; set; } + public string UserName { get; set; } = string.Empty; + public string? Icon { get; set; } + public string? Nick { get; set; } + public string? Email { get; set; } + public string? Ip { get; set; } + public string? Address { get; set; } + public long? Phone { get; set; } + public string? Introduction { get; set; } + public string? Remark { get; set; } + public SexEnum Sex { get; set; } = SexEnum.Unknown; + public long? DeptId { get; set; } + public DateTime CreationTime { get; set; } = DateTime.Now; + public long? CreatorId { get; set; } + + public bool State { get; set; } + + + public string DeptName { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetOutputDto.cs new file mode 100644 index 00000000..474c02a0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserGetOutputDto.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class UserGetOutputDto : IEntityDto + { + public long Id { get; set; } + public string? Name { get; set; } + public int? Age { get; set; } + public string UserName { get; set; } = string.Empty; + public string? Icon { get; set; } + public string? Nick { get; set; } + public string? Email { get; set; } + public string? Ip { get; set; } + public string? Address { get; set; } + public long? Phone { get; set; } + public string? Introduction { get; set; } + public string? Remark { get; set; } + public SexEnum Sex { get; set; } = SexEnum.Unknown; + public bool State { get; set; } + public DateTime CreationTime { get; set; } + + public long DeptId { get; set; } + + public DeptGetOutputDto Dept { get; set; } + + public List Posts { get; set; } + + public List Roles { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserUpdateInputVo.cs new file mode 100644 index 00000000..c191ea6d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/Dtos/User/UserUpdateInputVo.cs @@ -0,0 +1,34 @@ +using Mapster; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Application.Contracts.Identity.Dtos +{ + public class UserUpdateInputVo + { + public string? Name { get; set; } + public int? Age { get; set; } + public string? UserName { get; set; } + + [AdaptIgnore] + public string? Password { get; set; } + public string? Icon { get; set; } + public string? Nick { get; set; } + public string? Email { get; set; } + public string? Ip { get; set; } + public string? Address { get; set; } + public long? Phone { get; set; } + public string? Introduction { get; set; } + public string? Remark { get; set; } + public SexEnum? Sex { get; set; } + public long? DeptId { get; set; } + public List? PostIds { get; set; } + + public List? RoleIds { get; set; } + public bool? State { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IDeptService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IDeptService.cs new file mode 100644 index 00000000..e8be3078 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IDeptService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Identity +{ + /// + /// Dept服务抽象 + /// + public interface IDeptService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IMenuService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IMenuService.cs new file mode 100644 index 00000000..f045fa6b --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IMenuService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Identity +{ + /// + /// Menu服务抽象 + /// + public interface IMenuService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IPostService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IPostService.cs new file mode 100644 index 00000000..7248ce3e --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IPostService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Identity +{ + /// + /// Post服务抽象 + /// + public interface IPostService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IRoleService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IRoleService.cs new file mode 100644 index 00000000..c02d603e --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IRoleService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Identity +{ + /// + /// Role服务抽象 + /// + public interface IRoleService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IUserService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IUserService.cs new file mode 100644 index 00000000..e06d9e53 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Identity/IUserService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Identity +{ + /// + /// User服务抽象 + /// + public interface IUserService : ICrudAppService + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListInputVo.cs new file mode 100644 index 00000000..c35b995a --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListInputVo.cs @@ -0,0 +1,17 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Logs.Dtos.LoginLog +{ + public class LoginLogGetListInputVo: PagedAllResultRequestDto + { + public string? LoginUser { get; set; } + + public string? LoginIp { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListOutputDto.cs new file mode 100644 index 00000000..3ca4a77d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Logs/Dtos/LoginLog/LoginLogGetListOutputDto.cs @@ -0,0 +1,38 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Logs.Dtos.LoginLog +{ + public class LoginLogGetListOutputDto:EntityDto + { + public DateTime CreationTime { get; } + + + public string? LoginUser { get; set; } + + public string? LoginLocation { get; set; } + /// + /// 登录Ip + /// + public string? LoginIp { get; set; } + /// + /// 浏览器 + /// + public string? Browser { get; set; } + /// + /// 操作系统 + /// + public string? Os { get; set; } + /// + /// 登录信息 + /// + public string? LogMsg { get; set; } + + public long? CreatorId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigCreateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigCreateInputVo.cs new file mode 100644 index 00000000..22d41efb --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigCreateInputVo.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Setting.Dtos +{ + /// + /// Config输入创建对象 + /// + public class ConfigCreateInputVo + { + public long Id { get; set; } + public string ConfigName { get; set; } = string.Empty; + public string ConfigKey { get; set; } = string.Empty; + public string ConfigValue { get; set; } = string.Empty; + public string? ConfigType { get; set; } + public int OrderNum { get; set; } + public string? Remark { get; set; } + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListInputVo.cs new file mode 100644 index 00000000..1782cec4 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListInputVo.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Setting.Dtos +{ + /// + /// òѯ + /// + public class ConfigGetListInputVo : PagedAllResultRequestDto + { + /// + /// + /// + public string? ConfigName { get; set; } + + /// + /// ü + /// + public string? ConfigKey { get; set; } + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListOutputDto.cs new file mode 100644 index 00000000..1b1da511 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetListOutputDto.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Setting.Dtos +{ + public class ConfigGetListOutputDto : IEntityDto + { + public long Id { get; set; } + /// + /// + /// + public string ConfigName { get; set; } = string.Empty; + + /// + /// + /// + public string ConfigKey { get; set; } = string.Empty; + /// + /// ֵ + /// + public string ConfigValue { get; set; } = string.Empty; + /// + /// + /// + public string? ConfigType { get; set; } + /// + /// ֶ + /// + public int OrderNum { get; set; } + + /// + /// ע + /// + public string? Remark { get; set; } + + /// + /// ʱ + /// + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetOutputDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetOutputDto.cs new file mode 100644 index 00000000..ff50dbdd --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigGetOutputDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Contracts.Setting.Dtos +{ + public class ConfigGetOutputDto : IEntityDto + { + public long Id { get; set; } + public string ConfigName { get; set; } = string.Empty; + public string ConfigKey { get; set; } = string.Empty; + public string ConfigValue { get; set; } = string.Empty; + public string? ConfigType { get; set; } + public int OrderNum { get; set; } + public string? Remark { get; set; } + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigUpdateInputVo.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigUpdateInputVo.cs new file mode 100644 index 00000000..2c51f3a3 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/Dtos/Config/ConfigUpdateInputVo.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Application.Contracts.Setting.Dtos +{ + public class ConfigUpdateInputVo + { + public long Id { get; set; } + public string ConfigName { get; set; } = string.Empty; + public string ConfigKey { get; set; } = string.Empty; + public string ConfigValue { get; set; } = string.Empty; + public string? ConfigType { get; set; } + public int OrderNum { get; set; } + public string? Remark { get; set; } + public DateTime CreationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/IConfigService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/IConfigService.cs new file mode 100644 index 00000000..ef422730 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Setting/IConfigService.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts.Setting.Dtos; +using Yi.Framework.Ddd.Services.Abstract; + +namespace Yi.RBAC.Application.Contracts.Setting +{ + /// + /// Config服务抽象 + /// + public interface IConfigService : ICrudAppService + { + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.Contracts.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.Contracts.csproj new file mode 100644 index 00000000..af0ad078 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.Contracts.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + Always + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.ContractsSwaggerDoc.xml b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.ContractsSwaggerDoc.xml new file mode 100644 index 00000000..395d4e69 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/Yi.RBAC.Application.ContractsSwaggerDoc.xml @@ -0,0 +1,163 @@ + + + + Yi.RBAC.Application.Contracts + + + + + 账号 + + + + + 密码 + + + + + 唯一标识码 + + + + + 电话 + + + + + 验证码 + + + + + Dept输入创建对象 + + + + + Menu输入创建对象 + + + + + Post输入创建对象 + + + + + Role输入创建对象 + + + + + User输入创建对象 + + + + + Dept服务抽象 + + + + + Menu服务抽象 + + + + + Post服务抽象 + + + + + Role服务抽象 + + + + + User服务抽象 + + + + + 登录Ip + + + + + 浏览器 + + + + + 操作系统 + + + + + 登录信息 + + + + + Config输入创建对象 + + + + + 配置查询参数 + + + + + 配置名称 + + + + + 配置键 + + + + + 配置名称 + + + + + 配置主键 + + + + + 配置值 + + + + + 配置类型 + + + + + 排序字段 + + + + + 备注 + + + + + 创建时间 + + + + + Config服务抽象 + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/YiRBACApplicationContractsModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/YiRBACApplicationContractsModule.cs new file mode 100644 index 00000000..9ca2ed49 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application.Contracts/YiRBACApplicationContractsModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.RBAC.Domain.Shared; + +namespace Yi.RBAC.Application.Contracts +{ + [DependsOn( + typeof(YiRBACDomainSharedModule) + )] + public class YiRBACApplicationContractsModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/AccountService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/AccountService.cs new file mode 100644 index 00000000..b573e2ac --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/AccountService.cs @@ -0,0 +1,383 @@ +using Cike.EventBus.DistributedEvent; +using Hei.Captcha; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Cike.AutoWebApi.Setting; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Auth.JwtBearer.Authentication; +using Yi.Framework.Auth.JwtBearer.Authorization; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Enums; +using Yi.Framework.Core.Exceptions; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.Ddd.Services; +using Yi.RBAC.Application.Contracts.Identity; +using Yi.RBAC.Application.Contracts.Identity.Dtos.Account; +using Yi.RBAC.Domain.Identity; +using Yi.RBAC.Domain.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Identity.Repositories; +using Yi.RBAC.Domain.Shared.Identity.ConstClasses; +using Yi.RBAC.Domain.Shared.Identity.Dtos; +using Yi.RBAC.Domain.Shared.Identity.Etos; +using System.Net.WebSockets; +using Yi.Framework.Uow; +using Yi.Framework.Caching; +using Yi.Framework.Sms.Aliyun; +using Microsoft.Extensions.Options; +using System.Text.RegularExpressions; + +namespace Yi.RBAC.Application.Identity +{ + [AppService] + public class AccountService : ApplicationService, IAutoApiService + { + [Autowired] + private JwtTokenManager _jwtTokenManager { get; set; } + [Autowired] + private IUserRepository _userRepository { get; set; } + [Autowired] + private ICurrentUser _currentUser { get; set; } + [Autowired] + private AccountManager _accountManager { get; set; } + + [Autowired] + private IRepository _menuRepository { get; set; } + + [Autowired] + private SecurityCodeHelper _securityCode { get; set; } + + [Autowired] + private IDistributedEventBus _distributedEventBus { get; set; } + + + [Autowired] + private IUserService _userService { get; set; } + + + [Autowired] + private UserManager _userManager { get; set; } + + [Autowired] + private IUnitOfWorkManager _unitOfWorkManager { get; set; } + + [Autowired] + private IRepository _roleRepository { get; set; } + + [Autowired] + private CacheManager _cacheManager { get; set; } + + [Autowired] + private SmsAliyunManager _smsAliyunManager { get; set; } + + [Autowired] + private IOptions _smsAliyunManagerOptions { get; set; } + + /// + /// 效验图片登录验证码,无需和账号绑定 + /// + private void ValidationImageCaptcha(LoginInputVo input) + { + //登录不想要验证码 ,不效验 + return; + var value = _cacheManager.Get($"Yi:Captcha:{input.Code}"); + if (value is not null && value.Equals(input.Uuid)) + { + return; + } + throw new UserFriendlyException("验证码错误"); + } + + /// + /// 效验电话验证码,需要与电话号码绑定 + /// + private void ValidationPhoneCaptcha(RegisterDto input) + { + var value = _cacheManager.Get($"Yi:Phone:{input.Phone}"); + if (value is not null && value.Equals($"{input.Code}")) + { + //成功,需要清空 + _cacheManager.Del($"Yi:Phone:{input.Phone}"); + return; + } + throw new UserFriendlyException("验证码错误"); + } + + /// + /// 登录 + /// + /// + /// + public async Task PostLoginAsync(LoginInputVo input) + { + if (string.IsNullOrEmpty(input.Password) || string.IsNullOrEmpty(input.UserName)) + { + throw new UserFriendlyException("请输入合理数据!"); + } + + //效验验证码 + ValidationImageCaptcha(input); + + UserEntity user = new(); + //登录成功 + await _accountManager.LoginValidationAsync(input.UserName, input.Password, x => user = x); + + //获取用户信息 + var userInfo = await _userRepository.GetUserAllInfoAsync(user.Id); + + if (userInfo.RoleCodes.Count == 0) + { + throw new UserFriendlyException(UserConst.用户无角色分配); + } + //这里抛出一个登录的事件 + + //不阻碍执行,无需等待 +#pragma warning disable CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法 + _distributedEventBus.PublishAsync(new LoginEventArgs + { + UserId = userInfo.User.Id, + UserName = user.UserName + }); +#pragma warning restore CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法 + + //创建token + var token = _jwtTokenManager.CreateToken(_accountManager.UserInfoToClaim(userInfo)); + return new { Token = token }; + } + + /// + /// 生成验证码 + /// + /// + + [AllowAnonymous] + public CaptchaImageDto GetCaptchaImage() + { + var uuid = Guid.NewGuid(); + var code = _securityCode.GetRandomEnDigitalText(4); + //将uuid与code,Redis缓存中心化保存起来,登录根据uuid比对即可 + //10分钟过期 + _cacheManager.Set($"Yi:Captcha:{code}", uuid, new TimeSpan(0, 10, 0)); + var imgbyte = _securityCode.GetEnDigitalCodeByte(code); + return new CaptchaImageDto { Img = imgbyte, Code = code, Uuid = uuid }; + } + + /// + /// 验证电话号码 + /// + /// + private async Task ValidationPhone(string str_handset) + { + var res= Regex.IsMatch(str_handset, "^(0\\d{2,3}-?\\d{7,8}(-\\d{3,5}){0,1})|(((13[0-9])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(14[0-9]))\\d{8})$"); + if (res == false) + { + throw new UserFriendlyException("手机号码格式错误!请检查"); + } + if (await _userRepository.IsAnyAsync(x => x.Phone.ToString() == str_handset)) + { + throw new UserFriendlyException("该手机号已被注册!"); + + } + + } + + + /// + /// 注册 手机验证码 + /// + /// + [AllowAnonymous] + public async Task PostCaptchaPhone(PhoneCaptchaImageDto input) + { + await ValidationPhone(input.Phone); + var value = _cacheManager.Get($"Yi:Phone:{input.Phone}"); + + //防止暴刷 + if (value is not null) + { + throw new UserFriendlyException($"{input.Phone}已发送过验证码,10分钟后可重试"); + } + //生成一个4位数的验证码 + //发送短信,同时生成uuid + //key: 电话号码 value:验证码+uuid + var code = _securityCode.GetRandomEnDigitalText(4); + var uuid = Guid.NewGuid(); + + //未开启短信验证,默认8888 + if (_smsAliyunManagerOptions.Value.EnableFeature) + { + await _smsAliyunManager.Send(input.Phone, code); + } + else + { + code = "8888"; + } + _cacheManager.Set($"Yi:Phone:{input.Phone}", $"{code}", new TimeSpan(0, 10, 0)); + + + return new { Uuid = uuid }; + } + + /// + /// 注册,需要验证码通过 + /// + /// + /// + [AllowAnonymous] + public async Task PostRegisterAsync(RegisterDto input) + { + if (input.UserName == UserConst.Admin) + { + throw new UserFriendlyException("用户名无效注册!"); + } + + if (input.UserName.Length < 2) + { + throw new UserFriendlyException("账号名需大于等于2位!"); + } + if (input.Password.Length < 6) + { + throw new UserFriendlyException("密码需大于等于6位!"); + } + //效验验证码,根据电话号码获取 value,比对验证码已经uuid + ValidationPhoneCaptcha(input); + + + + //输入的用户名与电话号码都不能在数据库中存在 + UserEntity user = new(); + var isExist = await _userRepository.IsAnyAsync(x => + x.UserName == input.UserName + || x.Phone == input.Phone); + if (isExist) + { + throw new UserFriendlyException("用户已存在,注册失败"); + } + using (var uow = _unitOfWorkManager.CreateContext()) + { + var newUser = new UserEntity(input.UserName, input.Password, input.Phone); + + var entity = await _userRepository.InsertReturnEntityAsync(newUser); + //赋上一个初始角色 + var roleRepository = _roleRepository; + var role = await roleRepository.GetFirstAsync(x => x.RoleCode == UserConst.GuestRoleCode); + if (role is not null) + { + await _userManager.GiveUserSetRoleAsync(new List { entity.Id }, new List { role.Id }); + } + uow.Commit(); + } + + return true; + } + + + /// + /// 查询已登录的账户信息 + /// + /// + /// + [Route("/api/account")] + [Authorize] + public async Task Get() + { + //通过鉴权jwt获取到用户的id + var userId = _currentUser.Id; + //此处从缓存中获取即可 + //var data = _cacheManager.Get($"Yi:UserInfo:{userId}"); + var data = await _userRepository.GetUserAllInfoAsync(userId); + //系统用户数据被重置,老前端访问重新授权 + if (data is null) + { + throw new AuthException(); + } + + data.Menus.Clear(); + return data; + } + + + /// + /// 获取当前登录用户的前端路由 + /// + /// + [Authorize] + public async Task> GetVue3Router() + { + var userId = _currentUser.Id; + var data = await _userRepository.GetUserAllInfoAsync(userId); + var menus = data.Menus.ToList(); + + //为超级管理员直接给全部路由 + if (UserConst.Admin.Equals(data.User.UserName)) + { + menus = await _menuRepository.GetListAsync(); + } + //将后端菜单转换成前端路由,组件级别需要过滤 + List routers = menus.Vue3RouterBuild(); + return routers; + } + + /// + /// 退出登录 + /// + /// + public Task PostLogout() + { + return Task.FromResult(true); + } + + /// + /// 更新密码 + /// + /// + /// + public async Task UpdatePasswordAsync(UpdatePasswordDto input) + { + if (input.OldPassword.Equals(input.NewPassword)) + { + throw new UserFriendlyException("无效更新!输入的数据,新密码不能与老密码相同"); + } + await _accountManager.UpdatePasswordAsync(_currentUser.Id, input.NewPassword, input.OldPassword); + return true; + } + + /// + /// 重置密码 + /// + /// + /// + /// + [HttpPut] + public async Task RestPasswordAsync(long userId, RestPasswordDto input) + { + if (!string.IsNullOrEmpty(input.Password)) + { + throw new UserFriendlyException("重置密码不能为空!"); + } + await _accountManager.RestPasswordAsync(userId, input.Password); + return true; + } + + /// + /// 更新头像 + /// + /// + /// + public async Task UpdateIconAsync(UpdateIconDto input) + { + var entity = await _userRepository.GetByIdAsync(_currentUser.Id); + entity.Icon = input.Icon; + await _userRepository.UpdateAsync(entity); + + return true; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/DeptService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/DeptService.cs new file mode 100644 index 00000000..757518a6 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/DeptService.cs @@ -0,0 +1,51 @@ +using Yi.RBAC.Application.Contracts.Identity; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using Microsoft.AspNetCore.Mvc; + +namespace Yi.RBAC.Application.Identity +{ + /// + /// Dept服务实现 + /// + [AppService] + public class DeptService : CrudAppService, + IDeptService, IAutoApiService + { + + /// + /// 通过角色id查询该角色全部部门 + /// + /// + //[Route("{roleId}")] + public async Task> GetListRoleIdAsync([FromRoute]long roleId) + { + var entities= await _DbQueryable.Where(d => SqlFunc.Subqueryable().Where(rd => rd.RoleId == roleId && d.Id==rd.DeptId).Any()).ToListAsync(); + return await MapToGetListOutputDtosAsync(entities); + } + + /// + /// 多查 + /// + /// + /// + public override async Task> GetListAsync(DeptGetListInputVo input) + { + RefAsync total = 0; + var entities = await _DbQueryable + .WhereIF(!string.IsNullOrEmpty(input.DeptName), u => u.DeptName.Contains(input.DeptName!)) + .WhereIF(input.State is not null, u => u.State == input.State) + .OrderBy(u => u.OrderNum, OrderByType.Asc) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto + { + Items = await MapToGetListOutputDtosAsync(entities), + Total = total + }; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/MenuService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/MenuService.cs new file mode 100644 index 00000000..bd217b52 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/MenuService.cs @@ -0,0 +1,44 @@ +using Yi.RBAC.Application.Contracts.Identity; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.Framework.Ddd.Services; +using SqlSugar; +using Yi.Framework.Ddd.Dtos; + +namespace Yi.RBAC.Application.Identity +{ + /// + /// Menu服务实现 + /// + [AppService] + public class MenuService : CrudAppService, + IMenuService, IAutoApiService + { + + public override async Task> GetListAsync(MenuGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.MenuName), x => x.MenuName.Contains(input.MenuName!)) + .WhereIF(input.State is not null, x => x.State == input.State) + .OrderByDescending(x=>x.OrderNum) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + + /// + /// 查询当前角色的菜单 + /// + /// + /// + public async Task> GetListRoleIdAsync(long roleId) + { + var entities = await _DbQueryable.Where(m => SqlFunc.Subqueryable().Where(rm => rm.RoleId == roleId && rm.MenuId == m.Id).Any()).ToListAsync(); + + return await MapToGetListOutputDtosAsync(entities); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/PostService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/PostService.cs new file mode 100644 index 00000000..ab2eaccc --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/PostService.cs @@ -0,0 +1,31 @@ +using Yi.RBAC.Application.Contracts.Identity; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using Yi.RBAC.Application.Contracts.Setting.Dtos; + +namespace Yi.RBAC.Application.Identity +{ + /// + /// Post服务实现 + /// + [AppService] + public class PostService : CrudAppService, + IPostService, IAutoApiService + { + public override async Task> GetListAsync(PostGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.PostName), x => x.PostName.Contains(input.PostName!)) + .WhereIF(input.State is not null, x => x.State == input.State) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/RoleService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/RoleService.cs new file mode 100644 index 00000000..ddc08fd7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/RoleService.cs @@ -0,0 +1,106 @@ +using Yi.RBAC.Application.Contracts.Identity; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.Framework.Ddd.Services; +using Yi.RBAC.Domain.Identity; +using Microsoft.AspNetCore.Identity; +using Yi.Framework.Uow; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using Microsoft.AspNetCore.Mvc; + +namespace Yi.RBAC.Application.Identity +{ + /// + /// Role服务实现 + /// + [AppService] + public class RoleService : CrudAppService, + IRoleService, IAutoApiService + { + [Autowired] + private RoleManager _roleManager { get; set; } + + [Autowired] + private IUnitOfWorkManager _unitOfWorkManager { get; set; } + + + public override async Task> GetListAsync(RoleGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.RoleCode), x => x.RoleCode.Contains(input.RoleCode!)) + .WhereIF(!string.IsNullOrEmpty(input.RoleName), x => x.RoleName.Contains(input.RoleName!)) + .WhereIF(input.State is not null, x => x.State == input.State) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + + /// + /// 添加角色 + /// + /// + /// + public override async Task CreateAsync(RoleCreateInputVo input) + { + RoleGetOutputDto outputDto; + using (var uow = _unitOfWorkManager.CreateContext()) + { + var entity = await MapToEntityAsync(input); + await _repository.InsertAsync(entity); + outputDto = await MapToGetOutputDtoAsync(entity); + await _roleManager.GiveRoleSetMenuAsync(new List { entity.Id }, input.MenuIds); + uow.Commit(); + } + + return outputDto; + } + + /// + /// 修改角色 + /// + /// + /// + /// + public override async Task UpdateAsync(long id, RoleUpdateInputVo input) + { + var dto = new RoleGetOutputDto(); + using (var uow = _unitOfWorkManager.CreateContext()) + { + var entity = await _repository.GetByIdAsync(id); + await MapToEntityAsync(input, entity); + await _repository.UpdateAsync(entity); + + await _roleManager.GiveRoleSetMenuAsync(new List { id }, input.MenuIds); + + dto = await MapToGetOutputDtoAsync(entity); + uow.Commit(); + } + return dto; + } + + + /// + /// 更新状态 + /// + /// + /// + /// + [Route("/api/role/{id}/{state}")] + public async Task UpdateStateAsync([FromRoute] long id, [FromRoute] bool state) + { + var entity = await _repository.GetByIdAsync(id); + if (entity is null) + { + throw new ApplicationException("角色未存在"); + } + + entity.State = state; + await _repository.UpdateAsync(entity); + return await MapToGetOutputDtoAsync(entity); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/UserService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/UserService.cs new file mode 100644 index 00000000..cd65e3b4 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Identity/UserService.cs @@ -0,0 +1,192 @@ +using Yi.RBAC.Application.Contracts.Identity; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.Framework.Ddd.Services; +using Yi.RBAC.Domain.Shared.Identity.ConstClasses; +using Yi.RBAC.Domain.Identity; +using Yi.Framework.Uow; +using Yi.Framework.Ddd.Dtos; +using Yi.RBAC.Domain.Identity.Repositories; +using SqlSugar; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Yi.Framework.Auth.JwtBearer.Authorization; +using Yi.RBAC.Application.Contracts.Identity.Dtos.User; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.OperLogManager; + +namespace Yi.RBAC.Application.Identity +{ + /// + /// User服务实现 + /// + [AppService] + public class UserService : CrudAppService, + IUserService, IAutoApiService + { + [Autowired] + private UserManager _userManager { get; set; } + + [Autowired] + private IUnitOfWorkManager _unitOfWorkManager { get; set; } + + [Autowired] + private IUserRepository _userRepository { get; set; } + + [Autowired] + private ICurrentUser _currentUser { get; set; } + + /// + /// 查询用户 + /// + /// + /// + public override async Task> GetListAsync(UserGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + + List? ids = input.Ids?.Split(",").Select(x=>long.Parse(x)).ToList(); + var outPut = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.UserName), x => x.UserName.Contains(input.UserName!)) + .WhereIF(input.Phone is not null, x => x.Phone.ToString()!.Contains(input.Phone.ToString()!)) + .WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name!.Contains(input.Name!)) + .WhereIF(input.State is not null, x => x.State == input.State) + .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + + //这个为过滤当前部门,加入数据权限后,将由数据权限控制 + .WhereIF(input.DeptId is not null, x => x.DeptId == input.DeptId) + + .WhereIF(ids is not null,x=> ids.Contains(x.Id)) + + + .LeftJoin((user, dept) => user.DeptId == dept.Id) + .Select((user, dept) => new UserGetListOutputDto(), true) + .ToPageListAsync(input.PageNum, input.PageSize, total); + + var result = new PagedResultDto(); + result.Items = outPut; + result.Total = total; + return result; + } + + /// + /// 添加用户 + /// + /// + /// + /// + [OperLog("添加用户", OperEnum.Insert)] + public async override Task CreateAsync(UserCreateInputVo input) + { + if (string.IsNullOrEmpty(input.Password)) + { + throw new UserFriendlyException(UserConst.添加失败_密码为空); + } + if (await _repository.IsAnyAsync(u => input.UserName.Equals(u.UserName))) + { + throw new UserFriendlyException(UserConst.添加失败_用户存在); + } + var entities = await MapToEntityAsync(input); + + entities.BuildPassword(); + + using (var uow = _unitOfWorkManager.CreateContext()) + { + var returnEntity = await _repository.InsertReturnEntityAsync(entities); + await _userManager.GiveUserSetRoleAsync(new List { returnEntity.Id }, input.RoleIds); + await _userManager.GiveUserSetPostAsync(new List { returnEntity.Id }, input.PostIds); + uow.Commit(); + + var result = await MapToGetOutputDtoAsync(returnEntity); + return result; + } + } + /// + /// 单查 + /// + /// + /// + public override async Task GetAsync(long id) + { + //使用导航树形查询 + var entity = await _DbQueryable.Includes(u => u.Roles).Includes(u => u.Posts).Includes(u => u.Dept).InSingleAsync(id); + + return await MapToGetOutputDtoAsync(entity); + } + + /// + /// 更新用户 + /// + /// + /// + /// + [OperLog("更新用户", OperEnum.Update)] + public async override Task UpdateAsync(long id, UserUpdateInputVo input) + { + if (await _repository.IsAnyAsync(u => input.UserName!.Equals(u.UserName) && !id.Equals(u.Id))) + { + throw new UserFriendlyException("用户已经在,更新失败"); + } + var entity = await _repository.GetByIdAsync(id); + //更新密码,特殊处理 + if (input.Password is not null) + { + entity.Password = input.Password; + entity.BuildPassword(); + } + await MapToEntityAsync(input, entity); + using (var uow = _unitOfWorkManager.CreateContext()) + { + var res1 = await _repository.UpdateAsync(entity); + await _userManager.GiveUserSetRoleAsync(new List { id }, input.RoleIds); + await _userManager.GiveUserSetPostAsync(new List { id }, input.PostIds); + uow.Commit(); + } + return await MapToGetOutputDtoAsync(entity); + } + + /// + /// 更新个人中心 + /// + /// + /// + [OperLog("更新个人信息", OperEnum.Update)] + public async Task UpdateProfileAsync(ProfileUpdateInputVo input) + { + var entity = await _repository.GetByIdAsync(_currentUser.Id); + _mapper.Map(input, entity); + await _repository.UpdateAsync(entity); + var dto = _mapper.Map(entity); + return dto; + } + + /// + /// 更新状态 + /// + /// + /// + /// + [Route("/api/user/{id}/{state}")] + [OperLog("更新用户状态", OperEnum.Update)] + public async Task UpdateStateAsync([FromRoute] long id, [FromRoute] bool state) + { + var entity = await _repository.GetByIdAsync(id); + if (entity is null) + { + throw new ApplicationException("用户未存在"); + } + + entity.State = state; + await _repository.UpdateAsync(entity); + return await MapToGetOutputDtoAsync(entity); + } + [OperLog("删除用户", OperEnum.Delete)] + public override Task DeleteAsync(string id) + { + return base.DeleteAsync(id); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Logs/LoginLogService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Logs/LoginLogService.cs new file mode 100644 index 00000000..52ba4d68 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Logs/LoginLogService.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc; +using Cike.AutoWebApi.Setting; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Services; +using Yi.RBAC.Application.Contracts.Logs.Dtos.LoginLog; +using Yi.RBAC.Application.Contracts.Setting.Dtos; +using Yi.RBAC.Domain.Logs.Entities; + +namespace Yi.RBAC.Application.Logs +{ + [AppService] + public class LoginLogService : CrudAppService, IAutoApiService + { + public override async Task> GetListAsync(LoginLogGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _DbQueryable.WhereIF(!string.IsNullOrEmpty(input.LoginIp), x => x.LoginIp.Contains(input.LoginIp!)) + .WhereIF(!string.IsNullOrEmpty(input.LoginUser), x => x.LoginUser!.Contains(input.LoginUser!)) + .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .ToPageListAsync(input.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + + [NonAction] + public override Task UpdateAsync(long id, LoginLogGetListOutputDto input) + { + return base.UpdateAsync(id, input); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Setting/ConfigService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Setting/ConfigService.cs new file mode 100644 index 00000000..aab40d6f --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Setting/ConfigService.cs @@ -0,0 +1,40 @@ +using Yi.RBAC.Application.Contracts.Setting; +using Cike.AutoWebApi.Setting; +using Yi.RBAC.Application.Contracts.Setting.Dtos; +using Yi.RBAC.Domain.Setting.Entities; +using Yi.Framework.Ddd.Services; +using Yi.Framework.Ddd.Dtos; +using SqlSugar; +using Yi.RBAC.Application.Contracts.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Microsoft.AspNetCore.Mvc; + +namespace Yi.RBAC.Application.Setting +{ + /// + /// Config服务实现 + /// + [AppService] + + public class ConfigService : CrudAppService, + IConfigService, IAutoApiService + { + /// + /// 多查 + /// + /// + /// + public override async Task> GetListAsync(ConfigGetListInputVo input) + { + var entity = await MapToEntityAsync(input); + + RefAsync total = 0; + + var entities = await _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.PageNum, input.PageSize, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/TestService.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/TestService.cs new file mode 100644 index 00000000..5cf13672 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/TestService.cs @@ -0,0 +1,34 @@ +using Cike.AutoWebApi.Setting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Services; + +namespace Yi.RBAC.Application +{ + class Test01 + { + + public string Name { get; set; } + public bool State { get; set; } + } + + class Test02 + { + public string Name { get; set; } + } + + public class TestService : ApplicationService, IAutoApiService + { + + public void Test() + { + var t001 = new Test02 { Name = "121233" }; + var t002 = new Test01 { Name = "123", State = true }; + + var entity= _mapper.Map(t001, t002); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.Application.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.Application.csproj new file mode 100644 index 00000000..73d55ded --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.Application.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + + + + Always + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.ApplicationSwaggerDoc.xml b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.ApplicationSwaggerDoc.xml new file mode 100644 index 00000000..c9496fa2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/Yi.RBAC.ApplicationSwaggerDoc.xml @@ -0,0 +1,216 @@ + + + + Yi.RBAC.Application + + + + + 效验图片登录验证码,无需和账号绑定 + + + + + 效验电话验证码,需要与电话号码绑定 + + + + + 登录 + + + + + + + 生成验证码 + + + + + + 验证电话号码 + + + + + + 注册 手机验证码 + + + + + + 注册,需要验证码通过 + + + + + + + 查询已登录的账户信息 + + + + + + + 获取当前登录用户的前端路由 + + + + + + 退出登录 + + + + + + 更新密码 + + + + + + + 重置密码 + + + + + + + + 更新头像 + + + + + + + Dept服务实现 + + + + + 通过角色id查询该角色全部部门 + + + + + + 多查 + + + + + + + Menu服务实现 + + + + + 查询当前角色的菜单 + + + + + + + Post服务实现 + + + + + Role服务实现 + + + + + 添加角色 + + + + + + + 修改角色 + + + + + + + + 更新状态 + + + + + + + + User服务实现 + + + + + 查询用户 + + + + + + + 添加用户 + + + + + + + + 单查 + + + + + + + 更新用户 + + + + + + + + 更新个人中心 + + + + + + + 更新状态 + + + + + + + + Config服务实现 + + + + + 多查 + + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/YiRBACApplicationModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/YiRBACApplicationModule.cs new file mode 100644 index 00000000..627fda36 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Application/YiRBACApplicationModule.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Application.Contracts; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.Framework.Ddd; +using Yi.RBAC.Domain; + +namespace Yi.RBAC.Application +{ + [DependsOn( + typeof(YiRBACApplicationContractsModule), + typeof(YiRBACDomainModule), + typeof(YiFrameworkAuthJwtBearerModule) + )] + public class YiRBACApplicationModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/DeptConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/DeptConst.cs new file mode 100644 index 00000000..e0782cc9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/DeptConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.ConstClasses +{ + /// + /// 常量定义 + /// + + public class DeptConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/MenuConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/MenuConst.cs new file mode 100644 index 00000000..99856010 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/MenuConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.ConstClasses +{ + /// + /// 常量定义 + /// + + public class MenuConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/PostConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/PostConst.cs new file mode 100644 index 00000000..e84733d6 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/PostConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.ConstClasses +{ + /// + /// 常量定义 + /// + + public class PostConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/RoleConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/RoleConst.cs new file mode 100644 index 00000000..71a95507 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/RoleConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.ConstClasses +{ + /// + /// 常量定义 + /// + + public class RoleConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/UserConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/UserConst.cs new file mode 100644 index 00000000..8b927a0d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/ConstClasses/UserConst.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.ConstClasses +{ + /// + /// 常量定义 + /// + + public class UserConst + { + public const string 登录失败_错误 = "登录失败!用户名或密码错误!"; + public const string 登录失败_不存在 = "登录失败!用户名不存在!"; + public const string 添加失败_密码为空 = "密码为空,添加失败!"; + public const string 添加失败_用户存在 = "用户已经存在,添加失败!"; + public const string 用户无权限分配 = "登录禁用!该用户分配无任何权限,无意义登录!"; + public const string 用户无角色分配 = "登录禁用!该用户分配无任何角色,无意义登录!"; + + public const string Admin = "cc"; + public const string AdminRolesCode = "admin"; + public const string AdminPermissionCode = "*:*:*"; + + public const string GuestRoleCode = "guest"; + public const string CommonRoleName = "common"; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Dtos/Vue3RouterDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Dtos/Vue3RouterDto.cs new file mode 100644 index 00000000..c1e0fb2f --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Dtos/Vue3RouterDto.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Yi.Framework.Core.Helper.TreeHelper; + +namespace Yi.RBAC.Domain.Shared.Identity.Dtos +{ + public class Vue3RouterDto : ITreeModel + { + public long Id { get; set; } + public long ParentId { get; set; } + public int OrderNum { get; set; } + + public string Name { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; + public bool Hidden { get; set; } + public string Redirect { get; set; } = string.Empty; + public string Component { get; set; } = string.Empty; + public bool AlwaysShow { get; set; } + public Meta Meta { get; set; } = new Meta(); + public List? Children { get; set; } + } + + + public class Meta + { + public string Title { get; set; } = string.Empty; + public string Icon { get; set; } = string.Empty; + public bool NoCache { get; set; } + public string link { get; set; } = string.Empty; + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/DataScopeEnum.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/DataScopeEnum.cs new file mode 100644 index 00000000..5298296a --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/DataScopeEnum.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.EnumClasses +{ + public enum DataScopeEnum + { + ALL = 0, + CUSTOM = 1, + DEPT = 2, + DEPT_FOLLOW = 3, + USER = 4 + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/MenuTypeEnum.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/MenuTypeEnum.cs new file mode 100644 index 00000000..4c2ad6f0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/MenuTypeEnum.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.EnumClasses +{ + public enum MenuTypeEnum + { + Catalogue = 0, //目录 + Menu = 1, //菜单 + Component = 2//组件 + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/SexEnum.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/SexEnum.cs new file mode 100644 index 00000000..afbeaa4d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/EnumClasses/SexEnum.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.EnumClasses +{ + /// + /// 性别 + /// + public enum SexEnum + { + /// + /// 男性 + /// + Male = 0, + /// + /// 女性 + /// + Woman = 1, + /// + /// 未知 + /// + Unknown = 2 + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Etos/LoginEventArgs.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Etos/LoginEventArgs.cs new file mode 100644 index 00000000..c462f2d8 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Identity/Etos/LoginEventArgs.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Identity.Etos +{ + public class LoginEventArgs + { + public long UserId { get; set; } + public string UserName { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Setting/ConstClasses/ConfigConst.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Setting/ConstClasses/ConfigConst.cs new file mode 100644 index 00000000..8e5852a9 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Setting/ConstClasses/ConfigConst.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.RBAC.Domain.Shared.Setting.ConstClasses +{ + /// + /// 常量定义 + /// + + public class ConfigConst + { + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Yi.RBAC.Domain.Shared.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Yi.RBAC.Domain.Shared.csproj new file mode 100644 index 00000000..692994fe --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/Yi.RBAC.Domain.Shared.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/YiRBACDomainSharedModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/YiRBACDomainSharedModule.cs new file mode 100644 index 00000000..1c9173fc --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain.Shared/YiRBACDomainSharedModule.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Ddd; + +namespace Yi.RBAC.Domain.Shared +{ + [DependsOn( + typeof(YiFrameworkDddModule) + )] + public class YiRBACDomainSharedModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DeptDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DeptDataSeed.cs new file mode 100644 index 00000000..b5722d57 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DeptDataSeed.cs @@ -0,0 +1,137 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class DeptDataSeed : AbstractDataSeed + { + public DeptDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + var entities =new List(); + + DeptEntity chengziDept = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "橙子科技", + DeptCode = "Yi", + OrderNum = 100, + IsDeleted = false, + ParentId = 0, + Leader = "橙子", + Remark = "如名所指" + }; + entities.Add(chengziDept); + + + DeptEntity shenzhenDept = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "深圳总公司", + OrderNum = 100, + IsDeleted = false, + ParentId = chengziDept.Id + }; + entities.Add(shenzhenDept); + + + DeptEntity jiangxiDept = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "江西总公司", + OrderNum = 100, + IsDeleted = false, + ParentId = chengziDept.Id + }; + entities.Add(jiangxiDept); + + + + DeptEntity szDept1 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "研发部门", + OrderNum = 100, + IsDeleted = false, + ParentId = shenzhenDept.Id + }; + entities.Add(szDept1); + + DeptEntity szDept2 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "市场部门", + OrderNum = 100, + IsDeleted = false, + ParentId = shenzhenDept.Id + }; + entities.Add(szDept2); + + DeptEntity szDept3 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "测试部门", + OrderNum = 100, + IsDeleted = false, + ParentId = shenzhenDept.Id + }; + entities.Add(szDept3); + + DeptEntity szDept4 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "财务部门", + OrderNum = 100, + IsDeleted = false, + ParentId = shenzhenDept.Id + }; + entities.Add(szDept4); + + DeptEntity szDept5 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "运维部门", + OrderNum = 100, + IsDeleted = false, + ParentId = shenzhenDept.Id + }; + entities.Add(szDept5); + + + DeptEntity jxDept1 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "市场部门", + OrderNum = 100, + IsDeleted = false, + ParentId = jiangxiDept.Id + }; + entities.Add(jxDept1); + + + DeptEntity jxDept2 = new DeptEntity() + { + Id = SnowflakeHelper.NextId, + DeptName = "财务部门", + OrderNum = 100, + IsDeleted = false, + ParentId = jiangxiDept.Id + }; + entities.Add(jxDept2); + + + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryDataSeed.cs new file mode 100644 index 00000000..97247b78 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryDataSeed.cs @@ -0,0 +1,369 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.DictionaryManager.Entities; + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class DictionaryDataSeed : AbstractDataSeed + { + public DictionaryDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + List entities= new List(); + DictionaryEntity dictInfo1 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "男", + DictValue = "0", + DictType = "sys_user_sex", + OrderNum = 100, + Remark = "性别男", + IsDeleted = false, + }; + entities.Add(dictInfo1); + + DictionaryEntity dictInfo2 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "女", + DictValue = "1", + DictType = "sys_user_sex", + OrderNum = 99, + Remark = "性别女", + IsDeleted = false, + }; + entities.Add(dictInfo2); + + DictionaryEntity dictInfo3 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "未知", + DictValue = "2", + DictType = "sys_user_sex", + OrderNum = 98, + Remark = "性别未知", + IsDeleted = false, + }; + entities.Add(dictInfo3); + + + + DictionaryEntity dictInfo4 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "显示", + DictValue = "true", + DictType = "sys_show_hide", + OrderNum = 100, + Remark = "显示菜单", + IsDeleted = false, + }; + entities.Add(dictInfo4); + + DictionaryEntity dictInfo5 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "隐藏", + DictValue = "false", + DictType = "sys_show_hide", + OrderNum = 99, + Remark = "隐藏菜单", + IsDeleted = false, + }; + entities.Add(dictInfo5); + + + + DictionaryEntity dictInfo6 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "正常", + DictValue = "true", + DictType = "sys_normal_disable", + OrderNum = 100, + Remark = "正常状态", + IsDeleted = false, + }; + entities.Add(dictInfo6); + DictionaryEntity dictInfo7 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "停用", + DictValue = "false", + DictType = "sys_normal_disable", + OrderNum = 99, + Remark = "停用状态", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo7); + + + + DictionaryEntity dictInfo8 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "正常", + DictValue = "0", + DictType = "sys_job_status", + OrderNum = 100, + Remark = "正常状态", + IsDeleted = false, + }; + entities.Add(dictInfo8); + DictionaryEntity dictInfo9 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "暂停", + DictValue = "1", + DictType = "sys_job_status", + OrderNum = 99, + Remark = "停用状态", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo9); + + + + + DictionaryEntity dictInfo10 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "默认", + DictValue = "DEFAULT", + DictType = "sys_job_group", + OrderNum = 100, + Remark = "默认分组", + IsDeleted = false, + }; + entities.Add(dictInfo10); + DictionaryEntity dictInfo11 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "系统", + DictValue = "SYSTEM", + DictType = "sys_job_group", + OrderNum = 99, + Remark = "系统分组", + IsDeleted = false, + }; + entities.Add(dictInfo11); + + + + DictionaryEntity dictInfo12 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "是", + DictValue = "Y", + DictType = "sys_yes_no", + OrderNum = 100, + Remark = "系统默认是", + IsDeleted = false, + }; + entities.Add(dictInfo12); + DictionaryEntity dictInfo13 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "否", + DictValue = "N", + DictType = "sys_yes_no", + OrderNum = 99, + Remark = "系统默认否", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo13); + + + + DictionaryEntity dictInfo14 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "通知", + DictValue = "1", + DictType = "sys_notice_type", + OrderNum = 100, + Remark = "通知", + IsDeleted = false, + }; + entities.Add(dictInfo14); + DictionaryEntity dictInfo15 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "公告", + DictValue = "2", + DictType = "sys_notice_type", + OrderNum = 99, + Remark = "公告", + IsDeleted = false, + }; + entities.Add(dictInfo15); + + DictionaryEntity dictInfo16 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "正常", + DictValue = "0", + DictType = "sys_notice_status", + OrderNum = 100, + Remark = "正常状态", + IsDeleted = false, + }; + entities.Add(dictInfo16); + DictionaryEntity dictInfo17 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "关闭", + DictValue = "1", + DictType = "sys_notice_status", + OrderNum = 99, + Remark = "关闭状态", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo17); + + DictionaryEntity dictInfo18 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "新增", + DictValue = "1", + DictType = "sys_oper_type", + OrderNum = 100, + Remark = "新增操作", + IsDeleted = false, + }; + entities.Add(dictInfo18); + DictionaryEntity dictInfo19 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "修改", + DictValue = "2", + DictType = "sys_oper_type", + OrderNum = 99, + Remark = "修改操作", + IsDeleted = false, + }; + entities.Add(dictInfo19); + DictionaryEntity dictInfo22 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "删除", + DictValue = "3", + DictType = "sys_oper_type", + OrderNum = 98, + Remark = "删除操作", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo22); + DictionaryEntity dictInfo23 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "授权", + DictValue = "4", + DictType = "sys_oper_type", + OrderNum = 97, + Remark = "授权操作", + IsDeleted = false, + }; + entities.Add(dictInfo23); + DictionaryEntity dictInfo24 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "导出", + DictValue = "5", + DictType = "sys_oper_type", + OrderNum = 96, + Remark = "导出操作", + IsDeleted = false, + }; + entities.Add(dictInfo24); + DictionaryEntity dictInfo25 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "导入", + DictValue = "6", + DictType = "sys_oper_type", + OrderNum = 95, + Remark = "导入操作", + IsDeleted = false, + }; + entities.Add(dictInfo25); + DictionaryEntity dictInfo26 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "强退", + DictValue = "7", + DictType = "sys_oper_type", + OrderNum = 94, + Remark = "强退操作", + IsDeleted = false, + }; + entities.Add(dictInfo26); + DictionaryEntity dictInfo27 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "生成代码", + DictValue = "8", + DictType = "sys_oper_type", + OrderNum = 93, + Remark = "生成代码操作", + IsDeleted = false, + }; + entities.Add(dictInfo27); + DictionaryEntity dictInfo28 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "清空数据", + DictValue = "9", + DictType = "sys_oper_type", + OrderNum = 92, + Remark = "清空数据操作", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo28); + + + + DictionaryEntity dictInfo20 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "成功", + DictValue = "false", + DictType = "sys_common_status", + OrderNum = 100, + Remark = "正常状态", + IsDeleted = false, + }; + entities.Add(dictInfo20); + DictionaryEntity dictInfo21 = new DictionaryEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictLabel = "失败", + DictValue = "true", + DictType = "sys_common_status", + OrderNum = 99, + Remark = "失败状态", + IsDeleted = false, + ListClass = "danger" + }; + entities.Add(dictInfo21); + + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryTypeDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryTypeDataSeed.cs new file mode 100644 index 00000000..fdc4958b --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/DictionaryTypeDataSeed.cs @@ -0,0 +1,136 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.Framework.DictionaryManager.Entities; + + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class DictionaryTypeDataSeed : AbstractDataSeed + { + public DictionaryTypeDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + List entities= new List(); + DictionaryTypeEntity dict1 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "用户性别", + DictType = "sys_user_sex", + OrderNum = 100, + Remark = "用户性别列表", + IsDeleted = false, + }; + entities.Add(dict1); + + DictionaryTypeEntity dict2 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "菜单状态", + DictType = "sys_show_hide", + OrderNum = 100, + Remark = "菜单状态列表", + IsDeleted = false, + }; + entities.Add(dict2); + + DictionaryTypeEntity dict3 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "系统开关", + DictType = "sys_normal_disable", + OrderNum = 100, + Remark = "系统开关列表", + IsDeleted = false, + }; + entities.Add(dict3); + + DictionaryTypeEntity dict4 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "任务状态", + DictType = "sys_job_status", + OrderNum = 100, + Remark = "任务状态列表", + IsDeleted = false, + }; + entities.Add(dict4); + + DictionaryTypeEntity dict5 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "任务分组", + DictType = "sys_job_group", + OrderNum = 100, + Remark = "任务分组列表", + IsDeleted = false, + }; + entities.Add(dict5); + + DictionaryTypeEntity dict6 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "系统是否", + DictType = "sys_yes_no", + OrderNum = 100, + Remark = "系统是否列表", + IsDeleted = false, + }; + entities.Add(dict6); + + DictionaryTypeEntity dict7 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "通知类型", + DictType = "sys_notice_type", + OrderNum = 100, + Remark = "通知类型列表", + IsDeleted = false, + }; + entities.Add(dict7); + DictionaryTypeEntity dict8 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "通知状态", + DictType = "sys_notice_status", + OrderNum = 100, + Remark = "通知状态列表", + IsDeleted = false, + }; + entities.Add(dict8); + + DictionaryTypeEntity dict9 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "操作类型", + DictType = "sys_oper_type", + OrderNum = 100, + Remark = "操作类型列表", + IsDeleted = false, + }; + entities.Add(dict9); + + + DictionaryTypeEntity dict10 = new DictionaryTypeEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + DictName = "系统状态", + DictType = "sys_common_status", + OrderNum = 100, + Remark = "登录状态列表", + IsDeleted = false, + }; + entities.Add(dict10); + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/MenuDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/MenuDataSeed.cs new file mode 100644 index 00000000..17d8a7bd --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/MenuDataSeed.cs @@ -0,0 +1,1078 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class MenuDataSeed : AbstractDataSeed + { + public MenuDataSeed(IRepository repository) : base(repository) + { + } + + public override async Task IsInvoker() + { + return !await _repository.IsAnyAsync(x => x.MenuName == "系统管理"); + } + public override List GetSeedData() + { + List entities = new List(); + //系统管理 + MenuEntity system = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "系统管理", + MenuType = MenuTypeEnum.Catalogue, + Router = "/system", + IsShow = true, + IsLink = false, + MenuIcon = "system", + OrderNum = 100, + ParentId = 0, + IsDeleted = false + }; + entities.Add(system); + + //系统监控 + MenuEntity monitoring = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "系统监控", + MenuType = MenuTypeEnum.Catalogue, + Router = "/monitor", + IsShow = true, + IsLink = false, + MenuIcon = "monitor", + OrderNum = 99, + ParentId = 0, + IsDeleted = false + }; + entities.Add(monitoring); + + + //在线用户 + MenuEntity online = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "在线用户", + PermissionCode = "monitor:online:list", + MenuType = MenuTypeEnum.Menu, + Router = "online", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "monitor/online/index", + MenuIcon = "online", + OrderNum = 100, + ParentId = monitoring.Id, + IsDeleted = false + }; + entities.Add(online); + + + + + //系统工具 + MenuEntity tool = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "系统工具", + MenuType = MenuTypeEnum.Catalogue, + Router = "/tool", + IsShow = true, + IsLink = false, + MenuIcon = "tool", + OrderNum = 98, + ParentId = 0, + IsDeleted = false + }; + entities.Add(tool); + //swagger文档 + MenuEntity swagger = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "接口文档", + MenuType = MenuTypeEnum.Menu, + Router = "http://localhost:19001", + IsShow = true, + IsLink = true, + MenuIcon = "list", + OrderNum = 100, + ParentId = tool.Id, + IsDeleted = false, + }; + entities.Add(swagger); + + + //ERP + MenuEntity erp = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "ERP", + MenuType = MenuTypeEnum.Catalogue, + Router = "/erp", + IsShow = true, + IsLink = false, + MenuIcon = "international", + OrderNum = 96, + ParentId = 0, + IsDeleted = false + }; + entities.Add(erp); + + + + //供应商定义 + MenuEntity supplier = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "供应商定义", + PermissionCode = "erp:supplier:list", + MenuType = MenuTypeEnum.Menu, + Router = "supplier", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "erp/supplier/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = erp.Id, + IsDeleted = false + }; + entities.Add(supplier); + + MenuEntity supplierQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "供应商查询", + PermissionCode = "erp:supplier:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = supplier.Id, + IsDeleted = false + }; + entities.Add(supplierQuery); + + MenuEntity supplierAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "供应商新增", + PermissionCode = "erp:supplier:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = supplier.Id, + IsDeleted = false + }; + entities.Add(supplierAdd); + + MenuEntity supplierEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "供应商修改", + PermissionCode = "erp:supplier:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = supplier.Id, + IsDeleted = false + }; + entities.Add(supplierEdit); + + MenuEntity supplierRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "供应商删除", + PermissionCode = "erp:supplier:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = supplier.Id, + IsDeleted = false + }; + entities.Add(supplierRemove); + + + //仓库定义 + MenuEntity warehouse = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "仓库定义", + PermissionCode = "erp:warehouse:list", + MenuType = MenuTypeEnum.Menu, + Router = "warehouse", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "erp/warehouse/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = erp.Id, + IsDeleted = false + }; + entities.Add(warehouse); + + MenuEntity warehouseQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "仓库查询", + PermissionCode = "erp:warehouse:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = warehouse.Id, + IsDeleted = false + }; + entities.Add(warehouseQuery); + + MenuEntity warehouseAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "仓库新增", + PermissionCode = "erp:warehouse:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = warehouse.Id, + IsDeleted = false + }; + entities.Add(warehouseAdd); + + MenuEntity warehouseEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "仓库修改", + PermissionCode = "erp:warehouse:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = warehouse.Id, + IsDeleted = false + }; + entities.Add(warehouseEdit); + + MenuEntity warehouseRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "仓库删除", + PermissionCode = "erp:warehouse:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = warehouse.Id, + IsDeleted = false + }; + entities.Add(warehouseRemove); + + + //单位定义 + MenuEntity unit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "单位定义", + PermissionCode = "erp:unit:list", + MenuType = MenuTypeEnum.Menu, + Router = "unit", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "erp/unit/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = erp.Id, + IsDeleted = false + }; + entities.Add(unit); + + MenuEntity unitQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "单位查询", + PermissionCode = "erp:unit:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = unit.Id, + IsDeleted = false + }; + entities.Add(unitQuery); + + MenuEntity unitAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "单位新增", + PermissionCode = "erp:unit:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = unit.Id, + IsDeleted = false + }; + entities.Add(unitAdd); + + MenuEntity unitEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "单位修改", + PermissionCode = "erp:unit:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = unit.Id, + IsDeleted = false + }; + entities.Add(unitEdit); + + MenuEntity unitRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "单位删除", + PermissionCode = "erp:unit:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = unit.Id, + IsDeleted = false + }; + entities.Add(unitRemove); + + + //物料定义 + MenuEntity material = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "物料定义", + PermissionCode = "erp:material:list", + MenuType = MenuTypeEnum.Menu, + Router = "material", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "erp/material/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = erp.Id, + IsDeleted = false + }; + entities.Add(material); + + MenuEntity materialQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "物料查询", + PermissionCode = "erp:material:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = material.Id, + IsDeleted = false + }; + entities.Add(materialQuery); + + MenuEntity materialAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "物料新增", + PermissionCode = "erp:material:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = material.Id, + IsDeleted = false + }; + entities.Add(materialAdd); + + MenuEntity materialEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "物料修改", + PermissionCode = "erp:material:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = material.Id, + IsDeleted = false + }; + entities.Add(materialEdit); + + MenuEntity materialRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "物料删除", + PermissionCode = "erp:material:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = material.Id, + IsDeleted = false + }; + entities.Add(materialRemove); + + + //采购订单 + MenuEntity purchase = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "采购订单", + PermissionCode = "erp:purchase:list", + MenuType = MenuTypeEnum.Menu, + Router = "purchase", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "erp/purchase/index", + MenuIcon = "education", + OrderNum = 100, + ParentId = erp.Id, + IsDeleted = false + }; + entities.Add(purchase); + + MenuEntity purchaseQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "采购订单查询", + PermissionCode = "erp:purchase:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = purchase.Id, + IsDeleted = false + }; + entities.Add(purchaseQuery); + + MenuEntity purchaseAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "采购订单新增", + PermissionCode = "erp:purchase:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = purchase.Id, + IsDeleted = false + }; + entities.Add(purchaseAdd); + + MenuEntity purchaseEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "采购订单修改", + PermissionCode = "erp:purchase:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = purchase.Id, + IsDeleted = false + }; + entities.Add(purchaseEdit); + + MenuEntity purchaseRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "采购订单删除", + PermissionCode = "erp:purchase:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = purchase.Id, + IsDeleted = false + }; + entities.Add(purchaseRemove); + + + + //Yi框架 + MenuEntity guide = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "Yi框架", + MenuType = MenuTypeEnum.Catalogue, + Router = "https://gitee.com/ccnetcore/yi", + IsShow = true, + IsLink = true, + MenuIcon = "guide", + OrderNum = 90, + ParentId = 0, + IsDeleted = false, + }; + entities.Add(guide); + + //用户管理 + MenuEntity user = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "用户管理", + PermissionCode = "system:user:list", + MenuType = MenuTypeEnum.Menu, + Router = "user", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/user/index", + MenuIcon = "user", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(user); + + MenuEntity userQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "用户查询", + PermissionCode = "system:user:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = user.Id, + IsDeleted = false + }; + entities.Add(userQuery); + + MenuEntity userAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "用户新增", + PermissionCode = "system:user:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = user.Id, + IsDeleted = false + }; + entities.Add(userAdd); + + MenuEntity userEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "用户修改", + PermissionCode = "system:user:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = user.Id, + IsDeleted = false + }; + entities.Add(userEdit); + + MenuEntity userRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "用户删除", + PermissionCode = "system:user:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = user.Id, + IsDeleted = false + }; + entities.Add(userRemove); + + + //角色管理 + MenuEntity role = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "角色管理", + PermissionCode = "system:role:list", + MenuType = MenuTypeEnum.Menu, + Router = "role", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/role/index", + MenuIcon = "peoples", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(role); + + MenuEntity roleQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "角色查询", + PermissionCode = "system:role:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = role.Id, + IsDeleted = false + }; + entities.Add(roleQuery); + + MenuEntity roleAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "角色新增", + PermissionCode = "system:role:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = role.Id, + IsDeleted = false + }; + entities.Add(roleAdd); + + MenuEntity roleEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "角色修改", + PermissionCode = "system:role:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = role.Id, + IsDeleted = false + }; + entities.Add(roleEdit); + + MenuEntity roleRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "角色删除", + PermissionCode = "system:role:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = role.Id, + IsDeleted = false + }; + entities.Add(roleRemove); + + + //菜单管理 + MenuEntity menu = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "菜单管理", + PermissionCode = "system:menu:list", + MenuType = MenuTypeEnum.Menu, + Router = "menu", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/menu/index", + MenuIcon = "tree-table", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(menu); + + MenuEntity menuQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "菜单查询", + PermissionCode = "system:menu:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = menu.Id, + IsDeleted = false + }; + entities.Add(menuQuery); + + MenuEntity menuAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "菜单新增", + PermissionCode = "system:menu:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = menu.Id, + IsDeleted = false + }; + entities.Add(menuAdd); + + MenuEntity menuEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "菜单修改", + PermissionCode = "system:menu:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = menu.Id, + IsDeleted = false + }; + entities.Add(menuEdit); + + MenuEntity menuRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "菜单删除", + PermissionCode = "system:menu:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = menu.Id, + IsDeleted = false + }; + entities.Add(menuRemove); + + //部门管理 + MenuEntity dept = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "部门管理", + PermissionCode = "system:dept:list", + MenuType = MenuTypeEnum.Menu, + Router = "dept", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/dept/index", + MenuIcon = "tree", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(dept); + + MenuEntity deptQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "部门查询", + PermissionCode = "system:dept:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dept.Id, + IsDeleted = false + }; + entities.Add(deptQuery); + + MenuEntity deptAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "部门新增", + PermissionCode = "system:dept:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dept.Id, + IsDeleted = false + }; + entities.Add(deptAdd); + + MenuEntity deptEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "部门修改", + PermissionCode = "system:dept:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dept.Id, + IsDeleted = false + }; + entities.Add(deptEdit); + + MenuEntity deptRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "部门删除", + PermissionCode = "system:dept:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dept.Id, + IsDeleted = false + }; + entities.Add(deptRemove); + + + + //岗位管理 + MenuEntity post = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "岗位管理", + PermissionCode = "system:post:list", + MenuType = MenuTypeEnum.Menu, + Router = "post", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/post/index", + MenuIcon = "post", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(post); + + MenuEntity postQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "岗位查询", + PermissionCode = "system:post:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = post.Id, + IsDeleted = false + }; + entities.Add(postQuery); + + MenuEntity postAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "岗位新增", + PermissionCode = "system:post:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = post.Id, + IsDeleted = false + }; + entities.Add(postAdd); + + MenuEntity postEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "岗位修改", + PermissionCode = "system:post:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = post.Id, + IsDeleted = false + }; + entities.Add(postEdit); + + MenuEntity postRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "岗位删除", + PermissionCode = "system:post:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = post.Id, + IsDeleted = false + }; + entities.Add(postRemove); + + //字典管理 + MenuEntity dict = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "字典管理", + PermissionCode = "system:dict:list", + MenuType = MenuTypeEnum.Menu, + Router = "dict", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/dict/index", + MenuIcon = "dict", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(dict); + + MenuEntity dictQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "字典查询", + PermissionCode = "system:dict:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dict.Id, + IsDeleted = false + }; + entities.Add(dictQuery); + + MenuEntity dictAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "字典新增", + PermissionCode = "system:dict:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dict.Id, + IsDeleted = false + }; + entities.Add(dictAdd); + + MenuEntity dictEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "字典修改", + PermissionCode = "system:dict:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dict.Id, + IsDeleted = false + }; + entities.Add(dictEdit); + + MenuEntity dictRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "字典删除", + PermissionCode = "system:dict:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = dict.Id, + IsDeleted = false + }; + entities.Add(dictRemove); + + + //参数设置 + MenuEntity config = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "参数设置", + PermissionCode = "system:config:list", + MenuType = MenuTypeEnum.Menu, + Router = "config", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/config/index", + MenuIcon = "edit", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(config); + + MenuEntity configQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "参数查询", + PermissionCode = "system:config:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = config.Id, + IsDeleted = false + }; + entities.Add(configQuery); + + MenuEntity configAdd = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "参数新增", + PermissionCode = "system:config:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = config.Id, + IsDeleted = false + }; + entities.Add(configAdd); + + MenuEntity configEdit = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "参数修改", + PermissionCode = "system:config:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = config.Id, + IsDeleted = false + }; + entities.Add(configEdit); + + MenuEntity configRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "参数删除", + PermissionCode = "system:config:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = config.Id, + IsDeleted = false + }; + entities.Add(configRemove); + + + + + //日志管理 + MenuEntity log = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "日志管理", + MenuType = MenuTypeEnum.Catalogue, + Router = "log", + IsShow = true, + IsLink = false, + MenuIcon = "log", + OrderNum = 100, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(log); + + //操作日志 + MenuEntity operationLog = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "操作日志", + PermissionCode = "monitor:operlog:list", + MenuType = MenuTypeEnum.Menu, + Router = "operlog", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "monitor/operlog/index", + MenuIcon = "form", + OrderNum = 100, + ParentId = log.Id, + IsDeleted = false + }; + entities.Add(operationLog); + + MenuEntity operationLogQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "操作查询", + PermissionCode = "monitor:operlog:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = operationLog.Id, + IsDeleted = false + }; + entities.Add(operationLogQuery); + + MenuEntity operationLogRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "操作删除", + PermissionCode = "monitor:operlog:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = operationLog.Id, + IsDeleted = false + }; + entities.Add(operationLogRemove); + + + //登录日志 + MenuEntity loginLog = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "登录日志", + PermissionCode = "monitor:logininfor:list", + MenuType = MenuTypeEnum.Menu, + Router = "logininfor", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "monitor/logininfor/index", + MenuIcon = "logininfor", + OrderNum = 100, + ParentId = log.Id, + IsDeleted = false + }; + entities.Add(loginLog); + + MenuEntity loginLogQuery = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "登录查询", + PermissionCode = "monitor:logininfor:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = loginLog.Id, + IsDeleted = false + }; + entities.Add(loginLogQuery); + + MenuEntity loginLogRemove = new MenuEntity() + { + Id = SnowflakeHelper.NextId, + MenuName = "登录删除", + PermissionCode = "monitor:logininfor:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = loginLog.Id, + IsDeleted = false + }; + entities.Add(loginLogRemove); + + //默认值 + entities.ForEach(m => + { + m.IsDeleted = false; + m.State = true; + }); + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/PostDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/PostDataSeed.cs new file mode 100644 index 00000000..c09838f7 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/PostDataSeed.cs @@ -0,0 +1,69 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class PostDataSeed : AbstractDataSeed + { + public PostDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + var entites=new List(); + + PostEntity Post1 = new PostEntity() + { + Id = SnowflakeHelper.NextId, + PostName = "董事长", + PostCode = "ceo", + OrderNum = 100, + IsDeleted = false + }; + entites.Add(Post1); + + PostEntity Post2 = new PostEntity() + { + Id = SnowflakeHelper.NextId, + PostName = "项目经理", + PostCode = "se", + OrderNum = 100, + IsDeleted = false + }; + entites.Add(Post2); + + PostEntity Post3 = new PostEntity() + { + Id = SnowflakeHelper.NextId, + PostName = "人力资源", + PostCode = "hr", + OrderNum = 100, + IsDeleted = false + }; + entites.Add(Post3); + + PostEntity Post4 = new PostEntity() + { + Id = SnowflakeHelper.NextId, + PostName = "普通员工", + PostCode = "user", + OrderNum = 100, + IsDeleted = false + }; + + entites.Add(Post4); + return entites; + } + } + + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/RoleDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/RoleDataSeed.cs new file mode 100644 index 00000000..82bacfe1 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/RoleDataSeed.cs @@ -0,0 +1,76 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.DataSeeds +{ + [AppService(typeof(IDataSeed))] + public class RoleDataSeed : AbstractDataSeed + { + public RoleDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + var entities = new List(); + RoleEntity role1 = new RoleEntity() + { + Id = SnowflakeHelper.NextId, + RoleName = "管理员", + RoleCode = "admin", + DataScope = DataScopeEnum.ALL, + OrderNum = 999, + Remark = "管理员", + IsDeleted = false + }; + entities.Add(role1); + + RoleEntity role2 = new RoleEntity() + { + Id = SnowflakeHelper.NextId, + RoleName = "测试角色", + RoleCode = "test", + DataScope = DataScopeEnum.ALL, + OrderNum = 1, + Remark = "测试用的角色", + IsDeleted = false + }; + entities.Add(role2); + + RoleEntity role3 = new RoleEntity() + { + Id = SnowflakeHelper.NextId, + RoleName = "普通用户", + RoleCode = "common", + DataScope = DataScopeEnum.ALL, + OrderNum = 1, + Remark = "正常用户", + IsDeleted = false + }; + entities.Add(role3); + + RoleEntity role4 = new RoleEntity() + { + Id = SnowflakeHelper.NextId, + RoleName = "游客用户", + RoleCode = "guest", + DataScope = DataScopeEnum.ALL, + OrderNum = 1, + Remark = "可简单浏览", + IsDeleted = false + }; + entities.Add(role4); + + + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/UserDataSeed.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/UserDataSeed.cs new file mode 100644 index 00000000..a193bd72 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/DataSeeds/UserDataSeed.cs @@ -0,0 +1,93 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.DataSeeds; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.DataSeeds +{ + //支持依赖注入执行 + [AppService(typeof(IDataSeed))] + + //支持启动时执行 + [AppService(typeof(IDataSeed))] + public class UserDataSeed : AbstractDataSeed + { + public UserDataSeed(IRepository repository) : base(repository) + { + } + + public override List GetSeedData() + { + var entities=new List(); + UserEntity user1 = new UserEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + Name = "大橙子", + UserName = "cc", + Nick = "橙子", + Password = "123456", + Email = "454313500@qq.com", + Phone = 13800000000, + Sex = SexEnum.Male, + Address = "深圳", + Age = 20, + Introduction = "还有谁?", + OrderNum = 999, + Remark = "描述是什么呢?", + State = true + }; + user1.BuildPassword(); + entities.Add(user1); + + UserEntity user2 = new UserEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + Name = "大测试", + UserName = "test", + Nick = "测试", + Password = "123456", + Email = "454313500@qq.com", + Phone = 15900000000, + Sex = SexEnum.Woman, + Address = "深圳", + Age = 18, + Introduction = "还有我!", + OrderNum = 1, + Remark = "我没有描述!", + State = true + + }; + user2.BuildPassword(); + entities.Add(user2); + + UserEntity user3 = new UserEntity() + { + Id = SnowFlakeSingle.Instance.NextId(), + Name = "游客", + UserName = "guest", + Nick = "测试", + Password = "123456", + Email = "454313500@qq.com", + Phone = 15900000000, + Sex = SexEnum.Woman, + Address = "深圳", + Age = 18, + Introduction = "临时游客", + OrderNum = 1, + Remark = "懒得创账号", + State = true + + }; + user3.BuildPassword(); + entities.Add(user3); + + return entities; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/AccountManager.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/AccountManager.cs new file mode 100644 index 00000000..9ae6a95b --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/AccountManager.cs @@ -0,0 +1,149 @@ +using Mapster; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Const; +using Yi.Framework.Core.CurrentUsers; +using Yi.Framework.Core.Exceptions; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.ConstClasses; + +namespace Yi.RBAC.Domain.Identity +{ + + /// + /// 用户领域服务 + /// + [AppService] + public class AccountManager + { + private readonly IRepository _repository; + public AccountManager(IRepository repository) + { + _repository = repository; + } + + /// + /// 登录效验 + /// + /// + /// + /// + /// + public async Task LoginValidationAsync(string userName, string password, Action? userAction = null) + { + var user = new UserEntity(); + if (await ExistAsync(userName, o => user = o)) + { + if (userAction is not null) + { + userAction.Invoke(user); + } + if (user.Password == MD5Helper.SHA2Encode(password, user.Salt)) + { + return; + } + throw new UserFriendlyException(UserConst.登录失败_错误); + } + throw new UserFriendlyException(UserConst.登录失败_不存在); + } + + /// + /// 判断账户合法存在 + /// + /// + /// + /// + public async Task ExistAsync(string userName, Action? userAction = null) + { + var user = await _repository.GetFirstAsync(u => u.UserName == userName && u.State == true); + if (userAction is not null) + { + userAction.Invoke(user); + } + if (user == null) + { + return false; + } + return true; + } + + /// + /// 令牌转换 + /// + /// + /// + + public Dictionary UserInfoToClaim(UserRoleMenuDto dto) + { + var claims = new Dictionary(); + claims.Add(TokenTypeConst.Id, dto.User.Id); + claims.Add(TokenTypeConst.UserName, dto.User.UserName); + if (dto.User.Email is not null) + { + claims.Add(TokenTypeConst.Email, dto.User.Email); + } + if (dto.User.Phone is not null) + { + claims.Add(TokenTypeConst.PhoneNumber, dto.User.Phone); + } + if (UserConst.Admin.Equals(dto.User.UserName)) + { + claims.Add(TokenTypeConst.Permission, UserConst.AdminPermissionCode); + claims.Add(TokenTypeConst.Roles, UserConst.AdminRolesCode); + } + else + { + claims.Add(TokenTypeConst.Permission, dto.PermissionCodes.Where(x => !string.IsNullOrEmpty(x))); + claims.Add(TokenTypeConst.Roles, dto.RoleCodes.Where(x => !string.IsNullOrEmpty(x))); + } + + return claims; + } + + /// + /// 更新密码 + /// + /// + /// + /// + /// + /// + public async Task UpdatePasswordAsync(long userId, string newPassword, string oldPassword) + { + var user = await _repository.GetByIdAsync(userId); + + if (!user.JudgePassword(oldPassword)) + { + throw new UserFriendlyException("无效更新!原密码错误!"); + } + user.Password = newPassword; + user.BuildPassword(); + await _repository.UpdateAsync(user); + } + + /// + /// 重置密码 + /// + /// + /// + /// + public async Task RestPasswordAsync(long userId, string password) + { + var user = await _repository.GetByIdAsync(userId); + user.Id = userId; + user.Password = password; + user.BuildPassword(); + return await _repository.UpdateAsync(user); + + + } + } + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Dtos/UserRoleMenuDto.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Dtos/UserRoleMenuDto.cs new file mode 100644 index 00000000..80a4cc64 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Dtos/UserRoleMenuDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.RBAC.Domain.Identity.Dtos +{ + public class UserRoleMenuDto + { + public UserEntity User { get; set; } = new(); + public HashSet Roles { get; set; } = new(); + public HashSet Menus { get; set; } = new(); + + public List RoleCodes { get; set; } = new(); + public List PermissionCodes { get; set; } = new(); + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/DeptEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/DeptEntity.cs new file mode 100644 index 00000000..022c416a --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/DeptEntity.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 部门表 + /// + [SugarTable("Dept")] + public partial class DeptEntity : IEntity, ISoftDelete, IAuditedObject, IOrderNum, IState + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } = DateTime.Now; + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + + /// + /// 最后修改者 + /// + public long? LastModifierId { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + /// + /// 状态 + /// + public bool State { get; set; } = true; + + /// + /// 部门名称 + /// + public string DeptName { get; set; }=string.Empty; + /// + /// 部门编码 + /// + [SugarColumn(ColumnName = "DeptCode")] + public string DeptCode { get; set; } = string.Empty; + /// + /// 负责人 + /// + [SugarColumn(ColumnName = "Leader")] + public string? Leader { get; set; } + /// + /// 父级id + /// + [SugarColumn(ColumnName = "ParentId")] + public long ParentId { get; set; } + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/MenuEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/MenuEntity.cs new file mode 100644 index 00000000..00c36374 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/MenuEntity.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; +using Yi.RBAC.Domain.Shared.Identity.Dtos; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 菜单表 + /// + [SugarTable("Menu")] + public partial class MenuEntity : IEntity, ISoftDelete, IAuditedObject, IOrderNum, IState + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } = DateTime.Now; + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + + /// + /// 最后修改者 + /// + public long? LastModifierId { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + /// + /// 状态 + /// + public bool State { get; set; } + + /// + /// 菜单名 + /// + public string MenuName { get; set; } = string.Empty; + /// + /// + /// + [SugarColumn(ColumnName = "MenuType")] + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Menu; + /// + /// + /// + [SugarColumn(ColumnName = "PermissionCode")] + public string? PermissionCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ParentId")] + public long ParentId { get; set; } + + /// + /// 菜单图标 + /// + [SugarColumn(ColumnName = "MenuIcon")] + public string? MenuIcon { get; set; } + /// + /// 菜单组件路由 + /// + [SugarColumn(ColumnName = "Router")] + public string? Router { get; set; } + /// + /// 是否为外部链接 + /// + [SugarColumn(ColumnName = "IsLink")] + public bool IsLink { get; set; } + /// + /// 是否缓存 + /// + [SugarColumn(ColumnName = "IsCache")] + public bool IsCache { get; set; } + /// + /// 是否显示 + /// + [SugarColumn(ColumnName = "IsShow")] + public bool IsShow { get; set; } = true; + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + /// + /// 组件路径 + /// + [SugarColumn(ColumnName = "Component")] + public string? Component { get; set; } + /// + /// 路由参数 + /// + [SugarColumn(ColumnName = "Query")] + public string? Query { get; set; } + + [SugarColumn(IsIgnore = true)] + public List? Children { get; set; } + } + + /// + /// 实体扩展 + /// + public static class MenuEntityExtensions + { + /// + /// 构建vue3路由 + /// + /// + /// + public static List Vue3RouterBuild(this List menus) + { + menus = menus.Where(m => m.MenuType != MenuTypeEnum.Component).ToList(); + List routers = new(); + foreach (var m in menus) + { + + var r = new Vue3RouterDto(); + r.OrderNum = m.OrderNum; + var routerName = m.Router?.Split("/").LastOrDefault(); + r.Id = m.Id; + r.ParentId = m.ParentId; + + //开头大写 + r.Name = routerName?.First().ToString().ToUpper() + routerName?.Substring(1); + r.Path = m.Router!; + r.Hidden = !m.IsShow; + + + if (m.MenuType == MenuTypeEnum.Catalogue) + { + r.Redirect = "noRedirect"; + r.AlwaysShow = true; + + //判断是否为最顶层的路由 + if (0 == m.ParentId) + { + r.Component = "Layout"; + } + else + { + r.Component = "ParentView"; + } + } + if (m.MenuType == MenuTypeEnum.Menu) + { + r.Redirect = "noRedirect"; + r.AlwaysShow = true; + r.Component = m.Component!; + r.AlwaysShow = false; + } + r.Meta = new Meta + { + Title = m.MenuName!, + Icon = m.MenuIcon!, + NoCache = !m.IsCache + }; + if (m.IsLink) + { + r.Meta.link = m.Router!; + r.AlwaysShow = false; + } + + routers.Add(r); + } + return TreeHelper.SetTree(routers); + + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/PostEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/PostEntity.cs new file mode 100644 index 00000000..57f3922c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/PostEntity.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 岗位表 + /// + [SugarTable("Post")] + public partial class PostEntity : IEntity, ISoftDelete, IAuditedObject, IOrderNum, IState + { + + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } = DateTime.Now; + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + + /// + /// 最后修改者 + /// + public long? LastModifierId { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + /// + /// 状态 + /// + public bool State { get; set; }=true; + + /// + /// 岗位编码 + /// + [SugarColumn(ColumnName = "PostCode")] + public string PostCode { get; set; }=string.Empty; + /// + /// 岗位名称 + /// + [SugarColumn(ColumnName = "PostName")] + public string PostName { get; set; } = string.Empty; + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleDeptEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleDeptEntity.cs new file mode 100644 index 00000000..21deaf31 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleDeptEntity.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities; + + /// + /// 角色部门关系表 + /// + [SugarTable("RoleDept")] +public partial class RoleDeptEntity : IEntity +{ + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 角色id + /// + [SugarColumn(ColumnName = "RoleId")] + public long? RoleId { get; set; } + /// + /// 部门id + /// + [SugarColumn(ColumnName = "DeptId")] + public long? DeptId { get; set; } + + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleEntity.cs new file mode 100644 index 00000000..f64a1ec2 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleEntity.cs @@ -0,0 +1,91 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 角色表 + /// + [SugarTable("Role")] + public class RoleEntity : IEntity, ISoftDelete, IAuditedObject, IOrderNum, IState + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } = DateTime.Now; + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + + /// + /// 最后修改者 + /// + public long? LastModifierId { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + + /// + /// 角色名 + /// + public string RoleName { get; set; } = string.Empty; + + /// + /// 角色编码 + /// + [SugarColumn(ColumnName = "RoleCode")] + public string RoleCode { get; set; } = string.Empty; + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + /// + /// 角色数据范围 + /// + [SugarColumn(ColumnName = "DataScope")] + public DataScopeEnum DataScope { get; set; } = DataScopeEnum.ALL; + + /// + /// 状态 + /// + public bool State { get; set; }=true; + + + [Navigate(typeof(RoleMenuEntity), nameof(RoleMenuEntity.RoleId), nameof(RoleMenuEntity.MenuId))] + public List Menus { get; set; } + + [Navigate(typeof(RoleDeptEntity), nameof(RoleDeptEntity.RoleId), nameof(RoleDeptEntity.DeptId))] + public List Depts { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleMenuEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleMenuEntity.cs new file mode 100644 index 00000000..0cec74cc --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/RoleMenuEntity.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities; +/// +/// 角色菜单关系表 +/// +[SugarTable("RoleMenu")] +public partial class RoleMenuEntity : IEntity + +{ + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "RoleId")] + public long RoleId { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MenuId")] + public long MenuId { get; set; } + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserEntity.cs new file mode 100644 index 00000000..ec4e43fc --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserEntity.cs @@ -0,0 +1,213 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; +using Yi.RBAC.Domain.Shared.Identity.EnumClasses; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 用户表 + /// + [SugarTable("User")] + public class UserEntity : IEntity, ISoftDelete, IAuditedObject, IOrderNum,IState + { + public UserEntity( ) + { + + } + public UserEntity(string userName,string password,long phone,string nick="萌新" ) + { + Id = SnowflakeHelper.NextId; + UserName=userName; + Password=password; + Phone = phone; + Nick = nick; + BuildPassword(); + } + + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 逻辑删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 姓名 + /// + public string? Name { get; set; } + + /// + /// 年龄 + /// + public int? Age { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } = string.Empty; + + /// + /// 密码 + /// + public string Password { get; set; } = string.Empty; + + /// + /// 加密盐值 + /// + public string Salt { get; set; } = string.Empty; + + /// + /// 头像 + /// + public string? Icon { get; set; } + + /// + /// 昵称 + /// + public string? Nick { get; set; } + + /// + /// 邮箱 + /// + public string? Email { get; set; } + + /// + /// Ip + /// + public string? Ip { get; set; } + + /// + /// 地址 + /// + + public string? Address { get; set; } + + /// + /// 电话 + /// + public long? Phone { get; set; } + + /// + /// 简介 + /// + public string? Introduction { get; set; } + + /// + /// 备注 + /// + public string? Remark { get; set; } + + /// + /// 性别 + /// + public SexEnum Sex { get; set; } = SexEnum.Unknown; + + /// + /// 部门id + /// + public long? DeptId { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } = DateTime.Now; + + /// + /// 创建者 + /// + public long? CreatorId { get; set; } + + /// + /// 最后修改者 + /// + public long? LastModifierId { get; set; } + + /// + /// 最后修改时间 + /// + public DateTime? LastModificationTime { get; set; } + + /// + /// 排序 + /// + public int OrderNum { get; set; } = 0; + + + /// + /// 状态 + /// + public bool State { get; set; } = true; + + + /// + /// 角色 + /// + [Navigate(typeof(UserRoleEntity), nameof(UserRoleEntity.UserId), nameof(UserRoleEntity.RoleId))] + public List Roles { get; set; } + + /// + /// 岗位 + /// + + [Navigate(typeof(UserPostEntity), nameof(UserPostEntity.UserId), nameof(UserPostEntity.PostId))] + public List Posts { get; set; } + + /// + /// 部门 + /// + + [Navigate(NavigateType.OneToOne, nameof(DeptId))] + public DeptEntity? Dept { get; set; } + + /// + /// 构建密码,MD5盐值加密 + /// + public UserEntity BuildPassword(string? password = null) + { + //如果不传值,那就把自己的password当作传进来的password + if (password == null) + { + if (Password == null) + { + throw new ArgumentNullException(nameof(Password)); + } + password = Password; + } + Salt = MD5Helper.GenerateSalt(); + Password = MD5Helper.SHA2Encode(password, Salt); + return this; + } + + /// + /// 判断密码和加密后的密码是否相同 + /// + /// + /// + public bool JudgePassword(string password) + { + if (this.Salt is null) + { + throw new ArgumentNullException(this.Salt); + } + var p = MD5Helper.SHA2Encode(password, Salt); + if (Password == MD5Helper.SHA2Encode(password, Salt)) + { + return true; + } + return false; + } + } + + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserPostEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserPostEntity.cs new file mode 100644 index 00000000..f2550a9c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserPostEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using SqlSugar; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities; +/// +/// 用户岗位表 +/// +[SugarTable("UserPost")] +public partial class UserPostEntity : IEntity +{ + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + /// + /// 用户id + /// + [SugarColumn(ColumnName = "UserId")] + public long UserId { get; set; } + /// + /// 岗位id + /// + [SugarColumn(ColumnName = "PostId")] + public long PostId { get; set; } + +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserRoleEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserRoleEntity.cs new file mode 100644 index 00000000..ba251dff --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Entities/UserRoleEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Identity.Entities +{ + /// + /// 用户角色关系表 + /// + [SugarTable("UserRole")] + public partial class UserRoleEntity : IEntity + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// 角色id + /// + public long RoleId { get; set; } + + /// + /// 用户id + /// + public long UserId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Repositories/IUserRepository.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Repositories/IUserRepository.cs new file mode 100644 index 00000000..c6e66764 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/Repositories/IUserRepository.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Dtos.Abstract; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Shared.Identity.Dtos; + +namespace Yi.RBAC.Domain.Identity.Repositories +{ + public interface IUserRepository:IRepository + { + /// + /// 获取当前登录用户的所有信息 + /// + /// + /// + Task GetUserAllInfoAsync(long userId); + + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/RoleManager.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/RoleManager.cs new file mode 100644 index 00000000..50ce5211 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/RoleManager.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.RBAC.Domain.Identity +{ + [AppService] + public class RoleManager + { + private IRepository _repository; + private IRepository _roleMenuRepository; + public RoleManager(IRepository repository, IRepository roleMenuRepository) + { + _repository = repository; + _roleMenuRepository = roleMenuRepository; + } + + /// + /// 给角色设置菜单 + /// + /// + /// + /// + public async Task GiveRoleSetMenuAsync(List roleIds, List menuIds) + { + //这个是需要事务的,在service中进行工作单元 + await _roleMenuRepository.DeleteAsync(u => roleIds.Contains(u.RoleId)); + //遍历用户 + foreach (var roleId in roleIds) + { + //添加新的关系 + List roleMenuEntity = new(); + foreach (var menu in menuIds) + { + roleMenuEntity.Add(new RoleMenuEntity() {Id=SnowflakeHelper.NextId, RoleId = roleId, MenuId = menu }); + } + //一次性批量添加 + await _roleMenuRepository.InsertRangeAsync(roleMenuEntity); + } + + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/UserManager.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/UserManager.cs new file mode 100644 index 00000000..9fc2377c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Identity/UserManager.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Entities; + +namespace Yi.RBAC.Domain.Identity +{ + [AppService] + public class UserManager + { + private readonly IRepository _repository; + private readonly IRepository _repositoryUserRole; + private readonly IRepository _repositoryUserPost; + public UserManager(IRepository repository, IRepository repositoryUserRole, IRepository repositoryUserPost) => + (_repository, _repositoryUserRole, _repositoryUserPost) = + (repository, repositoryUserRole, repositoryUserPost); + + /// + /// 给用户设置角色 + /// + /// + /// + /// + public async Task GiveUserSetRoleAsync(List userIds, List? roleIds) + { + //删除用户之前所有的用户角色关系(物理删除,没有恢复的必要) + await _repositoryUserRole.DeleteAsync(u => userIds.Contains(u.UserId)); + + if (roleIds is not null) + { + //遍历用户 + foreach (var userId in userIds) + { + //添加新的关系 + List userRoleEntities = new(); + + foreach (var roleId in roleIds) + { + userRoleEntities.Add(new UserRoleEntity() { Id = SnowflakeHelper.NextId, UserId = userId, RoleId = roleId }); + } + //一次性批量添加 + await _repositoryUserRole.InsertRangeAsync(userRoleEntities); + } + } + } + + + /// + /// 给用户设置岗位 + /// + /// + /// + /// + public async Task GiveUserSetPostAsync(List userIds, List? postIds) + { + //删除用户之前所有的用户角色关系(物理删除,没有恢复的必要) + await _repositoryUserPost.DeleteAsync(u => userIds.Contains(u.UserId)); + if (postIds is not null) + { + //遍历用户 + foreach (var userId in userIds) + { + //添加新的关系 + List userPostEntities = new(); + foreach (var post in postIds) + { + userPostEntities.Add(new UserPostEntity() { Id = SnowflakeHelper.NextId, UserId = userId, PostId = post }); + } + + //一次性批量添加 + await _repositoryUserPost.InsertRangeAsync(userPostEntities); + } + + } + } + + } + +} \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Entities/LoginLogEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Entities/LoginLogEntity.cs new file mode 100644 index 00000000..a5d29a1d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Entities/LoginLogEntity.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Logs.Entities +{ + [SugarTable("LoginLog")] + public class LoginLogEntity : IEntity, ICreationAuditedObject + { + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] + public long Id { get; set; } + public DateTime CreationTime { get; set; } + + /// + /// 登录用户 + /// + [SugarColumn(ColumnName = "LoginUser")] + public string? LoginUser { get; set; } + /// + /// 登录地点 + /// + [SugarColumn(ColumnName = "LoginLocation")] + public string? LoginLocation { get; set; } + /// + /// 登录Ip + /// + [SugarColumn(ColumnName = "LoginIp")] + public string? LoginIp { get; set; } + /// + /// 浏览器 + /// + [SugarColumn(ColumnName = "Browser")] + public string? Browser { get; set; } + /// + /// 操作系统 + /// + [SugarColumn(ColumnName = "Os")] + public string? Os { get; set; } + /// + /// 登录信息 + /// + [SugarColumn(ColumnName = "LogMsg")] + public string? LogMsg { get; set; } + + public long? CreatorId { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Event/LoginEventHandler.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Event/LoginEventHandler.cs new file mode 100644 index 00000000..c9a69e46 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Logs/Event/LoginEventHandler.cs @@ -0,0 +1,81 @@ +using Cike.EventBus.EventHandlerAbstracts; +using IPTools.Core; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using UAParser; +using Yi.Framework.AspNetCore.Extensions; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Logs.Entities; +using Yi.RBAC.Domain.Shared.Identity.Etos; + +namespace Yi.RBAC.Domain.Logs.Event +{ + public class LoginEventHandler : IDistributedEventHandler + { + private readonly IRepository _loginLogRepository; + private readonly HttpContext _httpContext; + public LoginEventHandler(IRepository loginLogRepository, IHttpContextAccessor httpContextAccessor) + { + _loginLogRepository = loginLogRepository; + _httpContext = httpContextAccessor.HttpContext; + } + public Task HandlerAsync(LoginEventArgs eventData) + { + var loginLogEntity = GetLoginLogInfo(_httpContext); + loginLogEntity.Id = SnowflakeHelper.NextId; + loginLogEntity.LogMsg = eventData.UserName + "登录系统"; + loginLogEntity.LoginUser = eventData.UserName; + loginLogEntity.LoginIp = _httpContext.GetClientIp(); + + _loginLogRepository.InsertAsync(loginLogEntity); + return Task.CompletedTask; + } + + /// + /// 获取客户端信息 + /// + /// + /// + private static ClientInfo GetClientInfo(HttpContext context) + { + var str = context.GetUserAgent(); + var uaParser = Parser.GetDefault(); + ClientInfo c = uaParser.Parse(str); + return c; + } + + /// + /// 记录用户登陆信息 + /// + /// + /// + private static LoginLogEntity GetLoginLogInfo(HttpContext context) + { + var ipAddr = context.GetClientIp(); + IpInfo location; + if (ipAddr == "127.0.0.1") + { + location = new IpInfo() { Province = "本地", City = "本机" }; + } + else + { + location = IpTool.Search(ipAddr); + } + ClientInfo clientInfo = GetClientInfo(context); + LoginLogEntity entity = new() + { + Browser = clientInfo.Device.Family, + Os = clientInfo.OS.ToString(), + LoginIp = ipAddr, + LoginLocation = location.Province + "-" + location.City + }; + + return entity; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Setting/Entities/ConfigEntity.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Setting/Entities/ConfigEntity.cs new file mode 100644 index 00000000..734d8ded --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Setting/Entities/ConfigEntity.cs @@ -0,0 +1,63 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Data.Auditing; +using Yi.Framework.Data.Entities; +using Yi.Framework.Ddd.Entities; + +namespace Yi.RBAC.Domain.Setting.Entities +{ + /// + /// 配置表 + /// + [SugarTable("Config")] + public class ConfigEntity : IEntity, IAuditedObject, IOrderNum, ISoftDelete + { + [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] + public long Id { get; set; } + /// + /// 配置名称 + /// + [SugarColumn(ColumnName = "ConfigName")] + public string ConfigName { get; set; } = string.Empty; + /// + /// 配置键 + /// + [SugarColumn(ColumnName = "ConfigKey")] + public string ConfigKey { get; set; } = string.Empty; + /// + /// 配置值 + /// + [SugarColumn(ColumnName = "ConfigValue")] + public string ConfigValue { get; set; } = string.Empty; + /// + /// 配置类别 + /// + [SugarColumn(ColumnName = "ConfigType")] + public string? ConfigType { get; set; } + + + /// + /// 排序字段 + /// + [SugarColumn(ColumnName = "OrderNum")] + public int OrderNum { get; set; } + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Remark")] + public string? Remark { get; set; } + public bool IsDeleted { get; set; } + + public DateTime CreationTime { get; set; } + + public long? CreatorId { get; set; } + + public long? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.Domain.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.Domain.csproj new file mode 100644 index 00000000..96c41ae0 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.Domain.csproj @@ -0,0 +1,33 @@ + + + + net6.0 + enable + enable + True + ./$(AssemblyName)SwaggerDoc.xml + + + + + + + + + + + + + + + + + + + + Always + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.DomainSwaggerDoc.xml b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.DomainSwaggerDoc.xml new file mode 100644 index 00000000..f855e45c --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/Yi.RBAC.DomainSwaggerDoc.xml @@ -0,0 +1,704 @@ + + + + Yi.RBAC.Domain + + + + + 用户领域服务 + + + + + 登录效验 + + + + + + + + + 判断账户合法存在 + + + + + + + + 令牌转换 + + + + + + + 更新密码 + + + + + + + + + + 重置密码 + + + + + + + + 部门表 + + + + + 主键 + + + + + 逻辑删除 + + + + + 创建时间 + + + + + 创建者 + + + + + 最后修改者 + + + + + 最后修改时间 + + + + + 排序 + + + + + 状态 + + + + + 部门名称 + + + + + 部门编码 + + + + + 负责人 + + + + + 父级id + + + + + 描述 + + + + + 菜单表 + + + + + 主键 + + + + + 逻辑删除 + + + + + 创建时间 + + + + + 创建者 + + + + + 最后修改者 + + + + + 最后修改时间 + + + + + 排序 + + + + + 状态 + + + + + 菜单名 + + + + + + + + + + + + + + + + + + + + 菜单图标 + + + + + 菜单组件路由 + + + + + 是否为外部链接 + + + + + 是否缓存 + + + + + 是否显示 + + + + + 描述 + + + + + 组件路径 + + + + + 路由参数 + + + + + 实体扩展 + + + + + 构建vue3路由 + + + + + + + 岗位表 + + + + + 主键 + + + + + 逻辑删除 + + + + + 创建时间 + + + + + 创建者 + + + + + 最后修改者 + + + + + 最后修改时间 + + + + + 排序 + + + + + 状态 + + + + + 岗位编码 + + + + + 岗位名称 + + + + + 描述 + + + + + 角色部门关系表 + + + + + 主键 + + + + + 角色id + + + + + 部门id + + + + + 角色表 + + + + + 主键 + + + + + 逻辑删除 + + + + + 创建时间 + + + + + 创建者 + + + + + 最后修改者 + + + + + 最后修改时间 + + + + + 排序 + + + + + 角色名 + + + + + 角色编码 + + + + + 描述 + + + + + 角色数据范围 + + + + + 状态 + + + + + 角色菜单关系表 + + + + + 主键 + + + + + + + + + + + + + + + 用户表 + + + + + 主键 + + + + + 逻辑删除 + + + + + 姓名 + + + + + 年龄 + + + + + 用户名 + + + + + 密码 + + + + + 加密盐值 + + + + + 头像 + + + + + 昵称 + + + + + 邮箱 + + + + + Ip + + + + + 地址 + + + + + 电话 + + + + + 简介 + + + + + 备注 + + + + + 性别 + + + + + 部门id + + + + + 创建时间 + + + + + 创建者 + + + + + 最后修改者 + + + + + 最后修改时间 + + + + + 排序 + + + + + 状态 + + + + + 角色 + + + + + 岗位 + + + + + 部门 + + + + + 构建密码,MD5盐值加密 + + + + + 判断密码和加密后的密码是否相同 + + + + + + + 用户岗位表 + + + + + 主键 + + + + + 用户id + + + + + 岗位id + + + + + 用户角色关系表 + + + + + 主键 + + + + + 角色id + + + + + 用户id + + + + + 获取当前登录用户的所有信息 + + + + + + + 给角色设置菜单 + + + + + + + + 给用户设置角色 + + + + + + + + 给用户设置岗位 + + + + + + + + 登录用户 + + + + + 登录地点 + + + + + 登录Ip + + + + + 浏览器 + + + + + 操作系统 + + + + + 登录信息 + + + + + 获取客户端信息 + + + + + + + 记录用户登陆信息 + + + + + + + 配置表 + + + + + 配置名称 + + + + + 配置键 + + + + + 配置值 + + + + + 配置类别 + + + + + 排序字段 + + + + + 描述 + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/YiRBACDomainModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/YiRBACDomainModule.cs new file mode 100644 index 00000000..8be5183e --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Domain/YiRBACDomainModule.cs @@ -0,0 +1,45 @@ +using Hei.Captcha; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Data; +using Yi.Framework.Ddd; +using Yi.Framework.DictionaryManager; +using Yi.Framework.EventBus; +using Yi.Framework.FileManager; +using Yi.Framework.ImageSharp; +using Yi.Framework.OperLogManager; +using Yi.Framework.Sms.Aliyun; +using Yi.RBAC.Domain.Logs; +using Yi.RBAC.Domain.Shared; + +namespace Yi.RBAC.Domain +{ + [DependsOn( + typeof(YiRBACDomainSharedModule), + typeof(YiFrameworkDataModule), + typeof(YiFrameworkEventBusModule), + typeof(YiFrameworkOperLogManagerModule), + typeof(YiFrameworkFileManagerModule), + typeof(YiFrameworkDictionaryManagerModule), + typeof(YiFrameworkCachingMemoryCacheModule), + typeof(YiFrameworkSmsAliyunModule), + typeof(YiFrameworkImageSharpModule) + )] + public class YiRBACDomainModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Repositories/UserRepository.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Repositories/UserRepository.cs new file mode 100644 index 00000000..efda7689 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Repositories/UserRepository.cs @@ -0,0 +1,88 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Sqlsugar.Repositories; +using Yi.Framework.Ddd.Dtos; +using Yi.Framework.Ddd.Dtos.Abstract; +using Yi.Framework.Ddd.Repositories; +using Yi.RBAC.Domain.Identity.Dtos; +using Yi.RBAC.Domain.Identity.Entities; +using Yi.RBAC.Domain.Identity.Repositories; +using Yi.RBAC.Domain.Shared.Identity.ConstClasses; +using Yi.RBAC.Domain.Shared.Identity.Dtos; + +namespace Yi.RBAC.Sqlsugar.Repositories +{ + [AppService] + public class UserRepository : SqlsugarRepository, IUserRepository + { + public UserRepository(ISqlSugarClient context) : base(context) + { + } + + + + /// + /// 获取用户id的全部信息 + /// + /// + /// + /// + public async Task GetUserAllInfoAsync(long userId) + { + var userRoleMenu = new UserRoleMenuDto(); + //首先获取到该用户全部信息,导航到角色、菜单,(菜单需要去重,完全交给Set来处理即可) + + //得到用户 + var user = await _DbQueryable.Includes(u => u.Roles.Where(r => r.IsDeleted == false).ToList(), r => r.Menus.Where(m => m.IsDeleted == false).ToList()).InSingleAsync(userId); + if (user is null) + { + throw new ArgumentNullException(nameof(userId)); + } + user.Password = string.Empty; + user.Salt = string.Empty; + + //超级管理员特殊处理 + if (UserConst.Admin.Equals(user.UserName)) + { + userRoleMenu.User = user; + userRoleMenu.RoleCodes.Add(UserConst.AdminRolesCode); + userRoleMenu.PermissionCodes.Add(UserConst.AdminPermissionCode); + return userRoleMenu; + } + + //得到角色集合 + var roleList = user.Roles; + + //得到菜单集合 + foreach (var role in roleList) + { + userRoleMenu.RoleCodes.Add(role.RoleCode); + + if (role.Menus is not null) + { + foreach (var menu in role.Menus) + { + if (!string.IsNullOrEmpty(menu.PermissionCode)) + { + userRoleMenu.PermissionCodes.Add(menu.PermissionCode); + } + userRoleMenu.Menus.Add(menu); + } + } + + //刚好可以去除一下多余的导航属性 + role.Menus = new List(); + userRoleMenu.Roles.Add(role); + } + + user.Roles = new List(); + userRoleMenu.User = user; + + return userRoleMenu; + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Yi.RBAC.Sqlsugar.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Yi.RBAC.Sqlsugar.csproj new file mode 100644 index 00000000..4334ae02 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/Yi.RBAC.Sqlsugar.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/YiRBACSqlsugarModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/YiRBACSqlsugarModule.cs new file mode 100644 index 00000000..02c6a398 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Sqlsugar/YiRBACSqlsugarModule.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using StartupModules; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Sqlsugar; +using Yi.RBAC.Domain; + +namespace Yi.RBAC.Sqlsugar +{ + [DependsOn(typeof(YiFrameworkCoreSqlsugarModule), + typeof(YiRBACDomainModule))] + public class YiRBACSqlsugarModule : IStartupModule + { + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + } + + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //services.AddTransient(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Program.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Program.cs new file mode 100644 index 00000000..f7ca1426 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Program.cs @@ -0,0 +1,30 @@ +using AspNetCore.Microsoft.AspNetCore.Hosting; +using Yi.Framework.Core.Autofac.Extensions; +using Yi.Framework.Core.Autofac.Modules; +using Yi.Framework.Core.Extensions; +using Yi.Framework.Core.Module; +using Yi.RBAC.Application; +using Yi.RBAC.Web; + +var builder = WebApplication.CreateBuilder(args); +//设置启动url +builder.WebHost.UseStartUrlsServer(builder.Configuration); + +//添加模块 +builder.UseYiModules(typeof(YiRBACWebModule)); + +//添加autofac模块,需要添加模块 +builder.Host.ConfigureAutoFacContainer(container => +{ + container.RegisterYiModule(AutoFacModuleEnum.PropertiesAutowiredModule, ModuleAssembly.Assemblies); +}); +var app = builder.Build(); + +//全局错误中间件,需要放在最早 +app.UseErrorHandlingServer(); + +app.UseAuthentication(); +app.UseAuthorization(); +app.MapControllers(); + +app.Run(); diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Properties/launchSettings.json b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Properties/launchSettings.json new file mode 100644 index 00000000..04173e5a --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "Yi.RBAC.Web": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:19001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Yi.RBAC.Web.csproj b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Yi.RBAC.Web.csproj new file mode 100644 index 00000000..10c410d1 --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/Yi.RBAC.Web.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + + + + + + diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/YiRBACWebModule.cs b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/YiRBACWebModule.cs new file mode 100644 index 00000000..91f968be --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/YiRBACWebModule.cs @@ -0,0 +1,59 @@ +using AspNetCore.Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Options; +using StartupModules; +using Yi.Framework.AspNetCore; +using Yi.Framework.Auth.JwtBearer; +using Yi.Framework.Core; +using Yi.Framework.Core.Attributes; +using Yi.Framework.Core.Autofac; +using Yi.Framework.Core.Module; +using Yi.Framework.Data.Json; +using Yi.Framework.OperLogManager; +using Yi.RBAC.Application; +using Yi.RBAC.Sqlsugar; + +namespace Yi.RBAC.Web +{ + [DependsOn( + typeof(YiFrameworkAspNetCoreModule), + typeof(YiFrameworkCoreAutofacModule), + typeof(YiRBACSqlsugarModule), + typeof(YiRBACApplicationModule) + )] + public class YiRBACWebModule : IStartupModule + { + public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context) + { + //添加控制器与动态api + services.AddControllers().AddJsonOptions(opt => { + + opt.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + + }); + + + services.AddAutoApiService(opt => + { + //NETServiceTest所在程序集添加进动态api配置 + opt.CreateConventional(ModuleAssembly.Assemblies, option => option.RootPath = string.Empty); + }); + + + //添加swagger + services.AddSwaggerServer(); + } + public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context) + { + //if (app.Environment.IsDevelopment()) + { + app.UseSwaggerServer(); + } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + app.UseRouting(); + } + } +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/appsettings.json b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/appsettings.json new file mode 100644 index 00000000..7bd04afc --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/appsettings.json @@ -0,0 +1,41 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + //"Default": "Debug", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + + //程序启动地址,*代表全部网口 + "StartUrl": "http://*:19001", + + //数据库类型列表 + "DbList": [ "Sqlite", "Mysql", "Sqlserver", "Oracle" ], + + "DbConnOptions": { + "Url": "DataSource=yi-sqlsugar-dev.db", + "DbType": "Sqlite", + "EnabledDbSeed": false, + "EnabledReadWrite": false, + "EnabledCodeFirst": true, + "EntityAssembly": null, + "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 + ] + }, + + //授权 + "JwtTokenOptions": { + "Audience": "yi", + "Issuer": "localhost:19001", + "Subject": "yiframwork", + "ExpSecond": 3600 + }, + + //开启种子数据 + "EnabledDataSeed": true +} diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/ip2region.db b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/ip2region.db new file mode 100644 index 00000000..0fc60e6c Binary files /dev/null and b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/ip2region.db differ diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/key.pem b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/key.pem new file mode 100644 index 00000000..3314ab6e --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj +MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu +NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ +qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg +p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR +ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi +VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV +laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8 +sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H +mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY +dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw +ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ +DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T +N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t +0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv +t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU +AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk +48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL +DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK +xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA +mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh +2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz +et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr +VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD +TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc +dn/RsYEONbwQSjIfMPkvxF+8HQ== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/public.pem b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/public.pem new file mode 100644 index 00000000..1c9b622d --- /dev/null +++ b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo +4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u ++qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh +kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ +0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg +cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc +mwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/yi-sqlsugar-dev.db b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/yi-sqlsugar-dev.db new file mode 100644 index 00000000..ef3bb696 Binary files /dev/null and b/Yi.Framework.Net6/src/project/rbac/Yi.RBAC.Web/yi-sqlsugar-dev.db differ diff --git a/Yi.Framework.Net6/test/ReadMe.txt b/Yi.Framework.Net6/test/ReadMe.txt new file mode 100644 index 00000000..e69de29b diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/AspNetCore/CurrentUserAddExtensions.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/AspNetCore/CurrentUserAddExtensions.cs new file mode 100644 index 00000000..7a6f756d --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/AspNetCore/CurrentUserAddExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Yi.Framework.Infrastructure.CurrentUsers; +using Yi.Framework.Infrastructure.CurrentUsers.Accessor; + +namespace Yi.Framework.Infrastructure.AspNetCore +{ + public static class CurrentUserAddExtensions + { + public static IServiceCollection AddCurrentUserServer(this IServiceCollection services) + { + services.AddSingleton(); + return services.AddTransient(); + } + + + + } + + + +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Class1.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Class1.cs deleted file mode 100644 index b0a33e80..00000000 --- a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Yi.Framework.Infrastructure -{ - public class Class1 - { - - } -} \ No newline at end of file diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/PathConst.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/PathConst.cs new file mode 100644 index 00000000..1f42f0a8 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/PathConst.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.Const +{ + /// + /// 定义公共文件常量 + /// + public class PathConst + { + public const string wwwroot = "wwwroot"; + public const string DataTemplate = "_DataTemplate"; + public const string DataExport = "_DataExport"; + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs new file mode 100644 index 00000000..9e1e50fa --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.Const +{ + public class TokenTypeConst + { + public const string Id = nameof(Id); + + public const string UserName = nameof(UserName); + + public const string TenantId = nameof(TenantId); + + public const string Email = nameof(Email); + + public const string PhoneNumber = nameof(PhoneNumber); + + public const string Roles = nameof(Roles); + + public const string Permission = nameof(Permission); + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs new file mode 100644 index 00000000..009a2100 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/CurrentPrincipalAccessorBase.cs @@ -0,0 +1,32 @@ +using System.Security.Claims; +using Yi.Framework.Infrastructure.Utils; + +namespace Yi.Framework.Infrastructure.CurrentUsers.Accessor +{ + public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor + { + public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal(); + + private readonly AsyncLocal _currentPrincipal = new AsyncLocal(); + + protected abstract ClaimsPrincipal GetClaimsPrincipal(); + + public virtual IDisposable Change(ClaimsPrincipal principal) + { + return SetCurrent(principal); + } + + private IDisposable SetCurrent(ClaimsPrincipal principal) + { + var parent = Principal; + _currentPrincipal.Value = principal; + return new DisposeAction, ClaimsPrincipal>>(static (state) => + { + var (currentPrincipal, parent) = state; + currentPrincipal.Value = parent; + }, (_currentPrincipal, parent)); + + } + } + +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..1d738af3 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/HttpContextCurrentPrincipalAccessor.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.CurrentUsers.Accessor +{ + public class HttpContextCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor + { + private readonly IHttpContextAccessor _httpContextAccessor; + + public HttpContextCurrentPrincipalAccessor(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return _httpContextAccessor.HttpContext?.User ?? base.GetClaimsPrincipal(); + } + + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs new file mode 100644 index 00000000..2e773806 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ICurrentPrincipalAccessor.cs @@ -0,0 +1,11 @@ +using System.Security.Claims; + +namespace Yi.Framework.Infrastructure.CurrentUsers.Accessor +{ + public interface ICurrentPrincipalAccessor + { + ClaimsPrincipal Principal { get; } + IDisposable Change(ClaimsPrincipal principal); + } + +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..10b57604 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/StaticCurrentPrincipalAccessor.cs @@ -0,0 +1,13 @@ +using System.Security.Claims; + +namespace Yi.Framework.Infrastructure.CurrentUsers.Accessor +{ + public class StaticPrincipalAccessor : CurrentPrincipalAccessorBase + { + public static ClaimsPrincipal ClaimsPrincipal { get; set; } + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return ClaimsPrincipal; + } + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs new file mode 100644 index 00000000..874e01fe --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/Accessor/ThreadCurrentPrincipalAccessor.cs @@ -0,0 +1,13 @@ +using System.Security.Claims; + +namespace Yi.Framework.Infrastructure.CurrentUsers.Accessor +{ + public class ThreadCurrentPrincipalAccessor : CurrentPrincipalAccessorBase + { + protected override ClaimsPrincipal GetClaimsPrincipal() + { + return Thread.CurrentPrincipal as ClaimsPrincipal; + } + } + +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs new file mode 100644 index 00000000..17e6c9b2 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Infrastructure.Const; +using Yi.Framework.Infrastructure.CurrentUsers.Accessor; + +namespace Yi.Framework.Infrastructure.CurrentUsers +{ + public class CurrentUser : ICurrentUser + { + private readonly ICurrentPrincipalAccessor _principalAccessor; + public CurrentUser(ICurrentPrincipalAccessor principalAccessor) + { + _principalAccessor = principalAccessor; + } + public bool IsAuthenticated => Id != 0; + + public long Id => FindUserId(); + + public string UserName => this.FindClaimValue(TokenTypeConst.UserName); + + /// + /// 暂时为默认值 + /// + public Guid TenantId { get; set; } = Guid.Empty; + + public string Email => FindClaimValue(TokenTypeConst.Email); + + public bool EmailVerified => false; + + public string PhoneNumber => FindClaimValue(TokenTypeConst.PhoneNumber); + + public bool PhoneNumberVerified => false; + + public string[]? Roles => this.FindClaims(TokenTypeConst.Roles).Select(c => c.Value).Distinct().ToArray(); + + public string[]? Permission => this.FindClaims(TokenTypeConst.Permission).Select(c => c.Value).Distinct().ToArray(); + + public virtual Claim FindClaim(string claimType) + { + return _principalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == claimType); + } + + public virtual Claim[] FindClaims(string claimType) + { + return _principalAccessor.Principal?.Claims.Where(c => c.Type == claimType).ToArray() ?? new Claim[0]; + } + + public virtual Claim[] GetAllClaims() + { + return _principalAccessor.Principal?.Claims.ToArray() ?? new Claim[0]; + } + + public string FindClaimValue(string claimType) + { + return FindClaim(claimType)?.Value; + } + + + public long FindUserId() + { + var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id); + if (userIdOrNull == null || string.IsNullOrWhiteSpace(userIdOrNull.Value)) + { + return 0; + } + + if (long.TryParse(userIdOrNull.Value, out long userId)) + { + return userId; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs new file mode 100644 index 00000000..18485ed7 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.CurrentUsers +{ + public interface ICurrentUser + { + public bool IsAuthenticated { get; } + public long Id { get; } + + public string UserName { get; } + + public Guid TenantId { get; } + + public string Email { get; } + + public bool EmailVerified { get; } + + public string PhoneNumber { get; } + + public bool PhoneNumberVerified { get; } + + public string[]? Roles { get; } + + public string[]? Permission { get; } + + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/DbConnOptions.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/DbConnOptions.cs new file mode 100644 index 00000000..075bea51 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/DbConnOptions.cs @@ -0,0 +1,47 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.Sqlsugar +{ + public class DbConnOptions + { + /// + /// 连接字符串,必填 + /// + public string? Url { get; set; } + + /// + /// 数据库类型 + /// + public DbType? DbType { get; set; } + + /// + /// 开启种子数据 + /// + public bool EnabledDbSeed { get; set; } = false; + + /// + /// 开启读写分离 + /// + public bool EnabledReadWrite { get; set; } = false; + + /// + /// 开启codefirst + /// + public bool EnabledCodeFirst { get; set; } = false; + + /// + /// 实体程序集 + /// + public List? EntityAssembly { get; set; } + + /// + /// 读写分离 + /// + public List? ReadUrl { get; set; } + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlSugarDbContext.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlSugarDbContext.cs new file mode 100644 index 00000000..9bb2372f --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlSugarDbContext.cs @@ -0,0 +1,147 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Infrastructure.CurrentUsers; + +namespace Yi.Framework.Infrastructure.Sqlsugar +{ + public class SqlSugarDbContext + { + /// + /// SqlSugar 客户端 + /// + public ISqlSugarClient SqlSugarClient { get; set; } + + protected ICurrentUser _currentUser; + + protected ILogger _logger; + + protected IOptions _options; + + public SqlSugarDbContext(IOptions options, ICurrentUser currentUser, ILogger logger) + { + _currentUser = currentUser; + _logger = logger; + _options = options; + var dbConnOptions = options.Value; + #region 组装options + if (dbConnOptions.DbType is null) + { + throw new ArgumentException(SqlsugarConst.DbType配置为空); + } + var slavaConFig = new List(); + if (dbConnOptions.EnabledReadWrite) + { + if (dbConnOptions.ReadUrl is null) + { + throw new ArgumentException(SqlsugarConst.读写分离为空); + } + + var readCon = dbConnOptions.ReadUrl; + + readCon.ForEach(s => + { + //如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接 + slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s }); + }); + } + #endregion + SqlSugarClient = new SqlSugarScope(new ConnectionConfig() + { + //准备添加分表分库 + DbType = dbConnOptions.DbType ?? DbType.Sqlite, + ConnectionString = dbConnOptions.Url, + IsAutoCloseConnection = true, + MoreSettings = new ConnMoreSettings() + { + DisableNvarchar = true + }, + SlaveConnectionConfigs = slavaConFig, + //设置codefirst非空值判断 + ConfigureExternalServices = new ConfigureExternalServices + { + EntityService = (c, p) => + { + //高版C#写法 支持string?和string + if (new NullabilityInfoContext() + .Create(c).WriteState is NullabilityState.Nullable) + { + p.IsNullable = true; + } + } + } + }, + db => + { + + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + + //switch (entityInfo.OperationType) + //{ + // case DataFilterType.UpdateByObject: + + // if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime))) + // { + // entityInfo.SetValue(DateTime.Now); + // } + // if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId))) + // { + // if (_currentUser != null) + // { + // entityInfo.SetValue(_currentUser.Id); + // } + // } + // break; + // case DataFilterType.InsertByObject: + // if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime))) + // { + // entityInfo.SetValue(DateTime.Now); + // } + // if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId))) + // { + // if (_currentUser != null) + // { + // entityInfo.SetValue(_currentUser.Id); + // } + // } + + // //插入时,需要租户id,先预留 + // if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId))) + // { + // //if (this.CurrentTenant is not null) + // //{ + // // entityInfo.SetValue(this.CurrentTenant.Id); + // //} + // } + // break; + //} + }; + db.Aop.OnLogExecuting = (s, p) => + { + StringBuilder sb = new StringBuilder(); + //sb.Append("执行SQL:" + s.ToString()); + //foreach (var i in p) + //{ + // sb.Append($"\r\n参数:{i.ParameterName},参数值:{i.Value}"); + //} + sb.Append($"\r\n 完整SQL:{UtilMethods.GetSqlString(DbType.MySql, s, p)}"); + logger?.LogDebug(sb.ToString()); + }; + //扩展 + OnSqlSugarClientConfig(db); + }); + } + + //上下文对象扩展 + protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient) + { + } + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarConst.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarConst.cs new file mode 100644 index 00000000..527ff144 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarConst.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Infrastructure.Sqlsugar +{ + public class SqlsugarConst + { + public const string 读写分离为空 = "开启读写分离后,读库连接不能为空"; + + public const string DbType配置为空 = "DbType配置为空,必须选择一个数据库类型"; + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarExtensions.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarExtensions.cs new file mode 100644 index 00000000..41742812 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Yi.Framework.Infrastructure.Sqlsugar +{ + /// + /// 这一块,需要做成上下文对象,会进行重构 + /// + public static class SqlsugarExtensions + { + //使用上下文对象 + public static void AddDbSqlsugarContextServer(this IServiceCollection services) + { + services.AddSingleton(x => x.GetRequiredService().SqlSugarClient); + services.AddSingleton(); + } + + + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Startup.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Startup.cs new file mode 100644 index 00000000..f75e0f45 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Startup.cs @@ -0,0 +1,26 @@ +using Furion; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Yi.Framework.Infrastructure.AspNetCore; +using Yi.Framework.Infrastructure.Sqlsugar; + +namespace Yi.Framework.Infrastructure; + +public class Startup : AppStartup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddCurrentUserServer(); + + services.Configure(App.Configuration.GetSection("DbConnOptions")); + + services.AddDbSqlsugarContextServer(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Utils/DisposeAction.cs b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Utils/DisposeAction.cs new file mode 100644 index 00000000..9aae2f64 --- /dev/null +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Utils/DisposeAction.cs @@ -0,0 +1,27 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Yi.Framework.Infrastructure.Utils +{ + public class DisposeAction : IDisposable + { + private readonly Action _action; + + private readonly T _parameter; + + /// + /// Creates a new object. + /// + /// Action to be executed when this object is disposed. + /// The parameter of the action. + public DisposeAction(Action action, T parameter) + { + _action = action; + _parameter = parameter; + } + + public void Dispose() + { + _action(_parameter); + } + } +} diff --git a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Yi.Framework.Infrastructure.csproj b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Yi.Framework.Infrastructure.csproj index 9db0aaf6..b34164b4 100644 --- a/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Yi.Framework.Infrastructure.csproj +++ b/Yi.Furion.Rbac/Yi.Framework.Infrastructure/Yi.Framework.Infrastructure.csproj @@ -7,7 +7,7 @@ - + diff --git a/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/System/Services/SystemService.cs b/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/System/Services/SystemService.cs index d5861b29..4ee3379c 100644 --- a/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/System/Services/SystemService.cs +++ b/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/System/Services/SystemService.cs @@ -1,7 +1,14 @@ -namespace Yi.Furion.Rbac.Application; +using SqlSugar; + +namespace Yi.Furion.Rbac.Application; public class SystemService : ISystemService, ITransient { + private readonly ISqlSugarClient _sqlSugarClient; + public SystemService(ISqlSugarClient sqlSugarClient) + { + _sqlSugarClient=sqlSugarClient; + } public string GetDescription() { return "让 .NET 开发更简单,更通用,更流行。"; diff --git a/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/Yi.Furion.Rbac.Application.csproj b/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/Yi.Furion.Rbac.Application.csproj index 269b4ec0..84fca2d5 100644 --- a/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/Yi.Furion.Rbac.Application.csproj +++ b/Yi.Furion.Rbac/Yi.Furion.Rbac.Application/Yi.Furion.Rbac.Application.csproj @@ -22,7 +22,8 @@ - + + diff --git a/Yi.Furion.Rbac/Yi.Furion.Rbac.Database.Migrations/Yi.Furion.Rbac.Database.Migrations.csproj b/Yi.Furion.Rbac/Yi.Furion.Rbac.Database.Migrations/Yi.Furion.Rbac.Database.Migrations.csproj deleted file mode 100644 index b8a492f7..00000000 --- a/Yi.Furion.Rbac/Yi.Furion.Rbac.Database.Migrations/Yi.Furion.Rbac.Database.Migrations.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - net6.0 - - - - - - - - - diff --git a/Yi.Furion.Rbac/Yi.Furion.Rbac.Web.Entry/appsettings.json b/Yi.Furion.Rbac/Yi.Furion.Rbac.Web.Entry/appsettings.json index 704f5921..32de42f7 100644 --- a/Yi.Furion.Rbac/Yi.Furion.Rbac.Web.Entry/appsettings.json +++ b/Yi.Furion.Rbac/Yi.Furion.Rbac.Web.Entry/appsettings.json @@ -7,5 +7,20 @@ "Microsoft.EntityFrameworkCore": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + //数据库类型列表 + "DbList": [ "Sqlite", "Mysql", "Sqlserver", "Oracle" ], + + "DbConnOptions": { + "Url": "DataSource=yi-sqlsugar-dev.db", + "DbType": "Sqlite", + "EnabledReadWrite": false, + "EnabledCodeFirst": false, + "EntityAssembly": null, + "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 + ] + } } \ No newline at end of file