diff --git a/BootstrapAdmin-Blazor.slnf b/BootstrapAdmin-Blazor.slnf
new file mode 100644
index 00000000..4f220dd9
--- /dev/null
+++ b/BootstrapAdmin-Blazor.slnf
@@ -0,0 +1,11 @@
+{
+ "solution": {
+ "path": "BootstrapAdmin.sln",
+ "projects": [
+ "src\\blazor\\admin\\Bootstrap.Admin.Blazor.DataAccess\\Bootstrap.Admin.Blazor.DataAccess.csproj",
+ "src\\blazor\\admin\\Bootstrap.Admin.Blazor\\Bootstrap.Admin.Blazor.csproj",
+ "src\\mvc\\admin\\Bootstrap.Admin\\Bootstrap.Admin.csproj",
+ "src\\mvc\\admin\\Bootstrap.DataAccess\\Bootstrap.DataAccess.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/BootstrapAdmin.sln b/BootstrapAdmin.sln
index 66a25a42..91e3ea6d 100644
--- a/BootstrapAdmin.sln
+++ b/BootstrapAdmin.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29215.179
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLServer", "SQLServer", "{87319AF5-7C40-4362-B67C-35F9DD737DB4}"
ProjectSection(SolutionItems) = preProject
@@ -10,15 +10,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLServer", "SQLServer", "{
db\SqlServer\Install.sql = db\SqlServer\Install.sql
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Admin", "src\admin\Bootstrap.Admin\Bootstrap.Admin.csproj", "{7B2B7043-3CB2-4C5A-BDF2-8C47F1A5471A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Admin", "src\mvc\admin\Bootstrap.Admin\Bootstrap.Admin.csproj", "{7B2B7043-3CB2-4C5A-BDF2-8C47F1A5471A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "db", "db", "{586410F2-C1F0-47CD-AB28-2CF506DED2C8}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client", "src\client\Bootstrap.Client\Bootstrap.Client.csproj", "{C82A6E45-AB90-43D1-8429-5CBE953D8151}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client", "src\mvc\client\Bootstrap.Client\Bootstrap.Client.csproj", "{C82A6E45-AB90-43D1-8429-5CBE953D8151}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess", "src\admin\Bootstrap.DataAccess\Bootstrap.DataAccess.csproj", "{8D62BE79-BE13-43C8-969B-C9B00B3C84B7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess", "src\mvc\admin\Bootstrap.DataAccess\Bootstrap.DataAccess.csproj", "{8D62BE79-BE13-43C8-969B-C9B00B3C84B7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLite", "SQLite", "{523515EC-2AD7-4282-9AF4-9D20371183B0}"
ProjectSection(SolutionItems) = preProject
@@ -26,7 +26,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLite", "SQLite", "{523515
db\SQLite\Install.sql = db\SQLite\Install.sql
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess.MongoDB", "src\admin\Bootstrap.DataAccess.MongoDB\Bootstrap.DataAccess.MongoDB.csproj", "{8336F096-4B4A-4710-A1FA-0F5E44CD8D26}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess.MongoDB", "src\mvc\admin\Bootstrap.DataAccess.MongoDB\Bootstrap.DataAccess.MongoDB.csproj", "{8336F096-4B4A-4710-A1FA-0F5E44CD8D26}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongoDB", "MongoDB", "{A06A0AD8-A246-4329-B024-7174AE4A3EDE}"
ProjectSection(SolutionItems) = preProject
@@ -57,9 +57,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Postgresql", "Postgresql",
db\Postgresql\install.sql = db\Postgresql\install.sql
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.DataAccess", "src\client\Bootstrap.Client.DataAccess\Bootstrap.Client.DataAccess.csproj", "{843811A2-FE49-410F-BF9F-9F1FB14A1DEE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.DataAccess", "src\mvc\client\Bootstrap.Client.DataAccess\Bootstrap.Client.DataAccess.csproj", "{843811A2-FE49-410F-BF9F-9F1FB14A1DEE}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.DataAccess.MongoDB", "src\client\Bootstrap.Client.DataAccess.MongoDB\Bootstrap.Client.DataAccess.MongoDB.csproj", "{BC1C6D63-ADA9-4C3B-89F0-CEB191A86BF5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.DataAccess.MongoDB", "src\mvc\client\Bootstrap.Client.DataAccess.MongoDB\Bootstrap.Client.DataAccess.MongoDB.csproj", "{BC1C6D63-ADA9-4C3B-89F0-CEB191A86BF5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6AD32A76-F3AA-423E-96EA-E5CC679934D1}"
EndProject
@@ -74,9 +74,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{E057452E-0
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{85574E7C-7D58-4135-AB4B-76678552D271}"
- ProjectSection(SolutionItems) = preProject
- src\admin\Bootstrap.Admin\Dockerfile = src\admin\Bootstrap.Admin\Dockerfile
- EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "srcipts", "srcipts", "{72C103DB-E1D3-449F-97C2-DF12CA111FD4}"
EndProject
@@ -130,9 +127,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "git", "git", "{64EACBD1-23D
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "blazor", "blazor", "{DAE3826B-AAAB-468A-9A06-2F56EF5C0767}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.Blazor", "src\blazor\Bootstrap.Client.Blazor\Bootstrap.Client.Blazor.csproj", "{90BC5C25-0F93-4CDE-833C-3D8243E19D3B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.Blazor", "src\blazor\client\Bootstrap.Client.Blazor\Bootstrap.Client.Blazor.csproj", "{90BC5C25-0F93-4CDE-833C-3D8243E19D3B}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.Blazor.Shared", "src\blazor\Bootstrap.Client.Blazor.Shared\Bootstrap.Client.Blazor.Shared.csproj", "{B306BD58-1C73-40F2-86F7-E1763344007B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.Blazor.Shared", "src\blazor\client\Bootstrap.Client.Blazor.Shared\Bootstrap.Client.Blazor.Shared.csproj", "{B306BD58-1C73-40F2-86F7-E1763344007B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{C07631B9-5E5E-417A-9A16-3C88956D574E}"
ProjectSection(SolutionItems) = preProject
@@ -140,6 +137,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{C07631
.github\workflows\docker.yml = .github\workflows\docker.yml
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Admin.Blazor", "src\blazor\admin\Bootstrap.Admin.Blazor\Bootstrap.Admin.Blazor.csproj", "{485C1B75-7E3C-4AFC-8A91-2347FFEC1E96}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mvc", "mvc", "{C996F427-DA93-49D6-9804-4E665D195FC2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{45ADEF9B-C8BD-4224-9E12-F6716E85A22C}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{55A2459A-6BDE-4493-B2C0-5BE1673E99EE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bootstrap.Admin.Blazor.DataAccess", "src\blazor\admin\Bootstrap.Admin.Blazor.DataAccess\Bootstrap.Admin.Blazor.DataAccess.csproj", "{75730767-A53A-4CFB-BACB-B90401288FA6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -182,6 +189,14 @@ Global
{B306BD58-1C73-40F2-86F7-E1763344007B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B306BD58-1C73-40F2-86F7-E1763344007B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B306BD58-1C73-40F2-86F7-E1763344007B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {485C1B75-7E3C-4AFC-8A91-2347FFEC1E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {485C1B75-7E3C-4AFC-8A91-2347FFEC1E96}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {485C1B75-7E3C-4AFC-8A91-2347FFEC1E96}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {485C1B75-7E3C-4AFC-8A91-2347FFEC1E96}.Release|Any CPU.Build.0 = Release|Any CPU
+ {75730767-A53A-4CFB-BACB-B90401288FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {75730767-A53A-4CFB-BACB-B90401288FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {75730767-A53A-4CFB-BACB-B90401288FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {75730767-A53A-4CFB-BACB-B90401288FA6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -190,7 +205,7 @@ Global
{87319AF5-7C40-4362-B67C-35F9DD737DB4} = {586410F2-C1F0-47CD-AB28-2CF506DED2C8}
{7B2B7043-3CB2-4C5A-BDF2-8C47F1A5471A} = {E03B7391-B52F-4449-B400-5CD9DE01F085}
{C82A6E45-AB90-43D1-8429-5CBE953D8151} = {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}
- {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0} = {41B6D37A-5E5E-42B3-85E4-D81A81E3D757}
+ {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0} = {C996F427-DA93-49D6-9804-4E665D195FC2}
{8D62BE79-BE13-43C8-969B-C9B00B3C84B7} = {E03B7391-B52F-4449-B400-5CD9DE01F085}
{523515EC-2AD7-4282-9AF4-9D20371183B0} = {586410F2-C1F0-47CD-AB28-2CF506DED2C8}
{8336F096-4B4A-4710-A1FA-0F5E44CD8D26} = {E03B7391-B52F-4449-B400-5CD9DE01F085}
@@ -200,7 +215,7 @@ Global
{6F61C2AC-84D4-48A9-8A48-680657CC8175} = {586410F2-C1F0-47CD-AB28-2CF506DED2C8}
{843811A2-FE49-410F-BF9F-9F1FB14A1DEE} = {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}
{BC1C6D63-ADA9-4C3B-89F0-CEB191A86BF5} = {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}
- {E03B7391-B52F-4449-B400-5CD9DE01F085} = {41B6D37A-5E5E-42B3-85E4-D81A81E3D757}
+ {E03B7391-B52F-4449-B400-5CD9DE01F085} = {C996F427-DA93-49D6-9804-4E665D195FC2}
{C6F2DCA0-7941-4C28-9328-2D495F5DCB00} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
{FDCFC3E3-14CF-40B2-9FE5-5BC239AAC110} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
{5F732D4E-133B-4DA6-811B-C369CDC3FB89} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
@@ -208,8 +223,13 @@ Global
{41E078CA-F005-4B66-B440-FD7EB731AD61} = {586410F2-C1F0-47CD-AB28-2CF506DED2C8}
{64EACBD1-23DD-4168-BEED-55D47DB1A8BB} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
{DAE3826B-AAAB-468A-9A06-2F56EF5C0767} = {41B6D37A-5E5E-42B3-85E4-D81A81E3D757}
- {90BC5C25-0F93-4CDE-833C-3D8243E19D3B} = {DAE3826B-AAAB-468A-9A06-2F56EF5C0767}
- {B306BD58-1C73-40F2-86F7-E1763344007B} = {DAE3826B-AAAB-468A-9A06-2F56EF5C0767}
+ {90BC5C25-0F93-4CDE-833C-3D8243E19D3B} = {55A2459A-6BDE-4493-B2C0-5BE1673E99EE}
+ {B306BD58-1C73-40F2-86F7-E1763344007B} = {55A2459A-6BDE-4493-B2C0-5BE1673E99EE}
+ {485C1B75-7E3C-4AFC-8A91-2347FFEC1E96} = {45ADEF9B-C8BD-4224-9E12-F6716E85A22C}
+ {C996F427-DA93-49D6-9804-4E665D195FC2} = {41B6D37A-5E5E-42B3-85E4-D81A81E3D757}
+ {45ADEF9B-C8BD-4224-9E12-F6716E85A22C} = {DAE3826B-AAAB-468A-9A06-2F56EF5C0767}
+ {55A2459A-6BDE-4493-B2C0-5BE1673E99EE} = {DAE3826B-AAAB-468A-9A06-2F56EF5C0767}
+ {75730767-A53A-4CFB-BACB-B90401288FA6} = {45ADEF9B-C8BD-4224-9E12-F6716E85A22C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {221EAE38-5F75-4391-9A48-E462A9F3B8FC}
diff --git a/Directory.Build.props b/Directory.Build.props
index 0f784c34..f1ef7cae 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -11,17 +11,17 @@
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 5c90830b..c7627e53 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -2,6 +2,10 @@
+
+ net5.0
+
+
https://gitee.com/LongbowEnterprise/BootstrapAdmin
https://gitee.com/LongbowEnterprise/BootstrapAdmin.git
@@ -10,8 +14,4 @@
$(MSBuildProjectName).xml
-
- net5.0
-
-
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Bootstrap.Admin.Blazor.DataAccess.csproj b/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Bootstrap.Admin.Blazor.DataAccess.csproj
new file mode 100644
index 00000000..263821e9
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Bootstrap.Admin.Blazor.DataAccess.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Dict.cs b/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Dict.cs
new file mode 100644
index 00000000..d58b6823
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor.DataAccess/Dict.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+
+using PetaPoco;
+
+namespace Bootstrap.Admin.Blazor.DataAccess
+{
+ ///
+ /// 字典配置项
+ ///
+ [TableName("Dicts")]
+ public class Dict
+ {
+ ///
+ /// 获得/设置 字典主键 数据库自增列
+ ///
+ public string? Id { get; set; }
+
+ ///
+ /// 获得/设置 字典分类
+ ///
+ public string Category { get; set; } = "";
+
+ ///
+ /// 获得/设置 字典名称
+ ///
+ public string Name { get; set; } = "";
+
+ ///
+ /// 获得/设置 字典字典值
+ ///
+ public string Code { get; set; } = "";
+
+ ///
+ /// 获得/设置 字典定义值 0 表示系统使用,1 表示用户自定义 默认为 1
+ ///
+ public int Define { get; set; } = 1;
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor
new file mode 100644
index 00000000..b9431eaf
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor
@@ -0,0 +1,11 @@
+
+
+
+ @Title
+
+
+
+
+
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor.cs
new file mode 100644
index 00000000..97021777
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/App.razor.cs
@@ -0,0 +1,27 @@
+namespace Bootstrap.Admin.Blazor
+{
+ ///
+ ///
+ ///
+ public partial class App
+ {
+ ///
+ ///
+ ///
+ public string? Title { get; set; }
+
+ [Inject]
+ [NotNull]
+ private BootstrapAppContext? AppContext { get; set; }
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ //Title = DictHelper.RetrieveWebTitle(AppContext.AppId);
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Bootstrap.Admin.Blazor.csproj b/src/blazor/admin/Bootstrap.Admin.Blazor/Bootstrap.Admin.Blazor.csproj
new file mode 100644
index 00000000..f13b995c
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Bootstrap.Admin.Blazor.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net6.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/BootstrapAdmin.db b/src/blazor/admin/Bootstrap.Admin.Blazor/BootstrapAdmin.db
new file mode 100644
index 00000000..ab36649a
Binary files /dev/null and b/src/blazor/admin/Bootstrap.Admin.Blazor/BootstrapAdmin.db differ
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor
new file mode 100644
index 00000000..d5af07eb
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor
@@ -0,0 +1,18 @@
+@typeparam TItem
+
+
+
+ @TableToolbarTemplate
+
+
+ @ColumnsTemplete(context)
+
+
+ @CustomerSearchTemplate(context)
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor.cs
new file mode 100644
index 00000000..a537d031
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/BlazorTable.razor.cs
@@ -0,0 +1,60 @@
+namespace Bootstrap.Admin.Blazor.Components
+{
+ ///
+ ///
+ ///
+ [CascadingTypeParameter(nameof(TItem))]
+ public partial class BlazorTable where TItem : class, new()
+ {
+ ///
+ ///
+ ///
+ [Parameter]
+ public IEnumerable? PageItemsSource { get; set; }
+
+ ///
+ ///
+ ///
+ [NotNull]
+ [Parameter]
+ public RenderFragment? ColumnsTemplete { get; set; }
+
+ ///
+ ///
+ ///
+ [NotNull]
+ [Parameter]
+ public RenderFragment? CustomerSearchTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [NotNull]
+ [Parameter]
+ public RenderFragment? TableToolbarTemplate { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public bool IsPagination { get; set; } = true;
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public ITableSearchModel? TableSearchModel { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public IDataService? DataService { get; set; }
+
+ ///
+ ///
+ ///
+ [Parameter]
+ public Func>>? OnQueryAsync { get; set; }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Components/DictSearch.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/DictSearch.razor
new file mode 100644
index 00000000..4c5399d7
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Components/DictSearch.razor
@@ -0,0 +1,27 @@
+
+
+@code {
+ private IEnumerable? Items { get; set; } = new List()
+ {
+ new SelectedItem("","全部"),
+ new SelectedItem("0","系统使用"),
+ new SelectedItem("1","自定义"),
+ };
+
+ [Parameter]
+ [NotNull]
+ public DictsSearchModel? Value { get; set; }
+
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+}
\ No newline at end of file
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Controllers/AccountController.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Controllers/AccountController.cs
new file mode 100644
index 00000000..7e74dd13
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Controllers/AccountController.cs
@@ -0,0 +1,238 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.WebUtilities;
+using System.Security.Claims;
+
+namespace Bootstrap.Admin.Controllers
+{
+ /////
+ ///// Account controller.
+ /////
+ //[AllowAnonymous]
+ //[AutoValidateAntiforgeryToken]
+ //public class AccountController : Controller
+ //{
+ //private const string MobileSchema = "Mobile";
+ /////
+ ///// 系统锁屏界面
+ /////
+ /////
+ //[HttpGet]
+ //public async Task Lock()
+ //{
+ // if (!User.Identity!.IsAuthenticated) return Login();
+
+ // var authenticationType = User.Identity.AuthenticationType;
+ // await HttpContext.SignOutAsync();
+ // var urlReferrer = Request.Headers["Referer"].FirstOrDefault();
+ // if (urlReferrer?.Contains("/Pages", StringComparison.OrdinalIgnoreCase) ?? false) urlReferrer = "/Pages";
+ // return View(new LockModel(User.Identity.Name)
+ // {
+ // AuthenticationType = authenticationType,
+ // ReturnUrl = WebUtility.UrlEncode(string.IsNullOrEmpty(urlReferrer) ? CookieAuthenticationDefaults.LoginPath.Value : urlReferrer)
+ // });
+ //}
+
+ /////
+ ///// 系统锁屏界面
+ /////
+ /////
+ /////
+ /////
+ /////
+ /////
+ //[HttpPost]
+ //[IgnoreAntiforgeryToken]
+ //public Task Lock([FromServices] ISMSProvider provider, string userName, string password, string authType)
+ //{
+ // // 根据不同的登陆方式
+ // Task ret;
+ // if (authType == MobileSchema) ret = Mobile(provider, userName, password);
+ // else ret = Login(userName, password, string.Empty);
+ // return ret;
+ //}
+
+ /////
+ ///// 系统登录方法
+ /////
+ /////
+ /////
+ /////
+ //[HttpGet]
+ //public ActionResult Login([FromQuery] string? appId = null, [FromQuery] string view = "")
+ //{
+ // if (DictHelper.RetrieveSystemModel())
+ // {
+ // ViewBag.UserName = "Admin";
+ // ViewBag.Password = "123789";
+ // }
+ // return User.Identity!.IsAuthenticated ? (ActionResult)Redirect("~/Home/Index") : LoginView(view, new LoginModel(appId));
+ //}
+
+ //private ViewResult LoginView(string view, LoginModel model)
+ //{
+ // if (string.IsNullOrEmpty(view))
+ // {
+ // // retrieve login view from db
+ // view = DictHelper.RetrieveLoginView();
+ // }
+ // return View(view, model);
+ //}
+
+ /////
+ ///// 短信验证登陆方法
+ /////
+ /////
+ /////
+ /////
+ /////
+ //[HttpPost()]
+ //public async Task Mobile([FromServices] ISMSProvider provider, string phone, string code)
+ //{
+ // if (string.IsNullOrEmpty(phone) || string.IsNullOrEmpty(code)) return RedirectLogin();
+
+ // var auth = provider.Validate(phone, code);
+ // await HttpContext.Log(phone, auth);
+ // if (auth)
+ // {
+ // var user = UserHelper.Retrieves().FirstOrDefault(u => u.UserName == phone);
+ // if (user == null)
+ // {
+ // user = new User()
+ // {
+ // ApprovedBy = "Mobile",
+ // ApprovedTime = DateTime.Now,
+ // DisplayName = "手机用户",
+ // UserName = phone,
+ // Password = code,
+ // Icon = "default.jpg",
+ // Description = "手机用户",
+ // App = provider.Options.App
+ // };
+ // if (UserHelper.Save(user) && !string.IsNullOrEmpty(user.Id))
+ // {
+ // // 根据配置文件设置默认角色
+ // var roles = RoleHelper.Retrieves().Where(r => provider.Options.Roles.Any(rl => rl.Equals(r.RoleName, StringComparison.OrdinalIgnoreCase))).Select(r => r.Id!);
+ // RoleHelper.SaveByUserId(user.Id, roles);
+ // }
+ // }
+ // }
+ // return auth ? await SignInAsync(phone, true, MobileSchema) : RedirectLogin();
+ //}
+
+ //private IActionResult RedirectLogin()
+ //{
+ // var query = Request.Query.Aggregate(new Dictionary(), (d, v) =>
+ // {
+ // d.Add(v.Key, v.Value.ToString());
+ // return d;
+ // });
+ // return Redirect(QueryHelpers.AddQueryString(Request.PathBase + CookieAuthenticationDefaults.LoginPath, query));
+ //}
+
+ /////
+ ///// Login the specified userName, password and remember.
+ /////
+ ///// The login.
+ ///// User name.
+ ///// Password.
+ ///// Remember.
+ //[HttpPost]
+ //public async Task Login(string userName, string password, string remember)
+ //{
+ // if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)) return RedirectLogin();
+
+ // var auth = UserHelper.Authenticate(userName, password);
+ // await HttpContext.Log(userName, auth);
+ // return auth ? await SignInAsync(userName, remember == "true") : LoginView("", new LoginModel() { AuthFailed = true });
+ //}
+
+ //private async Task SignInAsync(string userName, bool persistent, string authenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme)
+ //{
+ // var identity = new ClaimsIdentity(authenticationScheme);
+ // identity.AddClaim(new Claim(ClaimTypes.Name, userName));
+ // await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties { ExpiresUtc = DateTimeOffset.Now.AddDays(DictHelper.RetrieveCookieExpiresPeriod()), IsPersistent = persistent });
+
+ // // redirect origin url
+ // var originUrl = Request.Query[CookieAuthenticationDefaults.ReturnUrlParameter].FirstOrDefault() ?? "~/Home/Index";
+ // return Redirect(originUrl);
+ //}
+
+ /////
+ ///// Logout this instance.
+ /////
+ /////
+ ///// The logout.
+ //[HttpGet]
+ //public async Task Logout([FromQuery] string appId)
+ //{
+ // await HttpContext.SignOutAsync();
+ // return Redirect(QueryHelpers.AddQueryString(Request.PathBase + CookieAuthenticationDefaults.LoginPath, "AppId", appId ?? BootstrapAppContext.AppId));
+ //}
+
+ /////
+ ///// Accesses the denied.
+ /////
+ ///// The denied.
+ //[ResponseCache(Duration = 600)]
+ //[HttpGet]
+ //public ActionResult AccessDenied() => View("Error", ErrorModel.CreateById(403));
+
+ /////
+ ///// Gitee 认证
+ /////
+ /////
+ //[HttpGet]
+ //public IActionResult Gitee([FromServices] IConfiguration config)
+ //{
+ // var enabled = config.GetValue($"{nameof(GiteeOptions)}:Enabled", false);
+ // return Challenge(enabled ? GiteeDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme);
+ //}
+
+ /////
+ ///// GitHub 认证
+ /////
+ /////
+ //[HttpGet]
+ //public IActionResult GitHub([FromServices] IConfiguration config)
+ //{
+ // var enabled = config.GetValue($"{nameof(GitHubOptions)}:Enabled", false);
+ // return Challenge(enabled ? GitHubDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme);
+ //}
+
+ /////
+ ///// Tencent 认证
+ /////
+ /////
+ //[HttpGet]
+ //public IActionResult Tencent([FromServices] IConfiguration config)
+ //{
+ // var enabled = config.GetValue($"{nameof(TencentOptions)}:Enabled", false);
+ // return Challenge(enabled ? TencentDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme);
+ //}
+
+ /////
+ ///// Alipay 认证
+ /////
+ /////
+ //[HttpGet]
+ //public IActionResult Alipay([FromServices] IConfiguration config)
+ //{
+ // var enabled = config.GetValue($"{nameof(AlipayOptions)}:Enabled", false);
+ // return Challenge(enabled ? AlipayDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme);
+ //}
+
+ /////
+ ///// WeChat 认证
+ /////
+ /////
+ //[HttpGet]
+ //public IActionResult WeChat([FromServices] IConfiguration config)
+ //{
+ // var enabled = config.GetValue($"{nameof(WeChatOptions)}:Enabled", false);
+ // return Challenge(enabled ? WeChatDefaults.AuthenticationScheme : CookieAuthenticationDefaults.AuthenticationScheme);
+ //}
+ //}
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/DatabaseExtensions.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/DatabaseExtensions.cs
new file mode 100644
index 00000000..2f0bb139
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/DatabaseExtensions.cs
@@ -0,0 +1,127 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using PetaPoco;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace BootstrapBlazor.DataAcces.PetaPoco
+{
+ ///
+ ///
+ ///
+ public static class DatabaseExtensions
+ {
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task> FetchAsync(this IDatabase db, IEnumerable where, string? sortName = null, SortOrder sortOrder = SortOrder.Unset)
+ {
+ var exp = where.GetFilterLambda();
+ var sql = new Sql();
+ AnalysisExpression(exp, db, sql);
+
+ if (!string.IsNullOrEmpty(sortName) && sortOrder != SortOrder.Unset)
+ {
+ sql.OrderBy(sortOrder == SortOrder.Asc ? sortName : $"{sortName} desc");
+ }
+ return db.FetchAsync(sql);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task> PageAsync(this IDatabase db, long pageIndex, long pageItems, IEnumerable where, string? sortName = null, SortOrder sortOrder = SortOrder.Unset)
+ {
+ var exp = where.GetFilterLambda();
+ var sql = new Sql();
+ AnalysisExpression(exp, db, sql);
+
+ if (!string.IsNullOrEmpty(sortName) && sortOrder != SortOrder.Unset)
+ {
+ sql.OrderBy(sortOrder == SortOrder.Asc ? sortName : $"{sortName} desc");
+ }
+ return db.PageAsync(pageIndex, pageItems, sql);
+ }
+
+ private static void AnalysisExpression(Expression expression, IDatabase db, Sql sql)
+ {
+ switch (expression.NodeType)
+ {
+ case ExpressionType.Lambda:
+ if (expression is LambdaExpression exp)
+ {
+ AnalysisExpression(exp.Body, db, sql);
+ }
+ break;
+ case ExpressionType.AndAlso:
+ if (expression is BinaryExpression andExp)
+ {
+ AnalysisExpression(andExp.Left, db, sql);
+ AnalysisExpression(andExp.Right, db, sql);
+ }
+ break;
+ case ExpressionType.Call:
+ if (expression is MethodCallExpression callExp)
+ {
+ if (callExp.Method.Name == "Contains")
+ {
+ if (callExp.Object is MemberExpression callLeft)
+ {
+ var callColName = GetColumnName(callLeft.Member) ?? callLeft.Member.Name;
+ var p = (callExp.Arguments[0] as ConstantExpression)?.Value;
+ if (p != null)
+ {
+ sql.Where($"{db.Provider.EscapeSqlIdentifier(callColName)} like @0", $"%{p}%");
+ }
+ }
+ }
+ }
+ break;
+ case ExpressionType.Equal:
+ case ExpressionType.NotEqual:
+ case ExpressionType.GreaterThan:
+ case ExpressionType.GreaterThanOrEqual:
+ case ExpressionType.LessThan:
+ case ExpressionType.LessThanOrEqual:
+ var binaryExp = (expression as BinaryExpression)!;
+ var left = (binaryExp.Left as MemberExpression)!;
+
+ // 查找 PetaPoco.Column 标签
+ var columnName = GetColumnName(left.Member) ?? left.Member.Name;
+
+ // 查找操作符右侧
+ var right = (binaryExp.Right as ConstantExpression)!;
+ var v = right.Value;
+
+ if (v != null)
+ {
+ var operatorExp = GetOperatorExpression(expression);
+ sql.Where($"{db.Provider.EscapeSqlIdentifier(columnName)} {operatorExp} @0", v);
+ }
+ break;
+
+ }
+ }
+
+ private static string? GetColumnName(MemberInfo member) => member.CustomAttributes
+ .FirstOrDefault(i => i.AttributeType == typeof(ColumnAttribute))?.NamedArguments
+ .FirstOrDefault(i => i.MemberName == "Name").TypedValue.Value?.ToString();
+
+ private static string GetOperatorExpression(Expression expression) => expression.NodeType switch
+ {
+ ExpressionType.Equal => "=",
+ ExpressionType.NotEqual => "!=",
+ ExpressionType.GreaterThan => ">",
+ ExpressionType.GreaterThanOrEqual => ">=",
+ ExpressionType.LessThan => "<",
+ ExpressionType.LessThanOrEqual => "<=",
+ _ => ""
+ };
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/ServicesExtensions.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/ServicesExtensions.cs
new file mode 100644
index 00000000..522b354b
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Extensions/ServicesExtensions.cs
@@ -0,0 +1,76 @@
+using BootstrapBlazor.DataAcces.PetaPoco;
+using System.Text;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ ///
+ ///
+ public static class ServicesExtensions
+ {
+ ///
+ /// 添加示例后台任务
+ ///
+ ///
+ public static IServiceCollection AddBootstrapBlazorAdminServices(this IServiceCollection services)
+ {
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+
+ // 增加后台任务服务
+ //services.AddTaskServices();
+
+ //services.AddLogging(logging => logging.AddFileLogger().AddCloudLogger().AddDBLogger(ExceptionsHelper.Log));
+ services.AddCors();
+ services.AddResponseCompression();
+ //services.AddCodePageProvider();
+
+ //services.AddCacheManager();
+ //services.AddDbAdapter();
+ //services.AddIPLocator(DictHelper.ConfigIPLocator);
+ //services.AddOnlineUsers();
+ //services.AddSignalR().AddJsonProtocol(op => op.PayloadSerializerOptions.AddDefaultConverters());
+ //services.AddBootstrapAdminAuthentication(Configuration)
+ // .AddGitee(OAuthHelper.Configure)
+ // .AddGitHub(OAuthHelper.Configure)
+ // .AddTencent(OAuthHelper.Configure)
+ // .AddAlipay(OAuthHelper.Configure);
+ //services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireBootstrapAdminAuthorizate().Build());
+ //services.AddButtonAuthorization(MenuHelper.AuthorizateButtons);
+ //services.AddBootstrapAdminBackgroundTask();
+ //services.AddHttpClient();
+ //services.AddAdminHealthChecks();
+ //services.AddSMSProvider();
+
+ //services.AddSwagger();
+ //services.AddApiVersioning(option =>
+ //{
+ // option.DefaultApiVersion = new ApiVersion(1, 0);
+ // option.ReportApiVersions = true;
+ // option.AssumeDefaultVersionWhenUnspecified = true;
+ // option.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("api-version"), new QueryStringApiVersionReader("api-version"));
+ //});
+ //services.AddExceptionless();
+ //services.AddControllersWithViews(options =>
+ //{
+ // options.Filters.Add();
+ // options.Filters.Add();
+ // options.Filters.Add>();
+ //}).AddJsonOptions(op => op.JsonSerializerOptions.AddDefaultConverters());
+ //services.AddControllersWithViews().AddJsonOptions(op => op.JsonSerializerOptions.AddDefaultConverters());
+
+ // 增加 BootstrapBlazor 组件
+ services.AddBootstrapBlazor();
+
+ // 增加数据服务
+ services.AddSingleton(typeof(IDataService<>), typeof(DefaultDataService<>));
+
+ // 增加 BootstrapApp 上下文服务
+ services.AddSingleton();
+
+ // 增加数据服务
+ services.AddSingleton();
+
+ return services;
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Models/DictsSearchModel.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Models/DictsSearchModel.cs
new file mode 100644
index 00000000..a9158a5b
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Models/DictsSearchModel.cs
@@ -0,0 +1,62 @@
+using Bootstrap.Admin.Blazor.DataAccess;
+
+namespace Bootstrap.Admin.Blazor.Models
+{
+ ///
+ ///
+ ///
+ public class DictsSearchModel : ITableSearchModel
+ {
+ ///
+ ///
+ ///
+ public string? Category { get; set; }
+
+ ///
+ ///
+ ///
+ public int? Define { get; set; }
+
+ ///
+ ///
+ ///
+ public string? Name { get; set; }
+
+ ///
+ ///
+ ///
+ ///
+ public IEnumerable GetSearchs()
+ {
+ var ret = new List();
+
+ if (!string.IsNullOrEmpty(Name))
+ {
+ ret.Add(new SearchFilterAction(nameof(Dict.Name), Name));
+ }
+
+ if (!string.IsNullOrEmpty(Category))
+ {
+ ret.Add(new SearchFilterAction(nameof(Dict.Category), Category));
+ }
+
+ if (Define.HasValue)
+ {
+ ret.Add(new SearchFilterAction(nameof(Dict.Define), Define, FilterAction.Equal));
+ }
+
+ return ret;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public void Reset()
+ {
+ Category = null;
+ Name = null;
+ Define = null;
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Models/LoginModel.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Models/LoginModel.cs
new file mode 100644
index 00000000..d9b7793a
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Models/LoginModel.cs
@@ -0,0 +1,27 @@
+namespace Bootstrap.Admin.Blazor.Models
+{
+ ///
+ /// 登陆页面 Model
+ ///
+ public class LoginModel
+ {
+ /////
+ ///// 默认构造函数
+ /////
+ /////
+ //public LoginModel(string? appId = null)
+ //{
+ // //ImageLibUrl = DictHelper.RetrieveImagesLibUrl();
+ //}
+
+ ///
+ /// 验证码图床地址
+ ///
+ public string? ImageLibUrl { get; protected set; }
+
+ ///
+ /// 是否登录认证失败 为真时客户端弹出滑块验证码
+ ///
+ public bool AuthFailed { get; set; }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor
new file mode 100644
index 00000000..8f69e5a4
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor
@@ -0,0 +1,22 @@
+@page "/admin/dicts"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if (context is DictsSearchModel searchModel)
+ {
+
+ }
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor.cs
new file mode 100644
index 00000000..5f78f41f
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Dicts.razor.cs
@@ -0,0 +1,30 @@
+namespace Bootstrap.Admin.Blazor.Pages.Admin
+{
+ ///
+ ///
+ ///
+ public partial class Dicts
+ {
+ private IEnumerable? EditDefines { get; set; }
+
+ private IEnumerable? LookUp { get; set; }
+
+ private ITableSearchModel? DictsSearchModel { get; set; } = new DictsSearchModel();
+
+ ///
+ ///
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+ EditDefines = new List()
+ {
+ new SelectedItem("0","系统使用"),
+ new SelectedItem("1","自定义"),
+ };
+
+ LookUp = EditDefines;
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Index.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Index.razor
new file mode 100644
index 00000000..6e4f365c
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Index.razor
@@ -0,0 +1,6 @@
+@page "/"
+@page "/admin"
+@page "/admin/index"
+@attribute [TabItemOption(Text = "后台管理")]
+
+欢迎使用后台管理
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor
new file mode 100644
index 00000000..1153b4bc
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor
@@ -0,0 +1,17 @@
+@page "/admin/users"
+
+@*
+
+
+
+
+
+
+
+
+
+
+
+
+
+*@
\ No newline at end of file
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor.cs
new file mode 100644
index 00000000..c15f1490
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/Users.razor.cs
@@ -0,0 +1,60 @@
+using Task = System.Threading.Tasks.Task;
+
+namespace Bootstrap.Admin.Blazor.Pages.Admin
+{
+ ///
+ ///
+ ///
+ public partial class Users
+ {
+ //[Inject]
+ //[NotNull]
+ //private DialogService? DialogService { get; set; }
+
+ //[Inject]
+ //[NotNull]
+ //private ToastService? ToastService { get; set; }
+
+ //private async Task OnAssignmentDept(IEnumerable users)
+ //{
+ // if (users.Count() == 1)
+ // {
+ // var option = new DialogOption()
+ // {
+ // Title = "部门授权",
+ // BodyTemplate = BootstrapDynamicComponent.CreateComponent>(new Dictionary
+ // {
+ // [nameof(CheckboxList.Items)] = GroupHelper.Retrieves().Select(s => new SelectedItem(s.GroupCode, s.GroupName))
+ // }).Render()
+ // };
+
+ // await DialogService.Show(option);
+ // }
+ // else
+ // {
+ // await ToastService.Warning("部门授权", "请选择一个用户");
+ // }
+ //}
+
+ //private async Task OnAssignmentRoles(IEnumerable users)
+ //{
+ // if (users.Count() != 0)
+ // {
+ // var option = new DialogOption()
+ // {
+ // Title = "分配角色",
+ // BodyTemplate = BootstrapDynamicComponent.CreateComponent>(new Dictionary
+ // {
+ // [nameof(CheckboxList.Items)] = RoleHelper.Retrieves().Select(s => new SelectedItem(s.Id!, s.RoleName) { Active = s.Checked == "" ? false : true })
+ // }).Render()
+ // };
+
+ // await DialogService.Show(option);
+ // }
+ // else
+ // {
+ // await ToastService.Warning("分配角色", "请选择一个用户");
+ // }
+ //}
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/_Imports.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/_Imports.razor
new file mode 100644
index 00000000..6de5d191
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Admin/_Imports.razor
@@ -0,0 +1 @@
+@attribute [Authorize]
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Home/Index.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Home/Index.razor
new file mode 100644
index 00000000..c600a12a
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/Home/Index.razor
@@ -0,0 +1,3 @@
+@page "/home"
+@page "/home/index"
+@attribute [TabItemOption(Text = "首页")]
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Host.cshtml b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Host.cshtml
new file mode 100644
index 00000000..7a162f41
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Host.cshtml
@@ -0,0 +1,8 @@
+@page "/"
+@namespace Bootstrap.Admin.Blazor.Pages
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+@{
+ Layout = "_Layout";
+}
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Layout.cshtml b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Layout.cshtml
new file mode 100644
index 00000000..3a8b8475
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Pages/_Layout.cshtml
@@ -0,0 +1,42 @@
+@using Microsoft.AspNetCore.Components.Web
+@namespace Bootstrap.Admin.Blazor.Pages
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @RenderBody()
+
+
+
+ An error has occurred. This application may no longer respond until reloaded.
+
+
+ An unhandled exception has occurred. See browser dev tools for details.
+
+
Reload
+
🗙
+
+
+
+
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Program.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Program.cs
new file mode 100644
index 00000000..814cc97b
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Program.cs
@@ -0,0 +1,30 @@
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+builder.Services.AddRazorPages();
+builder.Services.AddServerSideBlazor();
+
+// 注入项目服务
+builder.Services.AddBootstrapBlazorAdminServices();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (!app.Environment.IsDevelopment())
+{
+ app.UseExceptionHandler("/Error");
+}
+
+app.UseStaticFiles();
+
+app.UseRouting();
+
+// 开启缓存中间件
+//app.UseCacheManager();
+
+// 开启 webapi
+app.MapDefaultControllerRoute();
+app.MapBlazorHub();
+app.MapFallbackToPage("/_Host");
+
+app.Run();
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Properties/launchSettings.json b/src/blazor/admin/Bootstrap.Admin.Blazor/Properties/launchSettings.json
new file mode 100644
index 00000000..f3ceb803
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Properties/launchSettings.json
@@ -0,0 +1,28 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:24748",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "Bootstrap.Admin.Blazor": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:5110",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapAppContext.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapAppContext.cs
new file mode 100644
index 00000000..44dcfbe8
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapAppContext.cs
@@ -0,0 +1,22 @@
+namespace Bootstrap.Admin.Blazor.Services
+{
+ ///
+ ///
+ ///
+ public class BootstrapAppContext
+ {
+ ///
+ ///
+ ///
+ public string AppId { get; }
+
+ ///
+ ///
+ ///
+ ///
+ public BootstrapAppContext(IConfiguration configuration)
+ {
+ AppId = configuration.GetValue("AppId", "demo");
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapMenuService.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapMenuService.cs
new file mode 100644
index 00000000..a0b36b8d
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/BootstrapMenuService.cs
@@ -0,0 +1,9 @@
+namespace Bootstrap.Admin.Blazor.Services
+{
+ ///
+ ///
+ ///
+ public class BootstrapMenuService : IBootstrapMenuService
+ {
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Services/DefaultDataService.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/DefaultDataService.cs
new file mode 100644
index 00000000..f5eb551a
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/DefaultDataService.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Website: https://www.blazor.zone or https://argozhang.github.io/
+
+using PetaPoco;
+using PetaPoco.Extensions;
+using PetaPoco.Providers;
+
+namespace BootstrapBlazor.DataAcces.PetaPoco
+{
+ ///
+ /// PetaPoco ORM 的 IDataService 接口实现
+ ///
+ internal class DefaultDataService : DataServiceBase where TModel : class, new()
+ {
+ private readonly IDatabase _db;
+
+ ///
+ /// 构造函数
+ ///
+ public DefaultDataService(IConfiguration configuration)
+ {
+ //TODO: 后期改造成自定适配
+ var connString = configuration.GetConnectionString("bb");
+ _db = new Database(connString);
+ }
+
+ ///
+ /// 删除方法
+ ///
+ ///
+ ///
+ public override Task DeleteAsync(IEnumerable models)
+ {
+ // 通过模型获取主键列数据
+ // 支持批量删除
+ _db.DeleteBatch(models);
+ return Task.FromResult(true);
+ }
+
+ ///
+ /// 保存方法
+ ///
+ ///
+ ///
+ ///
+ public override async Task SaveAsync(TModel model, ItemChangedType changedType)
+ {
+ if (changedType == ItemChangedType.Add)
+ {
+ await _db.InsertAsync(model);
+ }
+ else
+ {
+ await _db.UpdateAsync(model);
+ }
+ return true;
+ }
+
+ ///
+ /// 查询方法
+ ///
+ ///
+ ///
+ public override async Task> QueryAsync(QueryPageOptions option)
+ {
+ var ret = new QueryData()
+ {
+ IsSorted = true,
+ IsFiltered = true,
+ IsSearch = true
+ };
+
+ var filters = option.Filters.Concat(option.Searchs).Concat(option.CustomerSearchs);
+ if (option.IsPage)
+ {
+ var items = await _db.PageAsync(option.PageIndex, option.PageItems, filters, option.SortName, option.SortOrder);
+
+ ret.TotalCount = Convert.ToInt32(items.TotalItems);
+ ret.Items = items.Items;
+ }
+ else
+ {
+ var items = await _db.FetchAsync(filters, option.SortName, option.SortOrder);
+ ret.TotalCount = items.Count;
+ ret.Items = items;
+ }
+ return ret;
+ }
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Services/IBootstrapMenuService.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/IBootstrapMenuService.cs
new file mode 100644
index 00000000..a63ff8df
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Services/IBootstrapMenuService.cs
@@ -0,0 +1,9 @@
+namespace Bootstrap.Admin.Blazor.Services
+{
+ ///
+ ///
+ ///
+ public interface IBootstrapMenuService
+ {
+ }
+}
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor b/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor
new file mode 100644
index 00000000..dae2155e
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor
@@ -0,0 +1,33 @@
+@inherits LayoutComponentBase
+
+
+
+ Bootstrap of Blazor
+
+ 超级管理员
+
+
+
+
+
+
+ 后台管理
+
+
+
+
+
+ 管理员
+
+
+
+
+
+ @Body
+
+
+
diff --git a/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor.cs b/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor.cs
new file mode 100644
index 00000000..73478338
--- /dev/null
+++ b/src/blazor/admin/Bootstrap.Admin.Blazor/Shared/MainLayout.razor.cs
@@ -0,0 +1,32 @@
+namespace Bootstrap.Admin.Blazor.Shared
+{
+ ///
+ /// MainLayout 布局类
+ ///
+ public partial class MainLayout
+ {
+ private IEnumerable