HasUserAsync();
20 | }
21 | }
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/DisabledButton.razor:
--------------------------------------------------------------------------------
1 |
2 | 默认按钮
3 | 主要按钮
4 | 成功按钮
5 | 信息按钮
6 | 警告按钮
7 | 危险按钮
8 |
9 |
10 | 朴素按钮
11 | 主要按钮
12 | 成功按钮
13 | 信息按钮
14 | 警告按钮
15 | 危险按钮
16 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:58364",
7 | "sslPort": 44392
8 | }
9 | },
10 | "profiles": {
11 | "BlazAdmin.Docs": {
12 | "commandName": "Project",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | },
17 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
18 | },
19 | "Docker": {
20 | "commandName": "Docker",
21 | "launchBrowser": true,
22 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
23 | "environmentVariables": {
24 | "ASPNETCORE_URLS": "https://+:443;http://+:80",
25 | "ASPNETCORE_HTTPS_PORT": "44393"
26 | },
27 | "httpPort": 58371,
28 | "useSSL": true,
29 | "sslPort": 44393
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/BlazAdmin/BNotAuthorizedBase.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace BlazAdmin
8 | {
9 | public class BNotAuthorizedBase : BAdminPageBase
10 | {
11 | internal bool? requireInitilize;
12 | [Parameter]
13 | public object LoginPage { get; set; }
14 | [Parameter]
15 | public object CreatePage { get; set; }
16 |
17 | [Parameter]
18 | public LoginInfoModel DefaultUser { get; set; }
19 |
20 | protected override async Task OnAfterRenderAsync(bool firstRender)
21 | {
22 | await base.OnAfterRenderAsync(firstRender);
23 | if (!firstRender)
24 | {
25 | return;
26 | }
27 | requireInitilize = await UserService.IsRequireInitilizeAsync();
28 | RequireRender = true;
29 | StateHasChanged();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # BlazAdmin
2 |
3 | #### Description
4 | 基于Blazui的后台管理模板,无JS,无TS,非 Silverlight,非 WebForm,开箱即用
5 |
6 | #### Software Architecture
7 | Software architecture description
8 |
9 | #### Installation
10 |
11 | 1. xxxx
12 | 2. xxxx
13 | 3. xxxx
14 |
15 | #### Instructions
16 |
17 | 1. xxxx
18 | 2. xxxx
19 | 3. xxxx
20 |
21 | #### Contribution
22 |
23 | 1. Fork the repository
24 | 2. Create Feat_xxx branch
25 | 3. Commit your code
26 | 4. Create Pull Request
27 |
28 |
29 | #### Gitee Feature
30 |
31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp)
35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
37 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BAdminPageBase.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin.Abstract;
2 | using Blazui.Component;
3 | using Microsoft.AspNetCore.Components;
4 | using Microsoft.AspNetCore.Components.Authorization;
5 | using Microsoft.AspNetCore.Identity;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BlazAdmin
12 | {
13 | public class BAdminPageBase : BComponentBase
14 | {
15 | [Inject]
16 | public IUserService UserService { get; set; }
17 |
18 | public string Username { get; private set; }
19 | [Inject]
20 | public AuthenticationStateProvider AuthenticationStateProvider { get; set; }
21 |
22 | protected override async Task OnInitializedAsync()
23 | {
24 | base.OnInitialized();
25 | var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
26 | var user = authState?.User;
27 | Username = user?.Identity?.Name;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/BorderedRadio.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 | 选项1
4 | 选项2
5 | 选项3
6 |
7 |
8 |
9 |
10 | 选项1
11 | 选项2
12 | 选项3
13 |
14 |
15 |
16 |
17 | 选项1
18 | 选项2
19 | 选项3
20 |
21 |
22 |
23 |
24 | 选项1
25 | 选项2
26 | 选项3
27 |
28 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/InlineForm.razor:
--------------------------------------------------------------------------------
1 | @inherits InlineFormBase
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 立即创建
17 | 重置
18 |
19 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/Activity.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Select;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace BlazAdmin.Docs.Demo.Form
9 | {
10 | public class Activity
11 | {
12 | public string Name { get; set; }
13 | public Area Area { get; set; }
14 | public DateTime? Time { get; set; }
15 | public bool Delivery { get; set; }
16 | public List Type { get; set; }
17 | public string Resource { get; set; }
18 | public string Description { get; set; }
19 |
20 | public override string ToString()
21 | {
22 | return $"名称:{Name},区域:{Area},日期:{Time?.ToString()},即时配送:{Delivery},性质:{string.Join(",", Type)},特殊资源:{Resource},活动形式:{Description}";
23 | }
24 | }
25 |
26 | public enum Area
27 | {
28 | [Description("上海")]
29 | Shanghai = 0,
30 |
31 | [Description("北京")]
32 | Beijing
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BLogin.razor:
--------------------------------------------------------------------------------
1 | @inherits BLoginBase
2 |
3 |
4 |
5 |
6 | 系统登录
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 登录
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BCreateSuperUser.razor:
--------------------------------------------------------------------------------
1 | @inherits BCreateSuperUserBase
2 |
3 |
4 |
5 |
6 | 创建管理员
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 创建
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BModifyPasswordBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Blazui.Component.Form;
3 | using Microsoft.AspNetCore.Components;
4 | using Microsoft.AspNetCore.Identity;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BlazAdmin
12 | {
13 | public class BModifyPasswordBase : BAdminPageBase
14 | {
15 | protected BForm form;
16 |
17 |
18 | public virtual async System.Threading.Tasks.Task ModifyAsync()
19 | {
20 | if (!form.IsValid())
21 | {
22 | return;
23 | }
24 |
25 | var info = form.GetValue();
26 |
27 | var result = await UserService.ChangePasswordAsync(Username, info.OldPassword, info.NewPassword);
28 | if (string.IsNullOrWhiteSpace(result))
29 | {
30 | _ = DialogService.CloseDialogAsync(this, info);
31 | return;
32 | }
33 | Toast(result);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 宇辰
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/dotnetcore-develop.yml:
--------------------------------------------------------------------------------
1 | name: Develop
2 |
3 | on:
4 | push:
5 | branches:
6 | - develop
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: Setup .NET Core
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: 3.1.100
19 | - name: Restore with dotnet
20 | run: dotnet restore src/BlazAdmin/BlazAdmin.csproj --configfile $GITHUB_WORKSPACE/nuget.config
21 | - name: Build with dotnet
22 | run: dotnet build src/BlazAdmin/BlazAdmin.csproj --configuration Release
23 | - name: Build Number Generator
24 | uses: einaregilsson/build-number@v2
25 | with:
26 | token: ${{secrets.github_token}}
27 | - name: pack nuget
28 | run: dotnet pack src/BlazAdmin/BlazAdmin.csproj /p:PackageVersion=0.0.2.${BUILD_NUMBER}-develop -c Release --no-build --no-restore
29 | - name: push nuget
30 | run: dotnet nuget push src/BlazAdmin/bin/Release/BlazAdmin.0.0.2.${BUILD_NUMBER}-develop.nupkg -s https://www.myget.org/F/wzxinchen-blazor/api/v2/package -k 2564e20d-4cd4-482e-ba4b-daf05e2effa8
31 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/RadioButton/RadioButton.razor:
--------------------------------------------------------------------------------
1 | @inherits RadioButtonBase
2 |
3 |
4 | 上海
5 | 北京
6 | 广东
7 |
8 |
9 |
10 |
11 | 选项1
12 | 选项2
13 | 选项3
14 |
15 |
16 |
17 |
18 | 选项1
19 | 选项2
20 | 选项3
21 |
22 |
23 |
24 |
25 | 选项1
26 | 选项2
27 | 选项3
28 |
29 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/BlazAdmin/AccountController.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin.Abstract;
2 | using Microsoft.AspNetCore.Identity;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace BlazAdmin
11 | {
12 | public class AccountController : ControllerBase
13 | {
14 | private readonly IUserService userService;
15 |
16 | public AccountController(IUserService userService)
17 | {
18 | this.userService = userService;
19 | }
20 |
21 | [HttpPost]
22 | public async System.Threading.Tasks.Task Login([FromForm]LoginInfoModel model, [FromQuery]string callback)
23 | {
24 | var err = await userService.LoginAsync(null, model.Username, model.Password, callback);
25 | if (!string.IsNullOrWhiteSpace(err))
26 | {
27 | return BadRequest(err);
28 | }
29 | return Redirect(callback);
30 | }
31 |
32 | public async Task Logout([FromQuery]string callback)
33 | {
34 | await userService.LogoutAsync(null, callback);
35 | return Redirect(callback);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/AutoGenerateFieldsActvity.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Form;
2 | using Blazui.Component.Select;
3 | using Blazui.Component.Switch;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.ComponentModel.DataAnnotations;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace BlazAdmin.Docs.Demo.Form
11 | {
12 | public class AutoGenerateFieldsActvity
13 | {
14 | [Display(Name = "名称")]
15 | public string Name { get; set; }
16 | [Display(Name = "区域")]
17 | public Area Area { get; set; }
18 | [Display(Name = "日期")]
19 | public DateTime? Time { get; set; }
20 | [Display(Name = "即时配送")]
21 | [FormControl(typeof(BSwitch))]
22 | public bool Delivery { get; set; }
23 | [Display(Name = "性质")]
24 | public List Type { get; set; }
25 | [Display(Name = "特殊资源")]
26 | public string Resource { get; set; }
27 | [Display(Name = "活动形式")]
28 | public string Description { get; set; }
29 |
30 | public override string ToString()
31 | {
32 | return $"名称:{Name},区域:{Area},日期:{Time?.ToString()},即时配送:{Delivery},性质:{string.Join(",", Type)},特殊资源:{Resource},活动形式:{Description}";
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/BlazAdmin/ExtensionBuilder.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin.Abstract;
2 | using Blazui.Component;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Components.Authorization;
5 | using Microsoft.AspNetCore.DataProtection;
6 | using Microsoft.AspNetCore.Identity;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Text;
12 |
13 | namespace BlazAdmin
14 | {
15 | public static class ExtensionBuilder
16 | {
17 | public static IServiceCollection AddBlazAdminCore(this IServiceCollection services)
18 | where TUserService : class, IUserService
19 | {
20 | services.AddRazorPages();
21 | services.AddServerSideBlazor();
22 | services.AddHttpClient();
23 | services.AddBlazuiServices();
24 | services.AddSingleton();
25 | services.AddScoped();
26 | return services;
27 | }
28 |
29 | //public static IApplicationBuilder UseBlazAdminCore(this IApplicationBuilder builder)
30 | //{
31 | // builder.UseMiddleware();
32 | // return builder;
33 | //}
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BlazAdmin
2 |
3 | ## 迁移
4 | 此仓库迁移至:https://github.com/wzxinchen/Blazui/tree/master/src/Admin ,并且不再更新
5 |
6 | ## 介绍
7 | 基于Blazui ([https://github.com/wzxinchen/Blazui](https://github.com/wzxinchen/Blazui)) 的后台管理模板,无JS,无TS,非 Silverlight,非 WebForm,开箱即用。
8 |
9 | ## 特性列表
10 |
11 | 1. [√] 一个标签,进行一些设置,得到一个后台管理界面
12 | 2. [√] 标签页式设计,天然模块化设计
13 | 3. [√] 集成Identity认证、用户登录
14 |
15 | ## 使用说明
16 |
17 | https://www.cnblogs.com/wzxinchen/p/12057171.html
18 |
19 | ## 关注与讨论
20 |
21 | ## 更新日志
22 |
23 | ### 版本 0.0.2.1,2020.01.03 发布
24 | https://github.com/wzxinchen/BlazAdmin/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av20200105
25 |
26 | 加入QQ群:74522853
27 |
28 | [5]: http://static.zybuluo.com/wzxinchen/gdblemd4hqpdzcq30mrmfiln/image.png
29 | [6]: http://static.zybuluo.com/wzxinchen/0hx1fjfwb83wvtsm711kxn3f/image.png
30 | [7]: http://static.zybuluo.com/wzxinchen/wofx18gqb3mogtn7m16kelgz/image.png
31 | [8]: http://static.zybuluo.com/wzxinchen/un5ci7s8ed9qqa3al2sk3egs/image.png
32 | [9]: http://static.zybuluo.com/wzxinchen/g69x0f81e009zychu6nsyhol/image.png
33 | [10]: http://static.zybuluo.com/wzxinchen/ht551s84uhx6cae92vwv0rpx/image.png
34 | [11]: http://static.zybuluo.com/wzxinchen/c5qzc8jj9e0ds06z7zct1yd9/image.png
35 | [12]: http://static.zybuluo.com/wzxinchen/r2svafomyl8t2syxv45w7jj2/image.png
36 |
--------------------------------------------------------------------------------
/src/BlazAdmin/RouteService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace BlazAdmin
8 | {
9 | internal class RouteService
10 | {
11 | private Dictionary routeMap = new Dictionary();
12 | public RouteService()
13 | {
14 | var pageTypes = AppDomain.CurrentDomain.GetAssemblies()
15 | .SelectMany(x => x.DefinedTypes)
16 | .Where(x => typeof(ComponentBase).IsAssignableFrom(x))
17 | .ToList();
18 | var pageTemplates = pageTypes.Select(x => new
19 | {
20 | Routes = x.GetCustomAttributes(typeof(RouteAttribute), true).Cast().Select(y => y.Template).ToArray(),
21 | Component = x
22 | }).ToArray();
23 | foreach (var pageTemplate in pageTemplates)
24 | {
25 | foreach (var route in pageTemplate.Routes)
26 | {
27 | routeMap.Add(route, pageTemplate.Component);
28 | }
29 | }
30 | }
31 | internal Type GetComponent(string path)
32 | {
33 | routeMap.TryGetValue(path, out var component);
34 | return component;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace BlazAdmin.Docs.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
5 |
6 |
7 |
8 |
9 |
10 | Blazui BlazAdmin 开发文档
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | @(await Html.RenderComponentAsync(RenderMode.ServerPrerendered))
19 |
20 |
21 |
22 |
23 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Menu/VerticalMenu.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 | Blazui 介绍
4 | Blazui 入门
5 |
6 | Button 按钮
7 | Input 输入框
8 | Radio 单选框
9 | Checkbox 多选框
10 | Select 选择器
11 | Switch
12 | Radio 单选框
13 | NavMenu 导航菜单
14 |
15 |
16 | Tabs 标签页
17 | Table 表格
18 | Message 消息
19 | Pagination 分页
20 | Loading 加载中
21 | MessageBox 消息弹窗
22 | Dialog 对话框
23 | DatePicker 日期选择器
24 | Form 表单
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Menu/HorizontalMenu.razor:
--------------------------------------------------------------------------------
1 |
2 | 横向最多仅支持二级菜单
3 |
4 |
5 | Blazui 介绍
6 | Blazui 入门
7 |
8 | Button 按钮
9 | Input 输入框
10 | Radio 单选框
11 | Checkbox 多选框
12 | Select 选择器
13 | Switch
14 | Radio 单选框
15 | NavMenu 导航菜单
16 |
17 |
18 | Tabs 标签页
19 | Table 表格
20 | Message 消息
21 | Pagination 分页
22 | Loading 加载中
23 | MessageBox 消息弹窗
24 | Dialog 对话框
25 | DatePicker 日期选择器
26 | Form 表单
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/BlazAdmin/ServerOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace BlazAdmin
6 | {
7 | public class ServerOptions
8 | {
9 | ///
10 | /// 服务器地址
11 | ///
12 | public string ServerUrl { get; set; } = "http://localhost:5050";
13 |
14 | ///
15 | /// 创建超级管理员的路由地址
16 | ///
17 | public string CreateSuperUserUrl { get; set; } = "/api/user/createsuperuser";
18 |
19 | ///
20 | /// 系统是否初次使用,需要初始化
21 | ///
22 | public string RequireInitilizeUrl { get; set; } = "/api/requireinitilize";
23 |
24 | ///
25 | /// 检查密码正确性的路由地址,该地址仅检查密码正确性,不做登录操作
26 | ///
27 | public string CheckPasswordUrl { get; set; } = "/api/checkpassword";
28 |
29 | ///
30 | /// 发送登录请求的地址
31 | ///
32 | public string LoginUrl { get; set; } = "/api/login";
33 |
34 | ///
35 | /// 发送登出请求的地址
36 | ///
37 | public string LogoutUrl { get; set; } = "/api/logout";
38 |
39 | ///
40 | /// 修改密码的地址
41 | ///
42 | public string ChangePasswordUrl { get; set; } = "/api/user/changepassword";
43 |
44 | ///
45 | /// 删除用户,支持批量删除
46 | ///
47 | public string DeleteUserUrl { get; set; } = "/api/user/deleteusers";
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/InitilizeFormBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Form;
2 | using Blazui.Component.Select;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.Form
10 | {
11 | public class InitilizeFormBase : ComponentBase
12 | {
13 | internal LabelAlign formAlign;
14 | [Inject]
15 | Blazui.Component.MessageBox MessageBox { get; set; }
16 |
17 | internal object value;
18 | protected BForm demoForm;
19 | protected void Submit()
20 | {
21 | if (!demoForm.IsValid())
22 | {
23 | return;
24 | }
25 |
26 | var activity = demoForm.GetValue();
27 | _ = MessageBox.AlertAsync(activity.ToString());
28 | }
29 |
30 | protected override void OnInitialized()
31 | {
32 | value = new Activity()
33 | {
34 | Area = Area.Beijing,
35 | Delivery = true,
36 | Description = "详情",
37 | Name = "测试",
38 | Resource = "场地",
39 | Time = DateTime.Now,
40 | Type = new List()
41 | {
42 | "Offline","Online"
43 | }
44 | };
45 | }
46 |
47 | protected void Reset()
48 | {
49 | demoForm.Reset();
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/BlazAdmin.ClientRender/ServerOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace BlazAdmin.ClientRender
6 | {
7 | public class ServerOptions
8 | {
9 | ///
10 | /// 服务器地址
11 | ///
12 | public string ServerUrl { get; set; } = "http://localhost:5050";
13 |
14 | ///
15 | /// 创建超级管理员的路由地址
16 | ///
17 | public string CreateSuperUserUrl { get; set; } = "/api/user/createsuperuser";
18 |
19 | ///
20 | /// 系统是否初次使用,需要初始化
21 | ///
22 | public string RequireInitilizeUrl { get; set; } = "/api/requireinitilize";
23 |
24 | ///
25 | /// 检查密码正确性的路由地址,该地址仅检查密码正确性,不做登录操作
26 | ///
27 | public string CheckPasswordUrl { get; set; } = "/api/checkpassword";
28 |
29 | ///
30 | /// 发送登录请求的地址
31 | ///
32 | public string LoginUrl { get; set; } = "/api/login";
33 |
34 | ///
35 | /// 发送登出请求的地址
36 | ///
37 | public string LogoutUrl { get; set; } = "/api/logout";
38 |
39 | ///
40 | /// 修改密码的地址
41 | ///
42 | public string ChangePasswordUrl { get; set; } = "/api/user/changepassword";
43 |
44 | ///
45 | /// 删除用户,支持批量删除
46 | ///
47 | public string DeleteUserUrl { get; set; } = "/api/user/deleteusers";
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/AutoGenerateFieldsInitilizeFormBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Form;
2 | using Blazui.Component.Select;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.Form
10 | {
11 | public class AutoGenerateFieldsInitilizeFormBase : ComponentBase
12 | {
13 | internal LabelAlign formAlign;
14 | [Inject]
15 | Blazui.Component.MessageBox MessageBox { get; set; }
16 |
17 | internal object value;
18 | protected BForm demoForm;
19 | protected void Submit()
20 | {
21 | if (!demoForm.IsValid())
22 | {
23 | return;
24 | }
25 |
26 | var activity = demoForm.GetValue();
27 | _ = MessageBox.AlertAsync(activity.ToString());
28 | }
29 |
30 | protected override void OnInitialized()
31 | {
32 | value = new Activity()
33 | {
34 | Area = Area.Beijing,
35 | Delivery = true,
36 | Description = "详情",
37 | Name = "测试",
38 | Resource = "场地",
39 | Time = DateTime.Now,
40 | Type = new List()
41 | {
42 | "Offline","Online"
43 | }
44 | };
45 | }
46 |
47 | protected void Reset()
48 | {
49 | demoForm.Reset();
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BLoginBase.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin;
2 | using Blazui.Component;
3 | using Blazui.Component.Form;
4 | using Blazui.Component.Input;
5 | using Microsoft.AspNetCore.Components;
6 | using Microsoft.AspNetCore.Identity;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Text;
10 |
11 | namespace BlazAdmin
12 | {
13 | public class BLoginBase : BAdminPageBase
14 | {
15 | public BForm Form { get; internal set; }
16 | [Parameter]
17 | public LoginInfoModel DefaultUser { get; set; }
18 |
19 | protected InputType passwordType = InputType.Password;
20 | internal void TogglePassword()
21 | {
22 | if (passwordType == InputType.Password)
23 | {
24 | passwordType = InputType.Text;
25 | }
26 | else
27 | {
28 | passwordType = InputType.Password;
29 | }
30 | }
31 |
32 | public virtual async System.Threading.Tasks.Task LoginAsync()
33 | {
34 | if (!Form.IsValid())
35 | {
36 | return;
37 | }
38 |
39 | var model = Form.GetValue();
40 | var result = await UserService.CheckPasswordAsync(model.Username, model.Password);
41 | if (string.IsNullOrWhiteSpace(result))
42 | {
43 | await UserService.LoginAsync(Form, model.Username, model.Password, NavigationManager.Uri);
44 | return;
45 | }
46 | Toast(result);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/BlazAdmin/Abstract/IUserService.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Form;
2 | using Microsoft.AspNetCore.Identity;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace BlazAdmin.Abstract
9 | {
10 | public interface IUserService
11 | {
12 | Task ChangePasswordAsync(string username, string oldPassword, string newPassword);
13 | Task CreateUserAsync(string username, string password);
14 | Task CreateRoleAsync(string roleName, string id);
15 | Task> GetUsersAsync();
16 | Task AddToRoleAsync(string username, params string[] roles);
17 | Task DeleteUsersAsync(params object[] users);
18 | ValueTask IsRequireInitilizeAsync();
19 |
20 | ///
21 | /// 仅检查密码
22 | ///
23 | ///
24 | ///
25 | ///
26 | Task CheckPasswordAsync(string username, string password);
27 | Task CreateSuperUserAsync(string username, string password);
28 | ValueTask LogoutAsync(BForm form, string callback);
29 |
30 | ///
31 | /// 检查密码,同时设置登录Cookie
32 | ///
33 | ///
34 | ///
35 | ///
36 | ValueTask LoginAsync(BForm form, string username, string password, string callback);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BCreateSuperUserBase.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin;
2 | using Blazui.Component;
3 | using Blazui.Component.Form;
4 | using Blazui.Component.Input;
5 | using Microsoft.AspNetCore.Components;
6 | using Microsoft.AspNetCore.Identity;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Transactions;
12 |
13 | namespace BlazAdmin
14 | {
15 | public class BCreateSuperUserBase : BAdminPageBase
16 | {
17 | internal BForm form;
18 | [Parameter]
19 | public LoginInfoModel DefaultUser { get; set; }
20 |
21 | protected InputType passwordType = InputType.Password;
22 | internal void TogglePassword()
23 | {
24 | if (passwordType == InputType.Password)
25 | {
26 | passwordType = InputType.Text;
27 | }
28 | else
29 | {
30 | passwordType = InputType.Password;
31 | }
32 | }
33 |
34 | public virtual async System.Threading.Tasks.Task CreateAsync()
35 | {
36 | if (!form.IsValid())
37 | {
38 | return;
39 | }
40 |
41 | var model = form.GetValue();
42 | var result = await UserService.CreateSuperUserAsync(model.Username, model.Password);
43 | if (string.IsNullOrWhiteSpace(result))
44 | {
45 | await UserService.LoginAsync(form, model.Username, model.Password, string.Empty);
46 | return;
47 | }
48 | Toast(result);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Layout.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Button 按钮
6 | Input 输入框
7 | Radio 单选框
8 | Checkbox 多选框
9 | Select 选择器
10 | Switch
11 | NavMenu 导航菜单
12 | Tabs 标签页
13 | Table 表格
14 | Message 消息
15 | Pagination 分页
16 | Loading 加载中
17 | MessageBox 消息弹窗
18 | Dialog 对话框
19 | DatePicker 日期选择器
20 | Form 表单
21 | Layout 布局面板
22 |
23 |
24 |
25 |
26 |
27 |
28 | 标签页
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Server/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Provide sufficient contrast against white background */
11 | a {
12 | color: #0366d6;
13 | }
14 |
15 | .btn-primary {
16 | color: #fff;
17 | background-color: #1b6ec2;
18 | border-color: #1861ac;
19 | }
20 |
21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
22 | color: #fff;
23 | background-color: #1b6ec2;
24 | border-color: #1861ac;
25 | }
26 |
27 | /* Sticky footer styles
28 | -------------------------------------------------- */
29 | html {
30 | font-size: 14px;
31 | }
32 | @media (min-width: 768px) {
33 | html {
34 | font-size: 16px;
35 | }
36 | }
37 |
38 | .border-top {
39 | border-top: 1px solid #e5e5e5;
40 | }
41 | .border-bottom {
42 | border-bottom: 1px solid #e5e5e5;
43 | }
44 |
45 | .box-shadow {
46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
47 | }
48 |
49 | button.accept-policy {
50 | font-size: 1rem;
51 | line-height: inherit;
52 | }
53 |
54 | /* Sticky footer styles
55 | -------------------------------------------------- */
56 | html {
57 | position: relative;
58 | min-height: 100%;
59 | }
60 |
61 | body {
62 | /* Margin bottom by footer height */
63 | margin-bottom: 60px;
64 | }
65 | .footer {
66 | position: absolute;
67 | bottom: 0;
68 | width: 100%;
69 | white-space: nowrap;
70 | line-height: 60px; /* Vertically center the text there */
71 | }
72 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/BasicButton/BasicButton.razor:
--------------------------------------------------------------------------------
1 |
2 | 默认按钮
3 | 主要按钮
4 | 成功按钮
5 | 信息按钮
6 | 警告按钮
7 | 危险按钮
8 |
9 |
10 | 朴素按钮
11 | 主要按钮
12 | 成功按钮
13 | 信息按钮
14 | 警告按钮
15 | 危险按钮
16 |
17 |
18 | 圆角按钮
19 | 主要按钮
20 | 成功按钮
21 | 信息按钮
22 | 警告按钮
23 | 危险按钮
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/NestedLayout.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 左边
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 左边
13 |
14 |
15 |
16 |
17 | 中间
18 |
19 |
20 |
21 |
22 | 右边
23 |
24 |
25 |
26 |
27 | 下边
28 |
29 |
30 |
31 |
32 | 上边
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 右边
41 |
42 |
43 |
44 |
45 | 下边
46 |
47 |
48 |
49 |
50 | 上边
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/EditableTab/BindingEditableTabBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Container;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Collections.ObjectModel;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.EditableTab
10 | {
11 | public class BindingEditableTabBase : ComponentBase
12 | {
13 | protected BTab tab;
14 | protected ObservableCollection models = new ObservableCollection()
15 | {
16 | new TabOption
17 | {
18 | Name="tab1",
19 | Title="选项卡1",
20 | Content="内容1",
21 | IsClosable=true
22 | },
23 | new TabOption
24 | {
25 | Name="tab2",
26 | Title="卡2",
27 | Content="内容2",
28 | IsClosable=true
29 | },
30 | new TabOption
31 | {
32 | Name="tab3",
33 | Title="卡3",
34 | Content="内容3",
35 | IsClosable=true
36 | },
37 | new TabOption
38 | {
39 | Name="tab4",
40 | Title="Component",
41 | Content=typeof(TestCheckBoxInTab),
42 | IsClosable=true
43 | }
44 | };
45 | protected void OnAddingTabAsync()
46 | {
47 | foreach (var item in models)
48 | {
49 | item.IsActive = false;
50 | }
51 | models.Add(new TabOption()
52 | {
53 | Content = "内容" + models.Count,
54 | IsClosable = true,
55 | Title = "标题" + models.Count,
56 | IsActive = true
57 | });
58 | tab.Refresh();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/EditableTab/EditableTabBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Container;
2 | using Microsoft.AspNetCore.Components;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Collections.ObjectModel;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.EditableTab
10 | {
11 | public class EditableTabBase : ComponentBase
12 | {
13 | protected BTab tab;
14 | protected ObservableCollection models = new ObservableCollection()
15 | {
16 | new TabOption
17 | {
18 | Name="tab1",
19 | Title="选项卡1",
20 | Content="内容1",
21 | IsClosable=true
22 | },
23 | new TabOption
24 | {
25 | Name="tab2",
26 | Title="卡2",
27 | Content="内容2",
28 | IsClosable=true
29 | },
30 | new TabOption
31 | {
32 | Name="tab3",
33 | Title="卡3",
34 | Content="内容3",
35 | IsClosable=true
36 | },
37 | new TabOption
38 | {
39 | Name="tab4",
40 | Title="Component",
41 | Content=typeof(TestCheckBoxInTab),
42 | IsClosable=true
43 | }
44 | };
45 | protected void OnAddingTabAsync()
46 | {
47 | models.Add(new TabOption()
48 | {
49 | Content = "内容" + models.Count,
50 | IsClosable = true,
51 | Title = "标题" + models.Count,
52 | IsActive = true
53 | });
54 | }
55 | protected void RemoveTabCloseAsync(BTabPanelBase tab)
56 | {
57 | models.Remove(models.FirstOrDefault(x => x.Title == tab.Title));
58 |
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Table/PaginationTableBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Blazui.Component.Table;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.Table
10 | {
11 | public class PaginationTableBase : ComponentBase
12 | {
13 | protected List AllDatas = new List();
14 |
15 | protected BTable table;
16 | protected int currentPage = 1;
17 |
18 | protected int pageSize = 5;
19 | [Inject]
20 | MessageService MessageService { get; set; }
21 |
22 | protected override void OnInitialized()
23 | {
24 | for (int i = 0; i < 1000; i++)
25 | {
26 | AllDatas.Add(new AutoGenerateColumnTestData()
27 | {
28 | Address = "地址" + i,
29 | Name = "张三" + i,
30 | Time = DateTime.Now
31 | });
32 | }
33 | }
34 |
35 | internal async Task LoadDataSource(int currentPage)
36 | {
37 | var result= new PagerResult()
38 | {
39 | Rows = AllDatas.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList(),
40 | Total = AllDatas.Count
41 | };
42 | return await Task.FromResult(result);
43 | }
44 | public void Edit(object testData)
45 | {
46 | MessageService.Show($"正在编辑 " + ((AutoGenerateColumnTestData)testData).Name);
47 | }
48 | public void Del(object testData)
49 | {
50 | MessageService.Show($"正在删除 " + ((AutoGenerateColumnTestData)testData).Name, MessageType.Warning);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/BasicForm.razor:
--------------------------------------------------------------------------------
1 | @inherits BasicFormBase
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 美食线上活动
21 | 地推活动
22 |
23 |
24 |
25 | 线上品牌赞助
26 | 线上场地免费
27 |
28 |
29 |
30 |
31 |
32 | 立即创建
33 | 重置
34 |
35 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/InitilizeForm.razor:
--------------------------------------------------------------------------------
1 | @inherits InitilizeFormBase
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 美食线上活动
21 | 地推活动
22 |
23 |
24 |
25 | 线上品牌赞助
26 | 线上场地免费
27 |
28 |
29 |
30 |
31 |
32 | 立即创建
33 | 重置
34 |
35 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Table/AutoGenerateColumnTableBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Blazui.Component.Table;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.Table
10 | {
11 | public class AutoGenerateColumnTableBase : ComponentBase
12 | {
13 | protected List Datas = new List();
14 |
15 | [Inject]
16 | MessageService MessageService { get; set; }
17 |
18 | protected override void OnInitialized()
19 | {
20 | Datas.Add(new AutoGenerateColumnTestData()
21 | {
22 | Address = "地址1",
23 | Name = "张三",
24 | Time = DateTime.Now
25 | });
26 | Datas.Add(new AutoGenerateColumnTestData()
27 | {
28 | Address = "地址2",
29 | Name = "张三1",
30 | Time = DateTime.Now
31 | });
32 | Datas.Add(new AutoGenerateColumnTestData()
33 | {
34 | Address = "地址3",
35 | Name = "张三3",
36 | Time = DateTime.Now,
37 | Yes = true
38 | });
39 | }
40 |
41 | internal async Task LoadDataSource(int currentPage)
42 | {
43 | var result= new PagerResult()
44 | {
45 | Rows = Datas,
46 | Total = Datas.Count
47 | };
48 | return await Task.FromResult(result);
49 | }
50 | public void Edit(object testData)
51 | {
52 | MessageService.Show($"正在编辑 " + ((AutoGenerateColumnTestData)testData).Name);
53 | }
54 | public void Del(object testData)
55 | {
56 | MessageService.Show($"正在删除 " + ((AutoGenerateColumnTestData)testData).Name, MessageType.Warning);
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/AutoGenerateFieldsInitilizeForm.razor:
--------------------------------------------------------------------------------
1 | @inherits AutoGenerateFieldsInitilizeFormBase
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 美食线上活动
21 | 地推活动
22 |
23 |
24 |
25 | 线上品牌赞助
26 | 线上场地免费
27 |
28 |
29 |
30 |
31 |
32 | 立即创建
33 | 重置
34 |
35 |
--------------------------------------------------------------------------------
/src/BlazAdmin/wwwroot/css/admin.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | }
4 |
5 | body app {
6 | display: flex;
7 | height: 100vh;
8 | }
9 |
10 | .blaz-layout-west .el-card {
11 | border: none;
12 | border-radius: 0;
13 | }
14 |
15 | .blaz-layout-west .el-card__header {
16 | color: rgba(255,255,255,.7);
17 | border: none;
18 | }
19 |
20 | .blaz-layout-west .el-card__body .el-menu {
21 | border: none;
22 | }
23 |
24 | .blaz-layout-center .navbar {
25 | display: flex;
26 | height: 50px;
27 | overflow: hidden;
28 | position: relative;
29 | box-shadow: 0 1px 4px rgba(0,21,41,.08);
30 | padding-left: 30px;
31 | padding-right: 30px;
32 | }
33 |
34 | .blaz-layout-center .navbar .fill {
35 | flex: 1;
36 | }
37 |
38 | .blaz-layout-center .navbar .tools, .blaz-layout-center .navbar .tools .el-breadcrumb {
39 | line-height: 50px;
40 | }
41 |
42 |
43 | .login-container {
44 | display: flex;
45 | width: 100%;
46 | height: 100%;
47 | background-color: #2d3a4b;
48 | align-items: center;
49 | }
50 |
51 | .login-container form {
52 | width: 520px;
53 | margin: 0 auto;
54 | padding: 0 35px;
55 | box-sizing: border-box;
56 | }
57 |
58 | .login-container form .el-form-item {
59 | border: 1px solid hsla(0,0%,100%,.1);
60 | background: rgba(0,0,0,.1);
61 | border-radius: 5px;
62 | color: #454545;
63 | }
64 |
65 | .login-container form .el-form-item .el-input input {
66 | background: transparent;
67 | border: 0;
68 | -webkit-appearance: none;
69 | border-radius: 0;
70 | color: #fff;
71 | padding-left: 40px;
72 | caret-color: #fff;
73 | }
74 |
75 | .login-container form .title-container .title {
76 | font-size: 26px;
77 | color: #eee;
78 | margin: 0 auto 40px auto;
79 | text-align: center;
80 | font-weight: 700;
81 | }
82 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/CheckBox/CheckBoxGroupBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.CheckBox;
2 | using Blazui.Component.EventArgs;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Collections.ObjectModel;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace BlazAdmin.Docs.Demo.CheckBox
11 | {
12 | public class CheckBoxGroupBase : ComponentBase
13 | {
14 | public Status Status { get; set; }
15 | public List Values { get; set; }
16 | public ObservableCollection SelectedValues { get; set; }
17 |
18 | protected override void OnInitialized()
19 | {
20 | Values = new List()
21 | {
22 | "列表选项1",
23 | "列表选项2",
24 | "列表选项3"
25 | };
26 | SelectedValues = new ObservableCollection()
27 | {
28 | "列表选项1",
29 | "列表选项3"
30 | };
31 | Status = Status.Indeterminate;
32 | }
33 | public void SelectAll(Status status)
34 | {
35 | Status = status;
36 | if (Status == Status.Checked)
37 | {
38 | SelectedValues = new ObservableCollection(Values);
39 | }
40 | else if (Status == Status.UnChecked)
41 | {
42 | SelectedValues = new ObservableCollection();
43 | }
44 | }
45 |
46 | public void ChangeStatus(Status status, string item)
47 | {
48 | if (status == Status.UnChecked)
49 | {
50 | SelectedValues.Remove(item);
51 | }
52 | else
53 | {
54 | SelectedValues.Add(item);
55 | }
56 |
57 | if (Values.All(SelectedValues.Contains))
58 | {
59 | Status = Status.Checked;
60 | }
61 | else if (SelectedValues.Any())
62 | {
63 | Status = Status.Indeterminate;
64 | }
65 | else
66 | {
67 | Status = Status.UnChecked;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Form/AlignForm.razor:
--------------------------------------------------------------------------------
1 | @inherits BasicFormBase
2 |
3 |
4 | 左对齐
5 | 右对齐
6 | 顶部对齐
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 美食线上活动
28 | 地推活动
29 |
30 |
31 |
32 | 线上品牌赞助
33 | 线上场地免费
34 |
35 |
36 |
37 |
38 |
39 | 立即创建
40 | 重置
41 |
42 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Components;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.HttpsPolicy;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Hosting;
12 | using Microsoft.AspNetCore.Identity;
13 | using Microsoft.EntityFrameworkCore;
14 |
15 | namespace BlazAdmin.Docs
16 | {
17 | public class Startup
18 | {
19 | public Startup(IConfiguration configuration)
20 | {
21 | Configuration = configuration;
22 | }
23 |
24 | public IConfiguration Configuration { get; }
25 |
26 | // This method gets called by the runtime. Use this method to add services to the container.
27 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
28 | public void ConfigureServices(IServiceCollection services)
29 | {
30 | services.AddDbContext(options =>
31 | {
32 | options.UseInMemoryDatabase("docs");
33 | });
34 | services.AddBlazAdmin();
35 | }
36 |
37 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
38 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
39 | {
40 | if (env.IsDevelopment())
41 | {
42 | app.UseDeveloperExceptionPage();
43 | }
44 | else
45 | {
46 | app.UseExceptionHandler("/Error");
47 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
48 | app.UseHsts();
49 | }
50 |
51 | app.UseBlazAdmin();
52 | app.UseHttpsRedirection();
53 | app.UseStaticFiles();
54 | app.UseRouting();
55 |
56 | app.UseEndpoints(endpoints =>
57 | {
58 | endpoints.MapDefaultControllerRoute();
59 | endpoints.MapBlazorHub();
60 | endpoints.MapFallbackToPage("/_Host");
61 | });
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Demo/Table/BasicTableBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Blazui.Component.Table;
3 | using Microsoft.AspNetCore.Components;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.Docs.Demo.Table
10 | {
11 | public class BasicTableBase : ComponentBase
12 | {
13 | protected int currentPage;
14 | protected List Datas = new List();
15 | protected List LargeDatas = new List();
16 |
17 | [Inject]
18 | MessageService MessageService { get; set; }
19 |
20 | protected override void OnInitialized()
21 | {
22 | Datas.Add(new TestData()
23 | {
24 | Address = "地址1",
25 | Name = "张三",
26 | Time = DateTime.Now
27 | });
28 | Datas.Add(new TestData()
29 | {
30 | Address = "地址2",
31 | Name = "张三1",
32 | Time = DateTime.Now
33 | });
34 | Datas.Add(new TestData()
35 | {
36 | Address = "地址3",
37 | Name = "张三3",
38 | Time = DateTime.Now
39 | });
40 | LargeDatas.AddRange(Datas);
41 | LargeDatas.AddRange(Datas);
42 | LargeDatas.AddRange(Datas);
43 | LargeDatas.AddRange(Datas);
44 | LargeDatas.AddRange(Datas);
45 | }
46 |
47 | internal async Task LoadDataSource1(int currentPage)
48 | {
49 | var result = new PagerResult()
50 | {
51 | Rows = Datas,
52 | Total = Datas.Count
53 | };
54 | return await Task.FromResult(result);
55 | }
56 | internal async Task LoadDataSource2(int currentPage)
57 | {
58 | var result = new PagerResult()
59 | {
60 | Rows = LargeDatas,
61 | Total = LargeDatas.Count
62 | };
63 | return await Task.FromResult(result);
64 | }
65 | public void Edit(object testData)
66 | {
67 | MessageService.Show($"正在编辑 " + ((TestData)testData).Name);
68 | }
69 | public void Del(object testData)
70 | {
71 | MessageService.Show($"正在删除 " + ((TestData)testData).Name, MessageType.Warning);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/BlazAdmin/HttpClientExtension.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin
10 | {
11 | public static class HttpClientExtension
12 | {
13 | ///
14 | /// 发送一个 Post 请求
15 | ///
16 | ///
17 | ///
18 | /// 请求地址
19 | ///
20 | ///
21 | public static async Task PostAsync(this HttpClient httpClient, string url, object requestContent)
22 | {
23 | var response = await httpClient.PostAsync(url, new StringContent(JsonConvert.SerializeObject(requestContent), Encoding.UTF8, "application/json"));
24 | return await GetContentAsync(response);
25 |
26 | }
27 |
28 | private static async Task GetContentAsync(HttpResponseMessage httpResponse)
29 | {
30 | if (httpResponse.StatusCode == System.Net.HttpStatusCode.InternalServerError)
31 | {
32 | throw new BlazuiException("服务器端发生内部错误");
33 | }
34 | if (httpResponse.StatusCode == System.Net.HttpStatusCode.BadRequest)
35 | {
36 | var content = await httpResponse.Content.ReadAsStringAsync();
37 | return content;
38 | }
39 | return string.Empty;
40 | }
41 |
42 | ///
43 | /// 发送一个 Get 请求
44 | ///
45 | ///
46 | ///
47 | /// 请求地址
48 | ///
49 | ///
50 | public static async Task GetAsync(this HttpClient httpClient, string url)
51 | {
52 | var response = await httpClient.GetAsync(url);
53 | return await GetContentAsync(response);
54 | }
55 |
56 | ///
57 | /// 发送一个 Delete 请求
58 | ///
59 | ///
60 | ///
61 | /// 请求地址
62 | ///
63 | ///
64 | public static async Task DeleteAsync(this HttpClient httpClient, string url)
65 | {
66 | var response = await httpClient.DeleteAsync(url);
67 | return await GetContentAsync(response);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/BlazAdmin.ClientRender/HttpClientExtension.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Net.Http;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace BlazAdmin.ClientRender
10 | {
11 | public static class HttpClientExtension
12 | {
13 | ///
14 | /// 发送一个 Post 请求
15 | ///
16 | ///
17 | ///
18 | /// 请求地址
19 | ///
20 | ///
21 | public static async Task PostAsync(this HttpClient httpClient, string url, object requestContent)
22 | {
23 | var response = await httpClient.PostAsync(url, new StringContent(JsonConvert.SerializeObject(requestContent), Encoding.UTF8, "application/json"));
24 | return await GetContentAsync(response);
25 |
26 | }
27 |
28 | private static async Task GetContentAsync(HttpResponseMessage httpResponse)
29 | {
30 | if (httpResponse.StatusCode == System.Net.HttpStatusCode.InternalServerError)
31 | {
32 | throw new BlazuiException("服务器端发生内部错误");
33 | }
34 | if (httpResponse.StatusCode == System.Net.HttpStatusCode.BadRequest)
35 | {
36 | var content = await httpResponse.Content.ReadAsStringAsync();
37 | return content;
38 | }
39 | return string.Empty;
40 | }
41 |
42 | ///
43 | /// 发送一个 Get 请求
44 | ///
45 | ///
46 | ///
47 | /// 请求地址
48 | ///
49 | ///
50 | public static async Task GetAsync(this HttpClient httpClient, string url)
51 | {
52 | var response = await httpClient.GetAsync(url);
53 | return await GetContentAsync(response);
54 | }
55 |
56 | ///
57 | /// 发送一个 Delete 请求
58 | ///
59 | ///
60 | ///
61 | /// 请求地址
62 | ///
63 | ///
64 | public static async Task DeleteAsync(this HttpClient httpClient, string url)
65 | {
66 | var response = await httpClient.DeleteAsync(url);
67 | return await GetContentAsync(response);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
2 |
3 | html, body {
4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
5 | }
6 |
7 | a, .btn-link {
8 | color: #0366d6;
9 | }
10 |
11 | .btn-primary {
12 | color: #fff;
13 | background-color: #1b6ec2;
14 | border-color: #1861ac;
15 | }
16 |
17 | app {
18 | position: relative;
19 | display: flex;
20 | flex-direction: column;
21 | }
22 |
23 | .top-row {
24 | height: 3.5rem;
25 | display: flex;
26 | align-items: center;
27 | }
28 |
29 | .main {
30 | flex: 1;
31 | }
32 |
33 | .main .top-row {
34 | background-color: #f7f7f7;
35 | border-bottom: 1px solid #d6d5d5;
36 | justify-content: flex-end;
37 | }
38 |
39 | .main .top-row > a {
40 | margin-left: 1.5rem;
41 | }
42 |
43 | .sidebar {
44 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
45 | }
46 |
47 | .sidebar .top-row {
48 | background-color: rgba(0,0,0,0.4);
49 | }
50 |
51 | .sidebar .navbar-brand {
52 | font-size: 1.1rem;
53 | }
54 |
55 | .sidebar .oi {
56 | width: 2rem;
57 | font-size: 1.1rem;
58 | vertical-align: text-top;
59 | top: -2px;
60 | }
61 |
62 | .nav-item {
63 | font-size: 0.9rem;
64 | padding-bottom: 0.5rem;
65 | }
66 |
67 | .nav-item:first-of-type {
68 | padding-top: 1rem;
69 | }
70 |
71 | .nav-item:last-of-type {
72 | padding-bottom: 1rem;
73 | }
74 |
75 | .nav-item a {
76 | color: #d7d7d7;
77 | border-radius: 4px;
78 | height: 3rem;
79 | display: flex;
80 | align-items: center;
81 | line-height: 3rem;
82 | }
83 |
84 | .nav-item a.active {
85 | background-color: rgba(255,255,255,0.25);
86 | color: white;
87 | }
88 |
89 | .nav-item a:hover {
90 | background-color: rgba(255,255,255,0.1);
91 | color: white;
92 | }
93 |
94 | .content {
95 | padding-top: 1.1rem;
96 | }
97 |
98 | .navbar-toggler {
99 | background-color: rgba(255, 255, 255, 0.1);
100 | }
101 |
102 | .valid.modified:not([type=checkbox]) {
103 | outline: 1px solid #26b050;
104 | }
105 |
106 | .invalid {
107 | outline: 1px solid red;
108 | }
109 |
110 | .validation-message {
111 | color: red;
112 | }
113 |
114 | @media (max-width: 767.98px) {
115 | .main .top-row {
116 | display: none;
117 | }
118 | }
119 |
120 | @media (min-width: 768px) {
121 | app {
122 | flex-direction: row;
123 | }
124 |
125 | .sidebar {
126 | width: 250px;
127 | height: 100vh;
128 | position: sticky;
129 | top: 0;
130 | }
131 |
132 | .main .top-row {
133 | position: sticky;
134 | top: 0;
135 | }
136 |
137 | .main > div {
138 | padding-left: 2rem !important;
139 | padding-right: 1.5rem !important;
140 | }
141 |
142 | .navbar-toggler {
143 | display: none;
144 | }
145 |
146 | .sidebar .collapse {
147 | /* Never collapse the sidebar for wide screens */
148 | display: block;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/BlazAdmin.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29519.87
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazAdmin.Docs", "src\BlazAdmin.Docs\BlazAdmin.Docs.csproj", "{79830AD2-3FEF-4E6A-8064-BD2320146101}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{B0C9413B-2E52-4243-A25C-FD3DC49A447A}"
9 | ProjectSection(SolutionItems) = preProject
10 | README.md = README.md
11 | EndProjectSection
12 | EndProject
13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8E11FDAD-45C7-4E56-95D6-A41FE41FDB39}"
14 | EndProject
15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{338D3C99-8FA3-46A7-8CFB-B5E60D283644}"
16 | EndProject
17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazAdmin", "src\BlazAdmin\BlazAdmin.csproj", "{52857DE9-BAC0-455B-8544-C385380621A9}"
18 | EndProject
19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazAdmin.ClientRender", "src\BlazAdmin.ClientRender\BlazAdmin.ClientRender.csproj", "{DB7A65D7-5AEB-4EE8-942A-0B088BDDC328}"
20 | EndProject
21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{2720E9D3-215A-4755-8647-17484C0ADD7B}"
22 | EndProject
23 | Global
24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 | Debug|Any CPU = Debug|Any CPU
26 | Release|Any CPU = Release|Any CPU
27 | EndGlobalSection
28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
29 | {79830AD2-3FEF-4E6A-8064-BD2320146101}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {79830AD2-3FEF-4E6A-8064-BD2320146101}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {79830AD2-3FEF-4E6A-8064-BD2320146101}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {79830AD2-3FEF-4E6A-8064-BD2320146101}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {52857DE9-BAC0-455B-8544-C385380621A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {52857DE9-BAC0-455B-8544-C385380621A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {52857DE9-BAC0-455B-8544-C385380621A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {52857DE9-BAC0-455B-8544-C385380621A9}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {DB7A65D7-5AEB-4EE8-942A-0B088BDDC328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {DB7A65D7-5AEB-4EE8-942A-0B088BDDC328}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {DB7A65D7-5AEB-4EE8-942A-0B088BDDC328}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {DB7A65D7-5AEB-4EE8-942A-0B088BDDC328}.Release|Any CPU.Build.0 = Release|Any CPU
41 | EndGlobalSection
42 | GlobalSection(SolutionProperties) = preSolution
43 | HideSolutionNode = FALSE
44 | EndGlobalSection
45 | GlobalSection(NestedProjects) = preSolution
46 | {79830AD2-3FEF-4E6A-8064-BD2320146101} = {338D3C99-8FA3-46A7-8CFB-B5E60D283644}
47 | {52857DE9-BAC0-455B-8544-C385380621A9} = {8E11FDAD-45C7-4E56-95D6-A41FE41FDB39}
48 | {DB7A65D7-5AEB-4EE8-942A-0B088BDDC328} = {8E11FDAD-45C7-4E56-95D6-A41FE41FDB39}
49 | EndGlobalSection
50 | GlobalSection(ExtensibilityGlobals) = postSolution
51 | SolutionGuid = {85E04683-718A-4B92-AF00-3696180326BE}
52 | EndGlobalSection
53 | EndGlobal
54 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/wwwroot/css/open-iconic/README.md:
--------------------------------------------------------------------------------
1 | [Open Iconic v1.1.1](http://useiconic.com/open)
2 | ===========
3 |
4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
5 |
6 |
7 |
8 | ## What's in Open Iconic?
9 |
10 | * 223 icons designed to be legible down to 8 pixels
11 | * Super-light SVG files - 61.8 for the entire set
12 | * SVG sprite—the modern replacement for icon fonts
13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
16 |
17 |
18 | ## Getting Started
19 |
20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
21 |
22 | ### General Usage
23 |
24 | #### Using Open Iconic's SVGs
25 |
26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Using Open Iconic's SVG Sprite
33 |
34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
35 |
36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.*
37 |
38 | ```
39 |
40 |
41 |
42 | ```
43 |
44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions.
45 |
46 | ```
47 | .icon {
48 | width: 16px;
49 | height: 16px;
50 | }
51 | ```
52 |
53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag.
54 |
55 | ```
56 | .icon-account-login {
57 | fill: #f00;
58 | }
59 | ```
60 |
61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
62 |
63 | #### Using Open Iconic's Icon Font...
64 |
65 |
66 | ##### …with Bootstrap
67 |
68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
69 |
70 |
71 | ```
72 |
73 | ```
74 |
75 |
76 | ```
77 |
78 | ```
79 |
80 | ##### …with Foundation
81 |
82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
83 |
84 | ```
85 |
86 | ```
87 |
88 |
89 | ```
90 |
91 | ```
92 |
93 | ##### …on its own
94 |
95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
96 |
97 | ```
98 |
99 | ```
100 |
101 | ```
102 |
103 | ```
104 |
105 |
106 | ## License
107 |
108 | ### Icons
109 |
110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
111 |
112 | ### Fonts
113 |
114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
115 |
--------------------------------------------------------------------------------
/src/BlazAdmin/BAdmin.razor:
--------------------------------------------------------------------------------
1 | @inherits BAdminBase
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | @NavigationTitle
12 |
13 |
14 |
15 | @foreach (var menu in Menus)
16 | {
17 | if (menu.Children != null && menu.Children.Any())
18 | {
19 |
20 | @foreach (var children in menu.Children)
21 | {
22 | @children.Label
23 | }
24 |
25 | }
26 | else
27 | {
28 | @menu.Label
29 | }
30 | }
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | @BreadcrumbTitle
41 | @if (CurrentMenu != null)
42 | {
43 | @(((MenuModel)CurrentMenu.Model).Title)
44 | }
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | @username
54 |
55 |
56 |
57 | 修改密码
58 | 注销登录
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/wwwroot/css/open-iconic/FONT-LICENSE:
--------------------------------------------------------------------------------
1 | SIL OPEN FONT LICENSE Version 1.1
2 |
3 | Copyright (c) 2014 Waybury
4 |
5 | PREAMBLE
6 | The goals of the Open Font License (OFL) are to stimulate worldwide
7 | development of collaborative font projects, to support the font creation
8 | efforts of academic and linguistic communities, and to provide a free and
9 | open framework in which fonts may be shared and improved in partnership
10 | with others.
11 |
12 | The OFL allows the licensed fonts to be used, studied, modified and
13 | redistributed freely as long as they are not sold by themselves. The
14 | fonts, including any derivative works, can be bundled, embedded,
15 | redistributed and/or sold with any software provided that any reserved
16 | names are not used by derivative works. The fonts and derivatives,
17 | however, cannot be released under any other type of license. The
18 | requirement for fonts to remain under this license does not apply
19 | to any document created using the fonts or their derivatives.
20 |
21 | DEFINITIONS
22 | "Font Software" refers to the set of files released by the Copyright
23 | Holder(s) under this license and clearly marked as such. This may
24 | include source files, build scripts and documentation.
25 |
26 | "Reserved Font Name" refers to any names specified as such after the
27 | copyright statement(s).
28 |
29 | "Original Version" refers to the collection of Font Software components as
30 | distributed by the Copyright Holder(s).
31 |
32 | "Modified Version" refers to any derivative made by adding to, deleting,
33 | or substituting -- in part or in whole -- any of the components of the
34 | Original Version, by changing formats or by porting the Font Software to a
35 | new environment.
36 |
37 | "Author" refers to any designer, engineer, programmer, technical
38 | writer or other person who contributed to the Font Software.
39 |
40 | PERMISSION & CONDITIONS
41 | Permission is hereby granted, free of charge, to any person obtaining
42 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
43 | redistribute, and sell modified and unmodified copies of the Font
44 | Software, subject to the following conditions:
45 |
46 | 1) Neither the Font Software nor any of its individual components,
47 | in Original or Modified Versions, may be sold by itself.
48 |
49 | 2) Original or Modified Versions of the Font Software may be bundled,
50 | redistributed and/or sold with any software, provided that each copy
51 | contains the above copyright notice and this license. These can be
52 | included either as stand-alone text files, human-readable headers or
53 | in the appropriate machine-readable metadata fields within text or
54 | binary files as long as those fields can be easily viewed by the user.
55 |
56 | 3) No Modified Version of the Font Software may use the Reserved Font
57 | Name(s) unless explicit written permission is granted by the corresponding
58 | Copyright Holder. This restriction only applies to the primary font name as
59 | presented to the users.
60 |
61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
62 | Software shall not be used to promote, endorse or advertise any
63 | Modified Version, except to acknowledge the contribution(s) of the
64 | Copyright Holder(s) and the Author(s) or with their explicit written
65 | permission.
66 |
67 | 5) The Font Software, modified or unmodified, in part or in whole,
68 | must be distributed entirely under this license, and must not be
69 | distributed under any other license. The requirement for fonts to
70 | remain under this license does not apply to any document created
71 | using the Font Software.
72 |
73 | TERMINATION
74 | This license becomes null and void if any of the above conditions are
75 | not met.
76 |
77 | DISCLAIMER
78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
86 | OTHER DEALINGS IN THE FONT SOFTWARE.
87 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Server/UserController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authentication;
2 | using Microsoft.AspNetCore.Authentication.Cookies;
3 | using Microsoft.AspNetCore.DataProtection;
4 | using Microsoft.AspNetCore.Identity;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.Extensions.Options;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Transactions;
12 |
13 | namespace BlazAdmin.Server
14 | {
15 | public class UserController : ControllerBase
16 | {
17 | private readonly IUserService userService;
18 | private readonly IOptions options;
19 |
20 | public UserController(IUserService userService, IOptions options)
21 | {
22 | this.userService = userService;
23 | this.options = options;
24 | }
25 |
26 | ///
27 | /// 判断系统是否首次使用
28 | ///
29 | ///
30 | [HttpGet]
31 | [Route("api/requireinitilize")]
32 | public async System.Threading.Tasks.Task RequireInitilizeAsync()
33 | {
34 | if (await userService.HasUserAsync())
35 | {
36 | return Ok();
37 | }
38 | return NotFound();
39 | }
40 |
41 | ///
42 | /// 判断系统是否首次使用
43 | ///
44 | ///
45 | [HttpPost]
46 | [Route("api/user/createsuperuser")]
47 | public async System.Threading.Tasks.Task CreateSuperUserAsync([FromBody]UserInfo user)
48 | {
49 | var err = await userService.CreateSuperUserAsync(user.Username, user.Password);
50 |
51 | if (string.IsNullOrWhiteSpace(err))
52 | {
53 | return Ok();
54 | }
55 | return BadRequest(err);
56 | }
57 |
58 | ///
59 | /// 执行用户登录
60 | ///
61 | ///
62 | [HttpPost]
63 | [Route("api/login")]
64 | public async System.Threading.Tasks.Task Login([FromForm]UserInfo user, [FromQuery]string callback)
65 | {
66 | var err = await userService.LoginAsync(user.Username, user.Password);
67 |
68 | //HttpContext.Response.Headers.TryGetValue("Set-Cookie", out var cookie);
69 | //if (cookie != string.Empty)
70 | //{
71 | // var value = options.Value.TicketDataFormat.Unprotect(cookie.ToString());
72 | //}
73 | if (string.IsNullOrWhiteSpace(err))
74 | {
75 | return Redirect(callback);
76 | }
77 | return BadRequest(err);
78 | }
79 |
80 | ///
81 | /// 执行用户登出
82 | ///
83 | ///
84 | [HttpPost]
85 | [Route("api/logout")]
86 | public async System.Threading.Tasks.Task Logout()
87 | {
88 | var err = await userService.LogoutAsync();
89 |
90 | if (string.IsNullOrWhiteSpace(err))
91 | {
92 | return Ok();
93 | }
94 | return BadRequest(err);
95 | }
96 |
97 | ///
98 | /// 检查用户密码是否正确,不进行登录
99 | ///
100 | ///
101 | [HttpPost]
102 | [Route("api/checkpassword")]
103 | public async System.Threading.Tasks.Task CheckPassword([FromBody]UserInfo user)
104 | {
105 | var err = await userService.CheckPasswordAsync(user.Username, user.Password);
106 |
107 | if (string.IsNullOrWhiteSpace(err))
108 | {
109 | return Ok();
110 | }
111 | return BadRequest(err);
112 | }
113 |
114 | ///
115 | /// 更换用户密码
116 | ///
117 | ///
118 | [HttpPost]
119 | [Route("api/changepassword")]
120 | public async System.Threading.Tasks.Task ChangePassword([FromBody]ChangePasswordModel user)
121 | {
122 | var err = await userService.ChangePasswordAsync(user.Username, user.OldPassword, user.NewPassword);
123 |
124 | if (string.IsNullOrWhiteSpace(err))
125 | {
126 | return Ok();
127 | }
128 | return BadRequest(err);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Shared/MainLayoutBase.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using System.Collections.Generic;
3 |
4 | namespace BlazAdmin.Docs.Shared
5 | {
6 | public class MainLayoutBase : LayoutComponentBase
7 | {
8 | protected LoginInfoModel DefaultUser { get; set; } = new LoginInfoModel()
9 | {
10 | Username = "admin",
11 | Password = "admin888"
12 | };
13 | protected List Menus { get; set; } = new List();
14 |
15 | protected override void OnInitialized()
16 | {
17 | Menus.Add(new MenuModel()
18 | {
19 | Label = "快速上手",
20 | Icon = "el-icon-s-promotion",
21 | Children = new List() {
22 | new MenuModel(){
23 | Label="Blazui 入门",
24 | Icon = "el-icon-s-promotion",
25 | Route="/guide/blazui"
26 | },
27 | new MenuModel(){
28 | Label="BlazAdmin 入门",
29 | Icon = "el-icon-s-promotion",
30 | Route="/guide/blazadmin"
31 | }
32 | }
33 | });
34 | Menus.Add(new MenuModel()
35 | {
36 | Label = "基础组件",
37 | Children = new List() {
38 | new MenuModel(){
39 | Label="Button 按钮",
40 | Route="/button",
41 | Flex=false
42 | },
43 | new MenuModel(){
44 | Label="Input 输入框",
45 | Route="/input",
46 | Flex=false
47 | },
48 | new MenuModel(){
49 | Label="Radio 单选框",
50 | Route="/radio",
51 | Flex=false
52 | },
53 | new MenuModel(){
54 | Label="Checkbox 多选框",
55 | Route="/checkbox",
56 | Flex=false
57 | },
58 | new MenuModel(){
59 | Label="Switch",
60 | Route="/switch",
61 | Flex=false
62 | },
63 | new MenuModel(){
64 | Label="Select 选择器",
65 | Route="/select",
66 | Flex=false
67 | },
68 | new MenuModel(){
69 | Label="NavMenu 导航菜单",
70 | Route="/menu",
71 | Flex=false
72 | },
73 | new MenuModel(){
74 | Label="Pagination 分页",
75 | Route="/pagination",
76 | Flex=false
77 | },
78 | new MenuModel(){
79 | Label="Tabs 标签页",
80 | Route="/tabs",
81 | Flex=false
82 | },
83 | new MenuModel(){
84 | Label="Table 表格",
85 | Route="/table",
86 | Flex=false
87 | },
88 | new MenuModel(){
89 | Label="Form 表单",
90 | Route="/form",
91 | Flex=false
92 | },
93 | new MenuModel(){
94 | Label="DatePicker 日期选择器",
95 | Route="/datepicker",
96 | Flex=false
97 | },
98 | new MenuModel(){
99 | Label="Layout 布局组件",
100 | Route="/layout",
101 | Flex=false
102 | }
103 | }
104 | });
105 | Menus.Add(new MenuModel()
106 | {
107 | Label = "弹窗组件",
108 | Children = new List() {
109 | new MenuModel(){
110 | Label="Message 消息",
111 | Route="/message",
112 | Flex=false
113 | },
114 | new MenuModel(){
115 | Label="MessageBox 消息弹窗",
116 | Route="/messagebox",
117 | Flex=false
118 | },
119 | new MenuModel(){
120 | Label="Dialog 对话框",
121 | Route="/dialog",
122 | Flex=false
123 | }
124 | }
125 | });
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/BlazAdmin.ClientRender/UserService.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin.Client.Abstract;
2 | using Blazui.Component;
3 | using Microsoft.Extensions.Options;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Net.Http;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace BlazAdmin.ClientRender
13 | {
14 | public class UserService : IUserService
15 | {
16 | private readonly HttpClient httpClient;
17 |
18 | public ServerOptions Options { get; }
19 |
20 | public UserService(IOptions options, IHttpClientFactory httpClientFactory)
21 | {
22 | this.Options = options.Value;
23 | this.httpClient = httpClientFactory.CreateClient();
24 | httpClient.BaseAddress = new Uri(Options.ServerUrl);
25 | }
26 |
27 | public Task> GetUsersAsync()
28 | {
29 | return Task.FromResult(new List());
30 | }
31 |
32 | public async Task IsRequireInitilizeAsync()
33 | {
34 | var response = await httpClient.GetAsync(Options.RequireInitilizeUrl);
35 | return response.StatusCode == System.Net.HttpStatusCode.NotFound;
36 | }
37 |
38 | public async Task CreateSuperUserAsync(string username, string password)
39 | {
40 | var response = await httpClient.PostAsync(Options.CreateSuperUserUrl, new
41 | {
42 | Username = username,
43 | Password = password
44 | });
45 | return response;
46 | }
47 |
48 | public async Task DeleteUsersAsync(params object[] users)
49 | {
50 | var ids = new List();
51 | var type = users.GetType().GetElementType();
52 | var properties = type.GetProperties();
53 | var idProperty = properties.FirstOrDefault(x => x.Name.Equals("id", StringComparison.CurrentCultureIgnoreCase));
54 | if (idProperty == null)
55 | {
56 | idProperty = properties.FirstOrDefault(x => x.Name.Equals("userid", StringComparison.CurrentCultureIgnoreCase));
57 | }
58 | if (idProperty == null)
59 | {
60 | idProperty = properties.FirstOrDefault(x => x.Name.EndsWith("id", StringComparison.CurrentCultureIgnoreCase));
61 | }
62 | if (idProperty == null)
63 | {
64 | throw new BlazuiException($"类型 {type.Name} 没有找到 id 属性,已按照如下规则查找,不区分大小写:1、id 属性,2、userid 属性,3、以 id 结尾的属性");
65 | }
66 | foreach (var user in users)
67 | {
68 | ids.Add(idProperty.GetValue(user)?.ToString());
69 | }
70 | var response = await httpClient.PostAsync(Options.DeleteUserUrl, ids);
71 | return response;
72 | }
73 |
74 | public async Task ChangePasswordAsync(string username, string oldPassword, string newPassword)
75 | {
76 | var response = await httpClient.PostAsync(Options.ChangePasswordUrl, new
77 | {
78 | Username = username,
79 | OldPassword = oldPassword,
80 | NewPasword = newPassword
81 | });
82 | return response;
83 | }
84 |
85 | public async Task CheckPasswordAsync(string username, string password)
86 | {
87 | var response = await httpClient.PostAsync(Options.CheckPasswordUrl, new
88 | {
89 | Username = username,
90 | Password = password
91 | });
92 | return response;
93 | }
94 |
95 | public Task CreateUserAsync(string username, string password)
96 | {
97 | throw new NotImplementedException();
98 | }
99 |
100 | public Task CreateRoleAsync(string roleName, string id)
101 | {
102 | throw new NotImplementedException();
103 | }
104 |
105 | public Task AddToRoleAsync(string username, params string[] roles)
106 | {
107 | throw new NotImplementedException();
108 | }
109 |
110 | public Task DeleteUserAsync(object user)
111 | {
112 | throw new NotImplementedException();
113 | }
114 |
115 | public Task LogoutAsync()
116 | {
117 | throw new NotImplementedException();
118 | }
119 |
120 | public Task LoginAsync(string username, string password)
121 | {
122 | throw new NotImplementedException();
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/Pages/PageBase.cs:
--------------------------------------------------------------------------------
1 | using Blazui.Component.Container;
2 | using Microsoft.AspNetCore.Components;
3 | using Microsoft.JSInterop;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Net.Http;
8 | using System.Threading.Tasks;
9 | using System.IO;
10 | using Newtonsoft.Json;
11 | using System.Net;
12 | using BlazAdmin.Docs.Model;
13 |
14 | namespace BlazAdmin.Docs.Pages
15 | {
16 | public class PageBase : ComponentBase
17 | {
18 | private IList Code(string name)
19 | {
20 | var location = Path.Combine(Path.GetDirectoryName(typeof(Startup).Assembly.Location), "Demo");
21 | var demoInfos = JsonConvert.DeserializeObject>(System.IO.File.ReadAllText(Path.Combine(location, "demos.json")));
22 | var demoInfo = demoInfos.SingleOrDefault(x => x.Name == name);
23 | if (demoInfo == null)
24 | {
25 | return new List();
26 | }
27 | var demos = new List();
28 | foreach (var item in demoInfo.Demos)
29 | {
30 | var razorPath = Path.Combine(location, item.Name + ".razor");
31 | var demoModel = new DemoModel()
32 | {
33 | Type = "BlazAdmin.Docs.Demo." + item.Name,
34 | Title = item.Title
35 | };
36 | if (System.IO.File.Exists(razorPath))
37 | {
38 | var code = System.IO.File.ReadAllText(razorPath);
39 | demoModel.Options.Add(new TabOption()
40 | {
41 | Content = GetCode(WebUtility.HtmlEncode(code), "razor"),
42 | Name = item.Name,
43 | Title = item.Name + ".razor",
44 | OnRenderCompletedAsync = TabCode_OnRenderCompleteAsync
45 | });
46 | demos.Add(demoModel);
47 | continue;
48 | }
49 | var codeFiles = Directory.EnumerateFiles(Path.Combine(location, item.Name))
50 | .Where(x => item.Files.Contains(Path.GetFileName(x)))
51 | .OrderBy(x => item.Files.IndexOf(Path.GetFileName(x)));
52 | demoModel.Type += "." + Path.GetFileNameWithoutExtension(codeFiles.FirstOrDefault());
53 | foreach (var codeFile in codeFiles)
54 | {
55 | var extension = codeFile.Split('.').LastOrDefault().ToLower();
56 | var language = extension;
57 | var code = System.IO.File.ReadAllText(codeFile);
58 | switch (extension)
59 | {
60 | case "razor":
61 | break;
62 | case "css":
63 | break;
64 | case "cs":
65 | language = "csharp";
66 | break;
67 | }
68 | demoModel.Options.Add(new TabOption()
69 | {
70 | Content = GetCode(WebUtility.HtmlEncode(code), language),
71 | Title = Path.GetFileName(codeFile),
72 | Name = language,
73 | OnRenderCompletedAsync = TabCode_OnRenderCompleteAsync
74 | });
75 | }
76 | demos.Add(demoModel);
77 | }
78 | return demos;
79 | }
80 | [Inject]
81 | private IHttpClientFactory httpClientFactory { get; set; }
82 | [Inject]
83 | protected IJSRuntime jSRuntime { get; set; }
84 |
85 | protected IList demos;
86 |
87 | protected string GetCode(string code, string language)
88 | {
89 | return $"{code} ";
90 | }
91 |
92 | protected string GetName(string fileName)
93 | {
94 | return fileName.Replace(".", string.Empty);
95 | }
96 |
97 | [Parameter]
98 | public string Name { get; set; }
99 | [Inject]
100 | private NavigationManager NavigationManager { get; set; }
101 | protected override void OnInitialized()
102 | {
103 | demos = Code(Name);
104 | foreach (var item in demos)
105 | {
106 | item.Demo = Type.GetType(item.Type);
107 | }
108 | }
109 |
110 | protected async Task TabCode_OnRenderCompleteAsync(object tab)
111 | {
112 | await jSRuntime.InvokeVoidAsync("renderHightlight", ((BTabPanelBase)tab).TabContainer.Content);
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/BlazAdmin/ReverseProxyMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.DataProtection;
2 | using Microsoft.AspNetCore.Http;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Net.Http;
8 | using System.Threading.Tasks;
9 |
10 | namespace BlazAdmin
11 | {
12 | public class ReverseProxyMiddleware
13 | {
14 | private static readonly HttpClient _httpClient;
15 | private readonly RequestDelegate _nextMiddleware;
16 | private static HttpClientHandler httpClientHandler;
17 |
18 | static ReverseProxyMiddleware()
19 | {
20 | httpClientHandler = new HttpClientHandler();
21 | httpClientHandler.AllowAutoRedirect = false;
22 | httpClientHandler.CookieContainer = new System.Net.CookieContainer();
23 | _httpClient = new HttpClient(httpClientHandler);
24 | }
25 | public ReverseProxyMiddleware(RequestDelegate nextMiddleware)
26 | {
27 | _nextMiddleware = nextMiddleware;
28 | }
29 | private HttpRequestMessage CreateTargetMessage(HttpContext context, Uri targetUri)
30 | {
31 | var requestMessage = new HttpRequestMessage();
32 | CopyFromOriginalRequestContentAndHeaders(context, requestMessage);
33 |
34 | requestMessage.RequestUri = targetUri;
35 | requestMessage.Method = GetMethod(context.Request.Method);
36 |
37 | return requestMessage;
38 | }
39 |
40 | private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
41 | {
42 | var requestMethod = context.Request.Method;
43 |
44 | if (!HttpMethods.IsGet(requestMethod) &&
45 | !HttpMethods.IsHead(requestMethod) &&
46 | !HttpMethods.IsDelete(requestMethod) &&
47 | !HttpMethods.IsTrace(requestMethod))
48 | {
49 | var streamContent = new StreamContent(context.Request.Body);
50 | requestMessage.Content = streamContent;
51 | }
52 |
53 | foreach (var header in context.Request.Headers)
54 | {
55 | requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
56 | }
57 | }
58 | private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
59 | {
60 | foreach (var header in responseMessage.Headers)
61 | {
62 | context.Response.Headers[header.Key] = header.Value.ToArray();
63 | }
64 |
65 | foreach (var header in responseMessage.Content.Headers)
66 | {
67 | context.Response.Headers[header.Key] = header.Value.ToArray();
68 | }
69 | var cookies = httpClientHandler.CookieContainer.GetCookies(new Uri("http://localhost:5050"));
70 | //var protector = context.RequestServices.GetDataProtector(string.Empty);
71 | //context.Response.Headers.TryGetValue("Set-Cookie", out var cookieString);
72 | //if (cookieString != string.Empty)
73 | //{
74 | //}
75 | foreach (Cookie cookie in cookies)
76 | {
77 | //protector.Unprotect(Convert.FromBase64String(cookie.Value));
78 | context.Response.Cookies.Append(cookie.Name, cookie.Value);
79 | }
80 | context.Response.Headers.Remove("transfer-encoding");
81 | }
82 | private static HttpMethod GetMethod(string method)
83 | {
84 | if (HttpMethods.IsDelete(method)) return HttpMethod.Delete;
85 | if (HttpMethods.IsGet(method)) return HttpMethod.Get;
86 | if (HttpMethods.IsHead(method)) return HttpMethod.Head;
87 | if (HttpMethods.IsOptions(method)) return HttpMethod.Options;
88 | if (HttpMethods.IsPost(method)) return HttpMethod.Post;
89 | if (HttpMethods.IsPut(method)) return HttpMethod.Put;
90 | if (HttpMethods.IsTrace(method)) return HttpMethod.Trace;
91 | return new HttpMethod(method);
92 | }
93 | public async Task Invoke(HttpContext context)
94 | {
95 | if (!context.Request.Path.StartsWithSegments("/proxy", StringComparison.CurrentCultureIgnoreCase, out var targetPath))
96 | {
97 | await _nextMiddleware(context);
98 | return;
99 | }
100 |
101 | var targetUri = "http://localhost:5050" + targetPath + context.Request.QueryString;
102 | var targetRequestMessage = CreateTargetMessage(context, new Uri(targetUri));
103 |
104 | using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
105 | {
106 | context.Response.StatusCode = (int)responseMessage.StatusCode;
107 | CopyFromTargetResponseHeaders(context, responseMessage);
108 | await responseMessage.Content.CopyToAsync(context.Response.Body);
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/BlazAdmin.ClientRender/ReverseProxyMiddleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.DataProtection;
2 | using Microsoft.AspNetCore.Http;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Net.Http;
8 | using System.Threading.Tasks;
9 |
10 | namespace BlazAdmin.Client
11 | {
12 | public class ReverseProxyMiddleware
13 | {
14 | private static readonly HttpClient _httpClient;
15 | private readonly RequestDelegate _nextMiddleware;
16 | private static HttpClientHandler httpClientHandler;
17 |
18 | static ReverseProxyMiddleware()
19 | {
20 | httpClientHandler = new HttpClientHandler();
21 | httpClientHandler.AllowAutoRedirect = false;
22 | httpClientHandler.CookieContainer = new System.Net.CookieContainer();
23 | _httpClient = new HttpClient(httpClientHandler);
24 | }
25 | public ReverseProxyMiddleware(RequestDelegate nextMiddleware)
26 | {
27 | _nextMiddleware = nextMiddleware;
28 | }
29 | private HttpRequestMessage CreateTargetMessage(HttpContext context, Uri targetUri)
30 | {
31 | var requestMessage = new HttpRequestMessage();
32 | CopyFromOriginalRequestContentAndHeaders(context, requestMessage);
33 |
34 | requestMessage.RequestUri = targetUri;
35 | requestMessage.Method = GetMethod(context.Request.Method);
36 |
37 | return requestMessage;
38 | }
39 |
40 | private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
41 | {
42 | var requestMethod = context.Request.Method;
43 |
44 | if (!HttpMethods.IsGet(requestMethod) &&
45 | !HttpMethods.IsHead(requestMethod) &&
46 | !HttpMethods.IsDelete(requestMethod) &&
47 | !HttpMethods.IsTrace(requestMethod))
48 | {
49 | var streamContent = new StreamContent(context.Request.Body);
50 | requestMessage.Content = streamContent;
51 | }
52 |
53 | foreach (var header in context.Request.Headers)
54 | {
55 | requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
56 | }
57 | }
58 | private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
59 | {
60 | foreach (var header in responseMessage.Headers)
61 | {
62 | context.Response.Headers[header.Key] = header.Value.ToArray();
63 | }
64 |
65 | foreach (var header in responseMessage.Content.Headers)
66 | {
67 | context.Response.Headers[header.Key] = header.Value.ToArray();
68 | }
69 | var cookies = httpClientHandler.CookieContainer.GetCookies(new Uri("http://localhost:5050"));
70 | //var protector = context.RequestServices.GetDataProtector(string.Empty);
71 | //context.Response.Headers.TryGetValue("Set-Cookie", out var cookieString);
72 | //if (cookieString != string.Empty)
73 | //{
74 | //}
75 | foreach (Cookie cookie in cookies)
76 | {
77 | //protector.Unprotect(Convert.FromBase64String(cookie.Value));
78 | context.Response.Cookies.Append(cookie.Name, cookie.Value);
79 | }
80 | context.Response.Headers.Remove("transfer-encoding");
81 | }
82 | private static HttpMethod GetMethod(string method)
83 | {
84 | if (HttpMethods.IsDelete(method)) return HttpMethod.Delete;
85 | if (HttpMethods.IsGet(method)) return HttpMethod.Get;
86 | if (HttpMethods.IsHead(method)) return HttpMethod.Head;
87 | if (HttpMethods.IsOptions(method)) return HttpMethod.Options;
88 | if (HttpMethods.IsPost(method)) return HttpMethod.Post;
89 | if (HttpMethods.IsPut(method)) return HttpMethod.Put;
90 | if (HttpMethods.IsTrace(method)) return HttpMethod.Trace;
91 | return new HttpMethod(method);
92 | }
93 | public async Task Invoke(HttpContext context)
94 | {
95 | if (!context.Request.Path.StartsWithSegments("/proxy", StringComparison.CurrentCultureIgnoreCase, out var targetPath))
96 | {
97 | await _nextMiddleware(context);
98 | return;
99 | }
100 |
101 | var targetUri = "http://localhost:5050" + targetPath + context.Request.QueryString;
102 | var targetRequestMessage = CreateTargetMessage(context, new Uri(targetUri));
103 |
104 | using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
105 | {
106 | context.Response.StatusCode = (int)responseMessage.StatusCode;
107 | CopyFromTargetResponseHeaders(context, responseMessage);
108 | await responseMessage.Content.CopyToAsync(context.Response.Body);
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
235 | **/wwwroot/lib/
236 |
237 | # RIA/Silverlight projects
238 | Generated_Code/
239 |
240 | # Backup & report files from converting an old project file
241 | # to a newer Visual Studio version. Backup files are not needed,
242 | # because we have git ;-)
243 | _UpgradeReport_Files/
244 | Backup*/
245 | UpgradeLog*.XML
246 | UpgradeLog*.htm
247 | ServiceFabricBackup/
248 | *.rptproj.bak
249 |
250 | # SQL Server files
251 | *.mdf
252 | *.ldf
253 | *.ndf
254 |
255 | # Business Intelligence projects
256 | *.rdl.data
257 | *.bim.layout
258 | *.bim_*.settings
259 | *.rptproj.rsuser
260 |
261 | # Microsoft Fakes
262 | FakesAssemblies/
263 |
264 | # GhostDoc plugin setting file
265 | *.GhostDoc.xml
266 |
267 | # Node.js Tools for Visual Studio
268 | .ntvs_analysis.dat
269 | node_modules/
270 |
271 | # Visual Studio 6 build log
272 | *.plg
273 |
274 | # Visual Studio 6 workspace options file
275 | *.opt
276 |
277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
278 | *.vbw
279 |
280 | # Visual Studio LightSwitch build output
281 | **/*.HTMLClient/GeneratedArtifacts
282 | **/*.DesktopClient/GeneratedArtifacts
283 | **/*.DesktopClient/ModelManifest.xml
284 | **/*.Server/GeneratedArtifacts
285 | **/*.Server/ModelManifest.xml
286 | _Pvt_Extensions
287 |
288 | # Paket dependency manager
289 | .paket/paket.exe
290 | paket-files/
291 |
292 | # FAKE - F# Make
293 | .fake/
294 |
295 | # JetBrains Rider
296 | .idea/
297 | *.sln.iml
298 |
299 | # CodeRush personal settings
300 | .cr/personal
301 |
302 | # Python Tools for Visual Studio (PTVS)
303 | __pycache__/
304 | *.pyc
305 |
306 | # Cake - Uncomment if you are using it
307 | # tools/**
308 | # !tools/packages.config
309 |
310 | # Tabs Studio
311 | *.tss
312 |
313 | # Telerik's JustMock configuration file
314 | *.jmconfig
315 |
316 | # BizTalk build output
317 | *.btp.cs
318 | *.btm.cs
319 | *.odx.cs
320 | *.xsd.cs
321 |
322 | # OpenCover UI analysis results
323 | OpenCover/
324 |
325 | # Azure Stream Analytics local run output
326 | ASALocalRun/
327 |
328 | # MSBuild Binary and Structured Log
329 | *.binlog
330 |
331 | # NVidia Nsight GPU debugger configuration file
332 | *.nvuser
333 |
334 | # MFractors (Xamarin productivity tool) working folder
335 | .mfractor/
336 |
337 | # Local History for Visual Studio
338 | .localhistory/
339 |
340 | # BeatPulse healthcheck temp database
341 | healthchecksdb
342 |
--------------------------------------------------------------------------------
/src/BlazAdmin.Docs/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'}
--------------------------------------------------------------------------------
/src/BlazAdmin/BAdminBase.cs:
--------------------------------------------------------------------------------
1 | using BlazAdmin;
2 | using Blazui.Component;
3 | using Blazui.Component.Container;
4 | using Blazui.Component.EventArgs;
5 | using Blazui.Component.Form;
6 | using Blazui.Component.NavMenu;
7 | using Microsoft.AspNetCore.Components;
8 | using Microsoft.AspNetCore.Components.Authorization;
9 | using Microsoft.AspNetCore.Identity;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Collections.ObjectModel;
13 | using System.IO;
14 | using System.Linq;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 |
18 | namespace BlazAdmin
19 | {
20 | public class BAdminBase : BAdminPageBase
21 | {
22 | internal BTabBase tab;
23 | internal BBreadcrumbBase breadcrumb;
24 | [Inject]
25 | private RouteService routeService { get; set; }
26 |
27 | protected BForm form;
28 | [Inject]
29 | private MessageService MessageService { get; set; }
30 |
31 | [Inject]
32 | private MessageBox MessageBox { get; set; }
33 |
34 | protected string defaultMenuIndex;
35 |
36 | [Parameter]
37 | public LoginInfoModel DefaultUser { get; set; }
38 |
39 | [Parameter]
40 | public bool EnablePermissionMenus { get; set; } = false;
41 | protected string username;
42 | [Parameter]
43 | public RenderFragment LoginPage { get; set; }
44 | [Parameter]
45 | public RenderFragment CreatePage { get; set; }
46 | [Parameter]
47 | public RenderFragment ModifyPasswordPage { get; set; }
48 |
49 | [Parameter]
50 | public float NavigationWidth { get; set; } = 250;
51 |
52 | ///
53 | /// 导航菜单栏标题
54 | ///
55 | [Parameter]
56 | public string NavigationTitle { get; set; } = "BlazAdmin 后台模板";
57 |
58 | ///
59 | /// 面包屑标题
60 | ///
61 | [Parameter]
62 | public string BreadcrumbTitle { get; set; } = "首页";
63 | [Parameter]
64 | public List Menus { get; set; }
65 |
66 | [Parameter]
67 | public RenderFragment ChildContent { get; set; }
68 | [Parameter]
69 | public string DefaultRoute { get; set; }
70 |
71 | internal string ActiveTabName { get; set; }
72 |
73 | [Parameter]
74 | public RenderFragment Body { get; set; }
75 |
76 | protected IMenuItem CurrentMenu { get; set; }
77 |
78 | ///
79 | /// 页面刚刚加载完成时自动加载选项卡的动作是否完成
80 | ///
81 | private bool isLoadRendered = false;
82 |
83 | internal async Task ModifyPasswordAsync()
84 | {
85 | var modifyPasswordPage = ModifyPasswordPage;
86 | if (modifyPasswordPage == null)
87 | {
88 | modifyPasswordPage = builder =>
89 | {
90 | builder.OpenComponent(0);
91 | builder.CloseComponent();
92 | };
93 | }
94 | var result = await DialogService.ShowDialogAsync(modifyPasswordPage, "修改密码", 500);
95 | if (result.Result == null)
96 | {
97 | return;
98 | }
99 |
100 | await UserService.LogoutAsync(form, NavigationManager.Uri);
101 | }
102 |
103 | internal async System.Threading.Tasks.Task LogoutAsync()
104 | {
105 | var result = await MessageBox.ConfirmAsync("是否确认注销登录?");
106 | if (result != MessageBoxResult.Ok)
107 | {
108 | return;
109 | }
110 |
111 | await UserService.LogoutAsync(form, NavigationManager.Uri);
112 | }
113 | ///
114 | /// 初始 Tab 集合
115 | ///
116 | [Parameter]
117 | public ObservableCollection Tabs { get; set; } = new ObservableCollection();
118 |
119 | protected void OnTabPanelChanging(BChangeEventArgs args)
120 | {
121 | args.DisallowChange = true;
122 | NavigationManager.NavigateTo(args.NewValue.Name);
123 | }
124 | protected override async Task OnInitializedAsync()
125 | {
126 | var path = new Uri(NavigationManager.Uri).LocalPath;
127 | if (path == "/" && !string.IsNullOrWhiteSpace(DefaultRoute))
128 | {
129 | NavigationManager.NavigateTo(DefaultRoute);
130 | return;
131 | }
132 |
133 | FixMenuInfo(Menus);
134 | var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
135 | var user = authState.User;
136 | username = user.Identity.Name;
137 | NavigationManager.LocationChanged -= NavigationManager_LocationChanged;
138 | NavigationManager.LocationChanged += NavigationManager_LocationChanged;
139 |
140 | if (EnablePermissionMenus)
141 | {
142 | var permissionMenu = new MenuModel();
143 | permissionMenu.Label = "权限管理";
144 | permissionMenu.Name = "权限管理";
145 | permissionMenu.Icon = "el-icon-lock";
146 | permissionMenu.Children.Add(new MenuModel()
147 | {
148 | Icon = "el-icon-user-solid",
149 | Label = "用户列表",
150 | Route = "/user/list",
151 | Name = "userlist",
152 | Title = "用户列表"
153 | });
154 | permissionMenu.Children.Add(new MenuModel()
155 | {
156 | Icon = "el-icon-s-custom",
157 | Label = "角色列表",
158 | Route = "/user/roles",
159 | Name = "rolelist",
160 | Title = "角色列表"
161 | });
162 | permissionMenu.Children.Add(new MenuModel()
163 | {
164 | Icon = "el-icon-s-grid",
165 | Label = "功能列表",
166 | Name = "featurelist",
167 | Route = "/user/features",
168 | Title = "功能列表"
169 | });
170 | Menus.Add(permissionMenu);
171 | }
172 | FindMenuName(Menus, path);
173 | }
174 |
175 | private void NavigationManager_LocationChanged(object sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
176 | {
177 | var path = new Uri(e.Location).LocalPath;
178 | AddTab(path);
179 | }
180 |
181 | void FindMenuName(List menus, string path)
182 | {
183 | foreach (var menu in menus)
184 | {
185 | if (menu.Route == path)
186 | {
187 | defaultMenuIndex = menu.Name;
188 | return;
189 | }
190 | FindMenuName(menu.Children, path);
191 | }
192 | }
193 |
194 | void FixMenuInfo(List menus)
195 | {
196 | foreach (var menu in menus)
197 | {
198 | menu.Name = menu.Name ?? menu.Route;
199 | menu.Title = menu.Title ?? menu.Label;
200 | FixMenuInfo(menu.Children);
201 | }
202 | }
203 |
204 | protected override void OnAfterRender(bool firstRender)
205 | {
206 | if (!isLoadRendered)
207 | {
208 | isLoadRendered = true;
209 | var path = new Uri(NavigationManager.Uri).LocalPath;
210 | AddTab(path);
211 | }
212 | }
213 |
214 | private void AddTab(string path)
215 | {
216 | var type = routeService.GetComponent(path);
217 | if (type == null)
218 | {
219 | return;
220 | }
221 | ActiveTabName = path;
222 | foreach (var item in Tabs)
223 | {
224 | item.IsActive = false;
225 | }
226 | var activeTab = Tabs.FirstOrDefault(x => x.Name == ActiveTabName);
227 | if (activeTab == null)
228 | {
229 | if (CurrentMenu == null)
230 | {
231 | return;
232 | }
233 | var model = (MenuModel)CurrentMenu.Model;
234 | Tabs.Add(new TabOption()
235 | {
236 | Title = model.Title ?? model.Label,
237 | IsClosable = true,
238 | IsActive = true,
239 | BodyStyle = model.Flex ? "display:flex;" : "display:block;",
240 | Name = ActiveTabName,
241 | Content = type
242 | });
243 | }
244 | else
245 | {
246 | activeTab.IsActive = true;
247 | }
248 | tab?.MarkAsRequireRender();
249 | tab?.Refresh();
250 | breadcrumb?.Refresh();
251 |
252 | }
253 | }
254 | }
255 |
--------------------------------------------------------------------------------