├── .github └── workflows │ └── dotnet.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_zh.md └── src ├── .template.config └── template.json └── BlazorAdmin ├── .dockerignore ├── BlazorAdmin.Modules ├── BlazorAdmin.About │ ├── BlazorAdmin.About.Client-- │ │ ├── BlazorAdmin.About.Client2.csproj │ │ ├── Pages │ │ │ ├── AboutPage.razor │ │ │ ├── AboutPage.razor.cs │ │ │ ├── TestComponent.razor │ │ │ └── TestComponent.razor.cs │ │ ├── Program.cs │ │ ├── _Imports.razor │ │ └── wwwroot │ │ │ ├── appsettings.Development.json │ │ │ └── appsettings.json │ ├── BlazorAdmin.About.Client │ │ ├── BlazorAdmin.About.Client.csproj │ │ ├── Pages │ │ │ ├── AboutPage.razor │ │ │ ├── AboutPage.razor.cs │ │ │ ├── TestComponent.razor │ │ │ └── TestComponent.razor.cs │ │ └── _Imports.razor │ └── BlazorAdmin.About.Server │ │ ├── BlazorAdmin.About.Server.csproj │ │ └── Controllers │ │ └── AboutController.cs ├── BlazorAdmin.Ai │ ├── BlazorAdmin.Ai.csproj │ ├── Pages │ │ ├── Config │ │ │ ├── Config.razor │ │ │ ├── Config.razor.cs │ │ │ └── Dialogs │ │ │ │ ├── EditConfigDialog.razor │ │ │ │ └── EditConfigDialog.razor.cs │ │ ├── Prompt │ │ │ ├── Dialogs │ │ │ │ └── PromptDialog.razor │ │ │ └── Prompt.razor │ │ └── RequestRecord │ │ │ ├── Dialogs │ │ │ ├── DetailDialog.razor │ │ │ └── DetailDialog.razor.cs │ │ │ ├── RequestRecord.razor │ │ │ └── RequestRecord.razor.cs │ ├── Resources │ │ ├── AiCulture.Designer.cs │ │ ├── AiCulture.en.resx │ │ └── AiCulture.resx │ └── _Imports.razor ├── BlazorAdmin.Clients │ ├── BlazorAdmin.Clients.Core │ │ ├── BlazorAdmin.Clients.Core.csproj │ │ └── Common │ │ │ ├── EmptyLayout.razor │ │ │ ├── EmptyLayout.razor.cs │ │ │ └── ProvidersAggregate.razor │ └── BlazorAdmin.Clients │ │ ├── BlazorAdmin.Clients.csproj │ │ ├── Program.cs │ │ └── Properties │ │ └── launchSettings.json ├── BlazorAdmin.Im │ ├── Backgrounds │ │ └── SendMessageBackgroundService.cs │ ├── BlazorAdmin.Im.csproj │ ├── Components │ │ ├── Chat.razor │ │ ├── Chat.razor.cs │ │ ├── ChatDialog.razor │ │ ├── ChatDialog.razor.cs │ │ ├── ChatDialog.razor.css │ │ ├── Messages │ │ │ ├── OtherMessage.razor │ │ │ └── SelfMessage.razor │ │ ├── UserPickerDialog.razor │ │ └── UserPickerDialog.razor.cs │ ├── Core │ │ ├── ChatHub.cs │ │ └── IChatClient.cs │ ├── Events │ │ └── UpdateNoReadCountEvent.cs │ ├── ImModule.cs │ ├── Resources │ │ ├── ImCulture.Designer.cs │ │ ├── ImCulture.en.resx │ │ └── ImCulture.resx │ ├── _Imports.razor │ └── wwwroot │ │ └── js │ │ └── scroll.js ├── BlazorAdmin.Layout │ ├── BlazorAdmin.Layout.csproj │ ├── Components │ │ ├── Culture │ │ │ └── CultureIcon.razor │ │ ├── NavMenus │ │ │ ├── NavItemMenu.razor │ │ │ ├── NavItemMenu.razor.cs │ │ │ ├── NavMenu.razor │ │ │ ├── NavMenu.razor.cs │ │ │ ├── NavMenu.razor.css │ │ │ └── NavOpenButton.razor │ │ ├── NavTabs │ │ │ ├── NavTab.razor │ │ │ └── NavTab.razor.cs │ │ ├── Notification │ │ │ ├── ActivatableContainer.razor │ │ │ └── NotificationIcon.razor │ │ ├── Themes │ │ │ ├── DarkToggleButton.razor │ │ │ ├── PrimaryChangeButton.razor │ │ │ └── ProvidersAggregate.razor │ │ └── UserAvatar │ │ │ ├── Dialogs │ │ │ ├── Com │ │ │ │ ├── AvatarEditDialog.razor │ │ │ │ ├── AvatarEditDialog.razor.cs │ │ │ │ ├── AvatarEditDialog.razor.css │ │ │ │ ├── BasicInfoConfig.razor │ │ │ │ ├── BasicInfoConfig.razor.cs │ │ │ │ ├── ChangePasswordDialog.razor │ │ │ │ └── ChangePasswordDialog.razor.cs │ │ │ └── ProfileSetting.razor │ │ │ └── UserMenuAvatar.razor │ ├── LayoutModule.cs │ ├── Resources │ │ ├── LayoutCulture.Designer.cs │ │ ├── LayoutCulture.en.resx │ │ └── LayoutCulture.resx │ ├── States │ │ └── LayoutState.cs │ ├── _Imports.razor │ └── wwwroot │ │ └── js │ │ └── drawer.js ├── BlazorAdmin.Log │ ├── BlazorAdmin.Log.csproj │ ├── Pages │ │ ├── AuditLog │ │ │ ├── AuditLog.razor │ │ │ ├── AuditLog.razor.cs │ │ │ └── Dialogs │ │ │ │ ├── AuditLogDetailDialog.razor │ │ │ │ └── AuditLogDetailDialog.razor.cs │ │ └── LoginLog │ │ │ ├── LoginLog.razor │ │ │ └── LoginLog.razor.cs │ └── _Imports.razor ├── BlazorAdmin.Metric │ ├── BlazorAdmin.Metric.csproj │ ├── Core │ │ ├── MetricData.cs │ │ └── MetricEventListener.cs │ ├── MetricModule.cs │ ├── Pages │ │ └── AppMetric.razor │ ├── Resources │ │ ├── MetricCulture.Designer.cs │ │ ├── MetricCulture.en.resx │ │ └── MetricCulture.resx │ ├── _Imports.razor │ └── wwwroot │ │ ├── background.png │ │ └── exampleJsInterop.js ├── BlazorAdmin.Rbac │ ├── BlazorAdmin.Rbac.csproj │ ├── Components │ │ ├── IconSelect.razor │ │ ├── IconSelect.razor.cs │ │ ├── IconSelect.razor.css │ │ ├── MenuTreeSelect.razor │ │ └── MenuTreeSelect.razor.cs │ ├── Pages │ │ ├── Menu │ │ │ ├── Menu.razor │ │ │ ├── Menu.razor.cs │ │ │ └── Menu.razor.css │ │ ├── Organization │ │ │ ├── Dialogs │ │ │ │ ├── MemberSelect.razor │ │ │ │ └── MemberSelect.razor.cs │ │ │ ├── Organization.razor │ │ │ └── Organization.razor.cs │ │ ├── Role │ │ │ ├── Dialogs │ │ │ │ ├── CreateRoleDialog.razor │ │ │ │ ├── CreateRoleDialog.razor.cs │ │ │ │ ├── RoleMenuDialog.razor │ │ │ │ ├── RoleMenuDialog.razor.cs │ │ │ │ ├── UpdateRoleDialog.razor │ │ │ │ └── UpdateRoleDialog.razor.cs │ │ │ ├── Role.razor │ │ │ └── Role.razor.cs │ │ └── User │ │ │ ├── Dialogs │ │ │ ├── ChangePasswordDialog.razor │ │ │ ├── ChangePasswordDialog.razor.cs │ │ │ ├── CreateUserDialog.razor │ │ │ ├── CreateUserDialog.razor.cs │ │ │ ├── UpdateUserDialog.razor │ │ │ ├── UpdateUserDialog.razor.cs │ │ │ ├── UserRoleDialog.razor │ │ │ └── UserRoleDialog.razor.cs │ │ │ ├── User.razor │ │ │ └── User.razor.cs │ ├── Resources │ │ ├── RbacCulture.Designer.cs │ │ ├── RbacCulture.en.resx │ │ └── RbacCulture.resx │ ├── _Imports.razor │ └── wwwroot │ │ └── js │ │ └── sort.js └── BlazorAdmin.Setting │ ├── BlazorAdmin.Setting.csproj │ ├── Pages │ ├── Codes │ │ └── CodeGenerator.razor │ └── Setting │ │ ├── Com │ │ ├── JwtCom.razor │ │ └── JwtCom.razor.cs │ │ ├── Dialogs │ │ ├── ConfirmUpdateRsa.razor │ │ └── ConfirmUpdateRsa.razor.cs │ │ ├── SettingPage.razor │ │ └── SettingPage.razor.cs │ ├── Resources │ ├── SettingCulture.Designer.cs │ ├── SettingCulture.en.resx │ └── SettingCulture.resx │ └── _Imports.razor ├── BlazorAdmin.Servers.Core ├── Auth │ ├── ApiAuthorizeAttribute.cs │ ├── ApiAuthorizeHandler.cs │ ├── ApiAuthorizeRequirement.cs │ ├── BlazorAuthorizationMiddlewareResultHandler.cs │ ├── JwtAuthStateProvider.cs │ ├── JwtOptionsExtension.cs │ └── UserStateExtension.cs ├── BlazorAdmin.Servers.Core.csproj ├── Chat │ ├── ChatMessageReceivedModel.cs │ ├── ChatMessageSendModel.cs │ └── MessageSender.cs ├── Components │ ├── Dialogs │ │ ├── CommonDeleteDialog.razor │ │ ├── CommonDeleteDialog.razor.cs │ │ ├── CommonDialog.cs │ │ ├── CommonDialogEventArgs.cs │ │ ├── ConfirmUserPasswordDialog.razor │ │ └── ConfirmUserPasswordDialog.razor.cs │ ├── Pages │ │ ├── PageDataGridConfig.cs │ │ ├── PageHeader.razor │ │ └── PagePagination.razor │ └── Select │ │ ├── OrganizationTreeSelect.razor │ │ └── OrganizationTreeSelect.razor.cs ├── CurrentApplication.cs ├── Data │ ├── Attributes │ │ └── IgnoreAudit.cs │ ├── BlazorAdminDbContext.cs │ ├── Constants │ │ ├── ClaimConstant.cs │ │ ├── CommonConstant.cs │ │ ├── IconsConstant.cs │ │ └── JwtConstant.cs │ ├── DatabaseExtension.cs │ ├── Entities │ │ ├── Ai │ │ │ ├── AiConfig.cs │ │ │ ├── AiPrompt.cs │ │ │ └── AiRequestRecord.cs │ │ ├── Chat │ │ │ ├── Group.cs │ │ │ ├── GroupMember.cs │ │ │ ├── GroupMessage.cs │ │ │ ├── GroupSetting.cs │ │ │ ├── NotReadedMessage.cs │ │ │ ├── PrivateMessage.cs │ │ │ └── PrivateSetting.cs │ │ ├── Log │ │ │ ├── AuditLog.cs │ │ │ ├── AuditLogDetail.cs │ │ │ └── LoginLog.cs │ │ ├── Notification │ │ │ ├── Notification.cs │ │ │ └── NotificationReceiver.cs │ │ ├── Rbac │ │ │ ├── Menu.cs │ │ │ ├── Organization.cs │ │ │ ├── OrganizationUser.cs │ │ │ ├── Role.cs │ │ │ ├── RoleMenu.cs │ │ │ ├── User.cs │ │ │ └── UserRole.cs │ │ └── Setting │ │ │ ├── Setting.cs │ │ │ └── UserSetting.cs │ ├── Extensions │ │ ├── OrganizationSetExtensions.cs │ │ └── SettingSetExtensions.cs │ └── QuartzExtension.cs ├── Dynamic │ ├── DynamicEntityAttribute.cs │ ├── DynamicEntityInfo.cs │ ├── DynamicLoader.cs │ └── DynamicPropertyAttribute.cs ├── Extension │ ├── ClaimsPrincipalExtensions.cs │ └── QueryableExtension.cs ├── Helper │ ├── AiHelper.cs │ ├── ChannelHelper.cs │ ├── EventHelper.cs │ ├── HashHelper.cs │ ├── JwtHelper.cs │ ├── NotificationHelper.cs │ ├── RandomHelper.cs │ ├── ReflectionHelper.cs │ └── SeleniumHelper.cs ├── Modules │ └── IModule.cs ├── Resources │ ├── CommonComponent.Designer.cs │ ├── CommonComponent.en.resx │ ├── CommonComponent.resx │ ├── CusCulture.Designer.cs │ ├── CusCulture.en.resx │ └── CusCulture.resx ├── Services │ ├── AccessService.cs │ ├── JobService.cs │ ├── LoopBackgroundService.cs │ └── TestJob.cs └── States │ └── ThemeState.cs ├── BlazorAdmin.Web ├── BlazorAdmin.Web.csproj ├── Components │ ├── App.razor │ ├── App.razor.cs │ ├── Layout │ │ ├── AuthorizedLayout.razor │ │ ├── AuthorizedLayout.razor.cs │ │ ├── EmptyLayout.razor │ │ ├── EmptyLayout.razor.cs │ │ ├── MainLayout.razor │ │ └── MainLayout.razor.css │ ├── Pages │ │ ├── Error.razor │ │ ├── Home.razor │ │ ├── Home.razor.cs │ │ ├── Login.razor │ │ ├── Login.razor.cs │ │ └── Login.razor.css │ ├── Routes.razor │ ├── Routes.razor.cs │ ├── Shared │ │ ├── Loading.razor │ │ ├── Loading.razor.cs │ │ ├── Loading.razor.css │ │ ├── LoggerErrorBoundary.cs │ │ ├── NoAuthorizedPage.razor │ │ ├── NoAuthorizedPage.razor.cs │ │ ├── NoAuthorizedPage.razor.css │ │ ├── NotFoundPage.razor │ │ └── NotFoundPage.razor.css │ └── _Imports.razor ├── Controllers │ └── CultureController.cs ├── Dockerfile ├── Program.cs ├── Properties │ └── launchSettings.json ├── appsettings.Development.json ├── appsettings.json └── wwwroot │ ├── app.css │ ├── favicon.png │ ├── images │ └── back.jpg │ ├── js │ ├── common.js │ └── cookieUtil.js │ └── libs │ └── Sortable.min.js └── BlazorAdmin.sln /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v3 21 | with: 22 | dotnet-version: 9.x 23 | - name: Restore dependencies 24 | run: | 25 | cd src 26 | cd BlazorAdmin 27 | dotnet restore 28 | - name: Build 29 | run: | 30 | cd src 31 | cd BlazorAdmin 32 | dotnet build --no-restore 33 | - name: Test 34 | run: | 35 | cd src 36 | cd BlazorAdmin 37 | dotnet test --no-build --verbosity normal 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 tenka 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### BlazorAdmin 2 | 3 | A simple management system template written using Blazor and MudBlazor. 4 | 5 | [中文版](README_zh.md) 6 | 7 | --- 8 | 9 | #### Features: 10 | 11 | - Support Interactive Auto Render Mode 12 | 13 | - Implemented RBAC 14 | 15 | - JWT Authentication 16 | 17 | - Built on Mudblazor 18 | 19 | - Theme light/dark and color switch 20 | 21 | - Localization 22 | 23 | - Audit/Login Log 24 | 25 | - Modularization 26 | 27 | - Quartz Support 28 | 29 | --- 30 | 31 | #### Technology stack: 32 | 33 | - .NET 9 34 | 35 | - Blazor 36 | 37 | - MudBlazor 38 | 39 | - Entity Framework Core 40 | 41 | --- 42 | 43 | #### Getting Started: 44 | 45 | ##### Run the Project: 46 | 47 | 1. Clone the repository 48 | 2. Navigate to the src/BlazorAdmin directory 49 | 3. Run `dotnet restore` to restore dependencies 50 | 4. Run `dotnet run --project BlazorAdmin.Web` to start the application 51 | 5. Open your browser and navigate to `https://localhost:37219` 52 | 53 | ##### Credentials: 54 | 55 | Username:BlazorAdmin 56 | 57 | Password:BlazorAdmin 58 | 59 | ##### Create New Project from Template: 60 | 61 | 1. Enter the folder: 62 | ```bash 63 | cd src 64 | ``` 65 | 66 | 2. Install the template: 67 | ```bash 68 | dotnet new install . 69 | ``` 70 | 71 | 3. Create a new project in other folder: 72 | ```bash 73 | dotnet new batpl -n YourProjectName 74 | ``` 75 | 76 | 4. Uninstall the template in src folder: 77 | ```bash 78 | dotnet new uninstall . 79 | ``` 80 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | ### BlazorAdmin 2 | 3 | 一个使用 Blazor 和 MudBlazor 编写的简单管理系统模板。 4 | 5 | [English](README.md) 6 | 7 | --- 8 | 9 | #### 特性: 10 | 11 | - 支持交互式自动渲染模式 12 | 13 | - 实现了基于角色的访问控制(RBAC) 14 | 15 | - JWT 身份认证 16 | 17 | - 基于 MudBlazor 构建 18 | 19 | - 主题明暗及颜色切换 20 | 21 | - 本地化支持 22 | 23 | - 审计/登录日志 24 | 25 | - 模块化设计 26 | 27 | - Quartz 支持 28 | 29 | --- 30 | 31 | #### 技术栈: 32 | 33 | - .NET 9 34 | 35 | - Blazor 36 | 37 | - MudBlazor 38 | 39 | - Entity Framework Core 40 | 41 | --- 42 | 43 | #### 快速开始: 44 | 45 | ##### 运行项目: 46 | 47 | 1. 克隆仓库 48 | 2. 进入 src/BlazorAdmin 目录 49 | 3. 运行 `dotnet restore` 恢复依赖 50 | 4. 运行 `dotnet run --project BlazorAdmin.Web` 启动应用 51 | 5. 打开浏览器访问 `https://localhost:37219` 52 | 53 | ##### 登录凭据: 54 | 55 | 用户名:BlazorAdmin 56 | 57 | 密码:BlazorAdmin 58 | 59 | ##### 从模板创建新项目: 60 | 61 | 1. 进入目录: 62 | ```bash 63 | cd src 64 | ``` 65 | 66 | 2. 安装模板: 67 | ```bash 68 | dotnet new install . 69 | ``` 70 | 71 | 3. 在其他目录创建新项目: 72 | ```bash 73 | dotnet new batpl -n 你的项目名称 74 | ``` 75 | 76 | 4. 在 src 目录卸载模板: 77 | ```bash 78 | dotnet new uninstall . 79 | ``` -------------------------------------------------------------------------------- /src/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "aishang2015", 3 | "classifications": [ "Web/WebAPI" ], 4 | "name": "BlazorAdmin", 5 | "identity": "BlazorAdminTpl", 6 | "shortName": "batpl", 7 | "tags": { 8 | "language": "C#", 9 | "type": "project" 10 | }, 11 | "sourceName": "BlazorAdmin", 12 | "preferNameDirectory": true, 13 | "sources":[ 14 | { 15 | "exclude":[ 16 | "**/[Bb]in/**", 17 | "**/[Oo]bj/**", 18 | ".template.config/**/*", 19 | "**/*.filelist", 20 | "**/*.user", 21 | "**/*.lock.json", 22 | "**/node_modules/**", 23 | ".github/**", 24 | ".git/**", 25 | "LICENSE", 26 | "README.md", 27 | "**/.vs/**", 28 | "**/.vscode/**", 29 | 30 | ] 31 | } 32 | ] 33 | 34 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/BlazorAdmin.About.Client2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | true 7 | Default 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/Pages/AboutPage.razor: -------------------------------------------------------------------------------- 1 | @page "/about" 2 | @using System.Net.Http.Headers 3 | @using Flurl 4 | @using Flurl.Http 5 | 6 | @rendermode InteractiveAuto 7 | 8 | 9 |

About

10 | 11 | Get A Number From Server 14 | Get A Number From Server Without Auth Token 17 | 18 | @code { 19 | 20 | private string _colorValue; 21 | 22 | private bool _isLoading = false; 23 | 24 | private int currentCount = 0; 25 | 26 | private async Task GetCount() 27 | { 28 | _isLoading = true; 29 | 30 | var cookieUtil = await _jsRuntime.InvokeAsync("import", "./js/cookieUtil.js"); 31 | var token = await cookieUtil.InvokeAsync("getCookie", "AccessToken"); 32 | 33 | var result = await _navManager.BaseUri 34 | .AppendPathSegment("api/about/GetRandomNumber") 35 | .WithOAuthBearerToken(token) 36 | .PostJsonAsync(new { }) 37 | .ReceiveString(); 38 | 39 | _snackbarService.Add("The Number Is " + result, Severity.Success); 40 | 41 | _isLoading = false; 42 | } 43 | 44 | private async Task GetCountWithAuthToken(){ 45 | 46 | _isLoading = true; 47 | 48 | try 49 | { 50 | var result = await _navManager.BaseUri 51 | .AppendPathSegment("api/about/GetRandomNumber") 52 | .PostJsonAsync(new { }) 53 | .ReceiveString(); 54 | 55 | _snackbarService.Add("The Number Is " + result, Severity.Success); 56 | } 57 | catch (FlurlHttpException ex) 58 | { 59 | _snackbarService.Add("Error: " + ex.Message, Severity.Error); 60 | } 61 | catch (Exception ex) 62 | { 63 | _snackbarService.Add("An unexpected error occurred: " + ex.Message, Severity.Error); 64 | } 65 | finally 66 | { 67 | _isLoading = false; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/Pages/AboutPage.razor.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.About.Client.Pages 2 | { 3 | public partial class AboutPage 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/Pages/TestComponent.razor: -------------------------------------------------------------------------------- 1 | @page "/testcomponent" 2 | 3 | @rendermode InteractiveWebAssembly 4 | @attribute [AllowAnonymous] 5 | 6 | @layout EmptyLayout 7 | 8 |

TestComponent

9 | 10 | aa 11 | 12 |
@(code)
13 |
--------------------------------------
14 |
@(code2)
15 | @code { 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 2 | using MudBlazor; 3 | using MudBlazor.Services; 4 | 5 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 6 | builder.Services.AddMudServices(config => 7 | { 8 | config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter; 9 | 10 | config.SnackbarConfiguration.PreventDuplicates = false; 11 | config.SnackbarConfiguration.NewestOnTop = false; 12 | config.SnackbarConfiguration.ShowCloseIcon = true; 13 | config.SnackbarConfiguration.VisibleStateDuration = 3000; 14 | config.SnackbarConfiguration.HideTransitionDuration = 200; 15 | config.SnackbarConfiguration.ShowTransitionDuration = 200; 16 | config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; 17 | }); 18 | await builder.Build().RunAsync(); 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Authorization 7 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 8 | @using Microsoft.AspNetCore.Components.Web.Virtualization 9 | @using Microsoft.JSInterop 10 | @using MudBlazor 11 | @using BlazorAdmin.Clients.Core.Common 12 | 13 | @inject IJSRuntime _jsRuntime; 14 | @inject ISnackbar _snackbarService; 15 | @inject NavigationManager _navManager; 16 | 17 | @attribute [Authorize] 18 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/wwwroot/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client--/wwwroot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client/BlazorAdmin.About.Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client/Pages/AboutPage.razor: -------------------------------------------------------------------------------- 1 | @page "/about" 2 | @using System.Net.Http.Headers 3 | @using Flurl 4 | @using Flurl.Http 5 | 6 | @rendermode InteractiveAuto 7 | 8 | 9 |

About

10 | 11 | Get A Number From Server 14 | Get A Number From Server Without Auth Token 17 | 18 | @code { 19 | 20 | private string _colorValue; 21 | 22 | private bool _isLoading = false; 23 | 24 | private int currentCount = 0; 25 | 26 | private async Task GetCount() 27 | { 28 | _isLoading = true; 29 | 30 | var cookieUtil = await _jsRuntime.InvokeAsync("import", "./js/cookieUtil.js"); 31 | var token = await cookieUtil.InvokeAsync("getCookie", "AccessToken"); 32 | 33 | var result = await _navManager.BaseUri 34 | .AppendPathSegment("api/about/GetRandomNumber") 35 | .WithOAuthBearerToken(token) 36 | .PostJsonAsync(new { }) 37 | .ReceiveString(); 38 | 39 | _snackbarService.Add("The Number Is " + result, Severity.Success); 40 | 41 | _isLoading = false; 42 | } 43 | 44 | private async Task GetCountWithAuthToken(){ 45 | 46 | _isLoading = true; 47 | 48 | try 49 | { 50 | var result = await _navManager.BaseUri 51 | .AppendPathSegment("api/about/GetRandomNumber") 52 | .PostJsonAsync(new { }) 53 | .ReceiveString(); 54 | 55 | _snackbarService.Add("The Number Is " + result, Severity.Success); 56 | } 57 | catch (FlurlHttpException ex) 58 | { 59 | _snackbarService.Add("Error: " + ex.Message, Severity.Error); 60 | } 61 | catch (Exception ex) 62 | { 63 | _snackbarService.Add("An unexpected error occurred: " + ex.Message, Severity.Error); 64 | } 65 | finally 66 | { 67 | _isLoading = false; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client/Pages/AboutPage.razor.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.About.Client.Pages 2 | { 3 | public partial class AboutPage 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client/Pages/TestComponent.razor: -------------------------------------------------------------------------------- 1 | @page "/testcomponent" 2 | 3 | @rendermode InteractiveWebAssembly 4 | @attribute [AllowAnonymous] 5 | 6 | @layout EmptyLayout 7 | 8 |

TestComponent

9 | 10 | aa 11 | 12 |
@(code)
13 |
--------------------------------------
14 |
@(code2)
15 | @code { 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Client/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Authorization 7 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 8 | @using Microsoft.AspNetCore.Components.Web.Virtualization 9 | @using Microsoft.JSInterop 10 | @using MudBlazor 11 | @using BlazorAdmin.Clients.Core.Common 12 | 13 | @inject IJSRuntime _jsRuntime; 14 | @inject ISnackbar _snackbarService; 15 | @inject NavigationManager _navManager; 16 | 17 | @attribute [Authorize] 18 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Server/BlazorAdmin.About.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.About/BlazorAdmin.About.Server/Controllers/AboutController.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Auth; 2 | using BlazorAdmin.Servers.Core.Data; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace BlazorAdmin.Web.Controllers 7 | { 8 | [Route("api/[controller]/[action]")] 9 | [ApiController] 10 | public class AboutController : ControllerBase 11 | { 12 | [ApiAuthorize] 13 | [HttpPost] 14 | public async Task GetRandomNumber([FromServices] IDbContextFactory _dbFactory) 15 | { 16 | using var context = await _dbFactory.CreateDbContextAsync(); 17 | return Ok(new Random(context.AuditLogs.Count()).Next(0, 9999)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/BlazorAdmin.Ai.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/Pages/Config/Dialogs/EditConfigDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Ai; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.EntityFrameworkCore; 4 | using MudBlazor; 5 | 6 | namespace BlazorAdmin.Ai.Pages.Config.Dialogs 7 | { 8 | public partial class EditConfigDialog 9 | { 10 | [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; 11 | 12 | [Parameter] public int ConfigId { get; set; } 13 | 14 | private AiConfig Config { get; set; } = new(); 15 | 16 | private MudForm form = null!; 17 | 18 | protected override async Task OnInitializedAsync() 19 | { 20 | if (ConfigId != 0) 21 | { 22 | using var context = await _dbFactory.CreateDbContextAsync(); 23 | var config = await context.AiConfigs.FindAsync(ConfigId); 24 | if (config != null) 25 | { 26 | Config = new AiConfig 27 | { 28 | Id = config.Id, 29 | ConfigName = config.ConfigName, 30 | Endpoint = config.Endpoint, 31 | ApiKey = config.ApiKey, 32 | ModelName = config.ModelName, 33 | ContextLength = config.ContextLength, 34 | InputPricePerToken = config.InputPricePerToken, 35 | OutputPricePerToken = config.OutputPricePerToken, 36 | Description = config.Description, 37 | }; 38 | } 39 | } 40 | } 41 | 42 | private async Task Submit() 43 | { 44 | await form.Validate(); 45 | if (form.IsValid) 46 | { 47 | using var context = await _dbFactory.CreateDbContextAsync(); 48 | if (ConfigId == 0) 49 | { 50 | context.AiConfigs.Add(Config); 51 | await context.SaveChangesAsync(); 52 | _snackbarService.Add(Loc["AIConfig_CreateSuccess"], Severity.Success); 53 | } 54 | else 55 | { 56 | context.Entry(Config).State = EntityState.Modified; 57 | await context.SaveChangesAsync(); 58 | _snackbarService.Add(Loc["AIConfig_EditSuccess"], Severity.Success); 59 | } 60 | MudDialog.Close(DialogResult.Ok(true)); 61 | } 62 | } 63 | 64 | private void Cancel() 65 | { 66 | MudDialog.Cancel(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/Pages/Prompt/Dialogs/PromptDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Data.Entities.Ai 2 | @using BlazorAdmin.Servers.Core.Helper 3 | @inject IStringLocalizer localizer 4 | 5 | 6 | 7 |
8 | 9 | 10 | 13 | 16 |
17 | 18 | @localizer["PromptDialog_Cancel"] 19 | @localizer["PromptDialog_Submit"] 20 |
21 |
22 |
23 |
24 |
25 | 26 | @code { 27 | [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; 28 | 29 | [Parameter] 30 | public AiPrompt Model { get; set; } = new(); 31 | 32 | private void Cancel() 33 | { 34 | MudDialog.Cancel(); 35 | } 36 | 37 | private async Task Submit() 38 | { 39 | using var context = await _dbFactory.CreateDbContextAsync(); 40 | if (Model.Id == 0) 41 | { 42 | await context.Set().AddAsync(Model); 43 | } 44 | else 45 | { 46 | context.Update(Model); 47 | } 48 | await context.SaveChangesAsync(); 49 | MudDialog.Close(DialogResult.Ok(true)); 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/Pages/RequestRecord/Dialogs/DetailDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Data.Entities.Ai 2 | @using BlazorAdmin.Servers.Core.Helper 3 | @inject IDbContextFactory _dbFactory 4 | 5 | 6 | 7 | @Loc["AIRequestRecord_RequestContent"]:
@Record?.RequestContent
8 | @Loc["AIRequestRecord_ResponseContent"]:
@Record?.ResponseContent
9 |
10 | 11 | @Loc["Button_Close"] 12 | 13 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/Pages/RequestRecord/Dialogs/DetailDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Ai; 2 | using Microsoft.AspNetCore.Components; 3 | using MudBlazor; 4 | 5 | namespace BlazorAdmin.Ai.Pages.RequestRecord.Dialogs 6 | { 7 | public partial class DetailDialog 8 | { 9 | [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; 10 | 11 | [Parameter] public int RecordId { get; set; } 12 | 13 | private AiRequestRecord? Record { get; set; } 14 | 15 | protected override async Task OnInitializedAsync() 16 | { 17 | using var context = await _dbFactory.CreateDbContextAsync(); 18 | Record = await context.AiRequestRecords.FindAsync(RecordId); 19 | } 20 | 21 | private void Cancel() 22 | { 23 | MudDialog.Close(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/Resources/AiCulture.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BlazorAdmin.Ai.Resources { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public class AiCulture { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal AiCulture() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BlazorAdmin.Ai.Resources.AiCulture", typeof(AiCulture).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Ai/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | @using BlazorAdmin.Ai.Resources 4 | 5 | @using BlazorAdmin.Servers.Core.Auth; 6 | @using BlazorAdmin.Servers.Core.Components.Pages; 7 | @using BlazorAdmin.Servers.Core.Components.Select; 8 | @using BlazorAdmin.Servers.Core.Data; 9 | @using BlazorAdmin.Servers.Core.Helper 10 | @using BlazorAdmin.Servers.Core.Resources; 11 | @using BlazorAdmin.Servers.Core.Services; 12 | @using Microsoft.AspNetCore.Authorization 13 | @using Microsoft.AspNetCore.Components.Authorization 14 | @using Microsoft.AspNetCore.Components.Forms 15 | @using Microsoft.AspNetCore.Components.Routing 16 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 17 | @using Microsoft.AspNetCore.Components.Web 18 | @using Microsoft.AspNetCore.Components.Web.Virtualization 19 | @using Microsoft.EntityFrameworkCore; 20 | @using Microsoft.Extensions.Localization; 21 | @using Microsoft.JSInterop 22 | @using MudBlazor 23 | 24 | @inject IJSRuntime _jsRuntime; 25 | @inject IDbContextFactory _dbFactory; 26 | @inject IDialogService _dialogService; 27 | @inject ISnackbar _snackbarService; 28 | @inject IAccessService _accessService; 29 | 30 | @inject JwtHelper _jwtHelper; 31 | @inject AiHelper _aiHelper; 32 | 33 | @inject AuthenticationStateProvider _stateProvider; 34 | @inject ExternalAuthService _authService; 35 | @inject ProtectedLocalStorage _localStorage; 36 | @inject NavigationManager _navManager; 37 | @inject IJobService _jobService; 38 | 39 | @inject IStringLocalizer Loc; 40 | 41 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients.Core/BlazorAdmin.Clients.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients.Core/Common/EmptyLayout.razor: -------------------------------------------------------------------------------- 1 |  2 | @inherits LayoutComponentBase 3 | 4 | 5 | 6 |
7 | @Body 8 |
9 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients.Core/Common/EmptyLayout.razor.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Clients.Core.Common 2 | { 3 | public partial class EmptyLayout 4 | { 5 | protected override async Task OnInitializedAsync() 6 | { 7 | await base.OnInitializedAsync(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients.Core/Common/ProvidersAggregate.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web 2 | @using MudBlazor 3 | 4 | @rendermode RenderMode.InteractiveWebAssembly 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients/BlazorAdmin.Clients.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | Default 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 2 | using MudBlazor; 3 | using MudBlazor.Services; 4 | 5 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 6 | builder.Services.AddMudServices(config => 7 | { 8 | config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter; 9 | 10 | config.SnackbarConfiguration.PreventDuplicates = false; 11 | config.SnackbarConfiguration.NewestOnTop = false; 12 | config.SnackbarConfiguration.ShowCloseIcon = true; 13 | config.SnackbarConfiguration.VisibleStateDuration = 3000; 14 | config.SnackbarConfiguration.HideTransitionDuration = 200; 15 | config.SnackbarConfiguration.ShowTransitionDuration = 200; 16 | config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; 17 | }); 18 | await builder.Build().RunAsync(); 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Clients/BlazorAdmin.Clients/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 9 | "applicationUrl": "http://localhost:5186", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/BlazorAdmin.Im.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | True 18 | True 19 | ImCulture.resx 20 | 21 | 22 | 23 | 24 | PublicResXFileCodeGenerator 25 | ImCulture.Designer.cs 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Components/Chat.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @implements IAsyncDisposable 3 | @rendermode InteractiveServer 4 | 5 | 6 | @if (_noReadCount > 0 && !_isDialogOpen) 7 | { 8 | 10 | 12 | 13 | 14 | } 15 | else 16 | { 17 | 19 | } 20 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Components/ChatDialog.razor.css: -------------------------------------------------------------------------------- 1 | #chat-title{ 2 | 3 | } 4 | 5 | #chat-area { 6 | width: 80vw; 7 | height: 80vh; 8 | } 9 | 10 | 11 | #channel-list { 12 | width: 300px; 13 | height: 100%; 14 | padding: 0 10px; 15 | } 16 | 17 | #message-list { 18 | flex: 1; 19 | height: 100%; 20 | } 21 | 22 | 23 | #message-area { 24 | overflow: auto; 25 | } 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Components/Messages/OtherMessage.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 |
4 | @if (string.IsNullOrEmpty(Avatar)) 5 | { 6 | 7 | @RealName?.First() 8 | 9 | } 10 | else 11 | { 12 | 13 | 14 | 15 | } 16 |
17 | 18 | @Message 19 | 20 | 21 | @SendTime 22 | 23 |
24 |
25 | 26 | @code { 27 | [Parameter] public string? Avatar { get; set; } 28 | 29 | [Parameter] public string? RealName { get; set; } 30 | 31 | [Parameter] public DateTime? SendTime { get; set; } 32 | 33 | [Parameter] public string? Message { get; set; } 34 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Components/Messages/SelfMessage.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 |
3 | @if (string.IsNullOrEmpty(Avatar)) 4 | { 5 | 6 | @RealName?.First() 7 | 8 | } 9 | else 10 | { 11 | 12 | 13 | 14 | } 15 |
16 | 17 | @Message 18 | 19 | 20 | @SendTime 21 | 22 |
23 |
24 | 25 | 26 | 27 | @code { 28 | [Parameter] public string? Avatar { get; set; } 29 | 30 | [Parameter] public string? RealName { get; set; } 31 | 32 | [Parameter] public DateTime? SendTime { get; set; } 33 | 34 | [Parameter] public string? Message { get; set; } 35 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Components/UserPickerDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 |
6 | 选择用户 7 | 8 | @if (_checkedUserSet.Count > 0) 9 | { 10 | 已选择@(_checkedUserSet.Count)个用户 11 | } 12 |
13 | 16 |
17 | 18 |
19 | 21 | @if (string.IsNullOrEmpty(context.Avatar)) 22 | { 23 | 24 | @context.RealName?.First() 25 | 26 | } 27 | else 28 | { 29 | 30 | 31 | 32 | } 33 | 34 | @context.RealName 35 | 36 |
37 |
38 |
39 | @if (_checkedUserSet.Count > 0) 40 | { 41 |
42 | 43 | 确定 44 |
45 | } 46 |
47 |
48 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Core/ChatHub.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Extension; 2 | using BlazorAdmin.Servers.Core.Helper; 3 | using Microsoft.AspNetCore.Http.Features; 4 | using Microsoft.AspNetCore.SignalR; 5 | using System.Collections.Concurrent; 6 | 7 | namespace BlazorAdmin.Im.Core 8 | { 9 | public class ChatHub : Hub 10 | { 11 | private readonly JwtHelper _jwtHelper; 12 | 13 | public static readonly string ChatHubUrl = "/blazoradmin-chat"; 14 | 15 | public static ConcurrentDictionary OnlineUsers = new ConcurrentDictionary(); 16 | 17 | public ChatHub(JwtHelper jwtHelper) 18 | { 19 | _jwtHelper = jwtHelper; 20 | } 21 | 22 | public override async Task OnConnectedAsync() 23 | { 24 | var httpContextFeature = Context.Features.FirstOrDefault(f => f.Value is IHttpRequestFeature).Value as IHttpRequestFeature; 25 | var authToken = httpContextFeature?.Headers.Authorization.ToString().Split(" ").Last(); 26 | var userPrincipal = _jwtHelper.ValidToken(authToken ?? string.Empty); 27 | 28 | if (userPrincipal == null) 29 | { 30 | throw new HubException("认证失败!拒绝连接!"); 31 | } 32 | 33 | OnlineUsers.AddOrUpdate(userPrincipal.GetUserId(), Context.ConnectionId, (key, value) => Context.ConnectionId); 34 | await base.OnConnectedAsync(); 35 | } 36 | 37 | public override async Task OnDisconnectedAsync(Exception? exception) 38 | { 39 | var httpContextFeature = Context.Features.FirstOrDefault(f => f.Value is IHttpRequestFeature).Value as IHttpRequestFeature; 40 | var authToken = httpContextFeature?.Headers.Authorization.ToString().Split(" ").Last(); 41 | var userPrincipal = _jwtHelper.ValidToken(authToken ?? string.Empty); 42 | OnlineUsers.Remove(userPrincipal.GetUserId(), out var connectionId); 43 | await base.OnDisconnectedAsync(exception); 44 | } 45 | 46 | public record OnlineUser 47 | { 48 | public string ConnectionId { get; set; } = null!; 49 | 50 | public int UserId { get; set; } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Core/IChatClient.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Chat; 2 | 3 | namespace BlazorAdmin.Im.Core 4 | { 5 | public interface IChatClient 6 | { 7 | Task ReceiveMessage(ChatMessageReceivedModel message); 8 | 9 | Task ChangeMessageCount(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/Events/UpdateNoReadCountEvent.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Im.Events 2 | { 3 | public class UpdateNoReadCountEvent 4 | { 5 | public UpdateNoCountEventType Type { get; set; } 6 | 7 | public int Count { get; set; } 8 | } 9 | 10 | public enum UpdateNoCountEventType 11 | { 12 | Add, 13 | Sub, 14 | Refresh, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/ImModule.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Im.Backgrounds; 2 | using BlazorAdmin.Im.Core; 3 | using BlazorAdmin.Im.Events; 4 | using BlazorAdmin.Servers.Core.Helper; 5 | using BlazorAdmin.Servers.Core.Modules; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.Extensions.DependencyInjection; 8 | 9 | namespace BlazorAdmin.Im 10 | { 11 | public class ImModule : IModule 12 | { 13 | public IServiceCollection Add(IServiceCollection services) 14 | { 15 | services.AddHostedService(); 16 | services.AddScoped>(); 17 | 18 | return services; 19 | } 20 | 21 | public WebApplication Use(WebApplication app) 22 | { 23 | app.MapHub(ChatHub.ChatHubUrl); 24 | return app; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | 4 | @using BlazorAdmin.Im.Events 5 | @using BlazorAdmin.Im.Resources 6 | @using BlazorAdmin.Servers.Core.Auth; 7 | @using BlazorAdmin.Servers.Core.Chat 8 | @using BlazorAdmin.Servers.Core.Components.Pages; 9 | @using BlazorAdmin.Servers.Core.Data; 10 | @using BlazorAdmin.Servers.Core.Helper 11 | @using BlazorAdmin.Servers.Core.Resources; 12 | @using BlazorAdmin.Servers.Core.Services; 13 | @using Microsoft.AspNetCore.Authorization 14 | @using Microsoft.AspNetCore.Components.Authorization 15 | @using Microsoft.AspNetCore.Components.Forms 16 | @using Microsoft.AspNetCore.Components.Routing 17 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 18 | @using Microsoft.AspNetCore.Components.Web 19 | @using Microsoft.AspNetCore.Components.Web.Virtualization 20 | @using Microsoft.EntityFrameworkCore; 21 | @using Microsoft.Extensions.Localization; 22 | @using Microsoft.JSInterop 23 | @using MudBlazor 24 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 25 | 26 | @inject IJSRuntime _jsRuntime; 27 | @inject IDbContextFactory _dbFactory; 28 | @inject IDialogService _dialogService; 29 | @inject ISnackbar _snackbarService; 30 | @inject IAccessService _accessService; 31 | 32 | @inject JwtHelper _jwtHelper; 33 | @inject AuthenticationStateProvider _stateProvider; 34 | @inject ExternalAuthService _authService; 35 | @inject ProtectedLocalStorage _localStorage; 36 | @inject NavigationManager _navManager; 37 | @inject IStringLocalizer _loc; 38 | @inject EventHelper _updateNoReadCountEventHelper; 39 | @inject MessageSender _messageSender; 40 | 41 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Im/wwwroot/js/scroll.js: -------------------------------------------------------------------------------- 1 | export function scrollToBottom() { 2 | let element = document.getElementById("message-area"); 3 | element.scrollTop = element.scrollHeight ; 4 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/BlazorAdmin.Layout.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | True 16 | True 17 | LayoutCulture.resx 18 | 19 | 20 | 21 | 22 | ResXFileCodeGenerator 23 | LayoutCulture.Designer.cs 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/Culture/CultureIcon.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | @if (IsText) 6 | { 7 | 9 | 10 | 11 | @_loc["CultureLanguage"] 12 | 13 | 14 | 15 | @Loc["AuthorizedLayout_Language_zhcn"] 16 | 17 | 18 | @Loc["AuthorizedLayout_Language_enus"] 19 | 20 | 21 | 22 | } 23 | else 24 | { 25 | 27 | 28 | @Loc["AuthorizedLayout_Language_zhcn"] 29 | 30 | 31 | @Loc["AuthorizedLayout_Language_enus"] 32 | 33 | 34 | } 35 | 36 | @code { 37 | [Parameter] public bool IsText { get; set; } = false; 38 | 39 | private void CultureChanged(string culture) 40 | { 41 | if (!string.IsNullOrEmpty(culture)) 42 | { 43 | var uri = new Uri(_navManager.Uri) 44 | .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); 45 | var cultureEscaped = Uri.EscapeDataString(culture); 46 | //var uriEscaped = Uri.EscapeDataString(uri); 47 | 48 | _navManager.NavigateTo( 49 | $"api/Culture/Set?culture={cultureEscaped}&redirectUri={uri}", 50 | forceLoad: true); 51 | } 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavItemMenu.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @foreach (var m in NavMenuItems) 4 | { 5 | if (m.Childs.Count == 0) 6 | { 7 | @_loc[m.MenuName] 9 | } 10 | else 11 | { 12 | 14 | 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavItemMenu.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace BlazorAdmin.Layout.Components.NavMenus 4 | { 5 | public partial class NavItemMenu 6 | { 7 | [Parameter] public HashSet NavMenuItems { get; set; } = new(); 8 | 9 | [Parameter] public EventCallback NavTo { get; set; } 10 | 11 | private bool _shouldRender = false; 12 | 13 | protected override bool ShouldRender() => _shouldRender; 14 | 15 | private async Task NavClick(NavMenuItem item) 16 | { 17 | await NavTo.InvokeAsync(item); 18 | } 19 | 20 | public record NavMenuItem 21 | { 22 | public string? MenuIcon { get; set; } 23 | 24 | public string? MenuName { get; set; } 25 | 26 | public string? Route { get; set; } 27 | 28 | public HashSet Childs { get; set; } = new(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavMenu.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | 6 | 7 | 8 | BlazorAdmin 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | @code { 19 | 20 | protected override void OnInitialized() 21 | { 22 | base.OnInitialized(); 23 | _layoutState.NavIsOpenEvent += () => StateHasChanged(); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavMenu.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Rbac; 2 | using static BlazorAdmin.Layout.Components.NavMenus.NavItemMenu; 3 | 4 | namespace BlazorAdmin.Layout.Components.NavMenus 5 | { 6 | public partial class NavMenu 7 | { 8 | 9 | private List MenuList = new(); 10 | 11 | public HashSet NavMenuItems { get; set; } = new(); 12 | 13 | protected override async Task OnInitializedAsync() 14 | { 15 | using var context = await _dbFactory.CreateDbContextAsync(); 16 | MenuList = context.Menus.Where(m => m.Type == 1).ToList(); 17 | 18 | var canAccessedMenus = await _accessService.GetCanAccessedMenus(); 19 | MenuList = MenuList.Where(m => canAccessedMenus.Contains(m.Id)).ToList(); 20 | 21 | NavMenuItems = AppendMenuItems(null, MenuList); 22 | } 23 | 24 | private HashSet AppendMenuItems(int? parentId, List menus) 25 | { 26 | return menus.Where(m => m.ParentId == parentId).OrderBy(m => m.Order) 27 | .Select(m => new NavMenuItem 28 | { 29 | MenuIcon = m.Icon, 30 | MenuName = m.Name, 31 | Route = m.Route, 32 | Childs = AppendMenuItems(m.Id, menus) 33 | }).ToHashSet(); 34 | } 35 | 36 | private void NavTo(NavMenuItem item) 37 | { 38 | _layoutState.NavTo(item); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | background-color: rgba(255, 255, 255, 0.1); 3 | } 4 | 5 | .top-row { 6 | height: 3.5rem; 7 | background-color: rgba(0,0,0,0.4); 8 | } 9 | 10 | .navbar-brand { 11 | font-size: 1.1rem; 12 | } 13 | 14 | .oi { 15 | width: 2rem; 16 | font-size: 1.1rem; 17 | vertical-align: text-top; 18 | top: -2px; 19 | } 20 | 21 | .nav-item { 22 | font-size: 0.9rem; 23 | padding-bottom: 0.5rem; 24 | } 25 | 26 | .nav-item:first-of-type { 27 | padding-top: 1rem; 28 | } 29 | 30 | .nav-item:last-of-type { 31 | padding-bottom: 1rem; 32 | } 33 | 34 | .nav-item ::deep a { 35 | color: #d7d7d7; 36 | border-radius: 4px; 37 | height: 3rem; 38 | display: flex; 39 | align-items: center; 40 | line-height: 3rem; 41 | } 42 | 43 | .nav-item ::deep a.active { 44 | background-color: rgba(255,255,255,0.25); 45 | color: white; 46 | } 47 | 48 | .nav-item ::deep a:hover { 49 | background-color: rgba(255,255,255,0.1); 50 | color: white; 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .navbar-toggler { 55 | display: none; 56 | } 57 | 58 | .collapse { 59 | /* Never collapse the sidebar for wide screens */ 60 | display: block; 61 | } 62 | 63 | .nav-scrollable { 64 | /* Allow sidebar to scroll for tall menus */ 65 | height: calc(100vh - 3.5rem); 66 | overflow-y: auto; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavMenus/NavOpenButton.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | 6 | 7 | 8 | @code { 9 | 10 | async Task DrawerToggle() 11 | { 12 | _layoutState.NavIsOpen = !_layoutState.NavIsOpen; 13 | 14 | var drawerModule = await _jsRuntime.InvokeAsync 15 | ("import", "./_content/BlazorAdmin.Layout/js/drawer.js"); 16 | await drawerModule.InvokeVoidAsync("handleDrawerToggled", _layoutState.NavIsOpen); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/NavTabs/NavTab.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | 9 | @foreach (var tab in _userTabs) 10 | { 11 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/Notification/ActivatableContainer.razor: -------------------------------------------------------------------------------- 1 | @using MudBlazor.Interfaces 2 | @namespace MudBlazor 3 | @implements IActivatable 4 | 5 | 6 | @ChildContent 7 | 8 | 9 | @code { 10 | /// 11 | /// The content to render 12 | /// 13 | [Parameter] 14 | public RenderFragment ChildContent { get; set; } 15 | 16 | public void Activate(object activator, MouseEventArgs args) 17 | { 18 | // NOOP 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/Themes/DarkToggleButton.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/Themes/ProvidersAggregate.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 | 6 | 7 | 8 | 9 | 10 | @code { 11 | protected override void OnInitialized() 12 | { 13 | _themeState.IsDarkChangeEvent += StateHasChanged; 14 | _themeState.ThemeChangeEvent += StateHasChanged; 15 | } 16 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/UserAvatar/Dialogs/Com/AvatarEditDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @using Cropper.Blazor.Components; 4 | 5 | 6 |
7 |
8 | 11 |
12 |
13 |
14 | 保存头像 16 |
17 |
18 | 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/UserAvatar/Dialogs/Com/AvatarEditDialog.razor.css: -------------------------------------------------------------------------------- 1 | .img-container { 2 | height: 400px; 3 | width: 600px; 4 | } 5 | 6 | .cropper-img { 7 | width: 400px; 8 | height: 400px; 9 | } 10 | 11 | .previewed-image { 12 | width: 100px; 13 | height: 100px; 14 | overflow: hidden; 15 | border-radius: 50px; 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/UserAvatar/Dialogs/Com/ChangePasswordDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | 4 | 5 |
6 | 修改密码 7 | 8 | 9 | 11 | 13 |
14 | 15 | 提交 17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/UserAvatar/Dialogs/Com/ChangePasswordDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Auth; 2 | using BlazorAdmin.Servers.Core.Helper; 3 | using Microsoft.AspNetCore.Components; 4 | using MudBlazor; 5 | using System.ComponentModel.DataAnnotations; 6 | 7 | namespace BlazorAdmin.Layout.Components.UserAvatar.Dialogs.Com 8 | { 9 | public partial class ChangePasswordDialog 10 | { 11 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 12 | 13 | private PasswordChangeModel PasswordModel = new(); 14 | 15 | private async Task Submit() 16 | { 17 | using var context = _dbFactory.CreateDbContext(); 18 | var userId = await _stateProvider.GetUserIdAsync(); 19 | var user = context.Users.Find(userId); 20 | if (user != null) 21 | { 22 | user.PasswordHash = HashHelper.HashPassword(PasswordModel.Password!); 23 | await context.SaveChangesAsync(); 24 | _snackbarService.Add("密码修改成功!", Severity.Success); 25 | MudDialog?.Close(DialogResult.Ok(true)); 26 | } 27 | else 28 | { 29 | _snackbarService.Add("用户信息不存在!", Severity.Error); 30 | } 31 | } 32 | 33 | private record PasswordChangeModel 34 | { 35 | [Required(ErrorMessage = "请输入密码")] 36 | [MinLength(4, ErrorMessage = "密码位数过短")] 37 | [MaxLength(100, ErrorMessage = "密码位数过长")] 38 | [RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", ErrorMessage = "密码中必须包含大小写字母以及数字")] 39 | public string? Password { get; set; } 40 | 41 | [Compare(nameof(Password), ErrorMessage = "两次输入的密码不一致")] 42 | public string? ConfirmPassword { get; set; } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/Components/UserAvatar/Dialogs/ProfileSetting.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Layout.Components.UserAvatar.Dialogs.Com 2 | @using BlazorAdmin.Servers.Core.Helper 3 | @using BlazorAdmin.Servers.Core.States 4 | 5 | 6 | 7 | 8 |
9 | 账号设置 10 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/LayoutModule.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Layout.States; 2 | using BlazorAdmin.Servers.Core.Modules; 3 | using BlazorAdmin.Servers.Core.States; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace BlazorAdmin.Layout 7 | { 8 | public class LayoutModule : IModule 9 | { 10 | public IServiceCollection Add(IServiceCollection services) 11 | { 12 | services.AddScoped(); 13 | services.AddScoped(); 14 | return services; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/States/LayoutState.cs: -------------------------------------------------------------------------------- 1 | using static BlazorAdmin.Layout.Components.NavMenus.NavItemMenu; 2 | 3 | namespace BlazorAdmin.Layout.States 4 | { 5 | public class LayoutState 6 | { 7 | private bool _navIsOpen = true; 8 | 9 | public event Action? NavIsOpenEvent; 10 | 11 | public bool NavIsOpen 12 | { 13 | get => _navIsOpen; 14 | set 15 | { 16 | _navIsOpen = value; 17 | NavIsOpenEvent?.Invoke(); 18 | } 19 | } 20 | 21 | 22 | public event Action? NavToEvent; 23 | 24 | public void NavTo(NavMenuItem item) => NavToEvent?.Invoke(item); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using BlazorAdmin.Layout.Resources 4 | @using BlazorAdmin.Layout.States 5 | @using BlazorAdmin.Servers.Core.Auth 6 | @using BlazorAdmin.Servers.Core.Chat 7 | @using BlazorAdmin.Servers.Core.Components.Pages; 8 | @using BlazorAdmin.Servers.Core.Data 9 | @using BlazorAdmin.Servers.Core.Data.Constants 10 | @using BlazorAdmin.Servers.Core.Extension 11 | @using BlazorAdmin.Servers.Core.Helper 12 | @using BlazorAdmin.Servers.Core.Resources 13 | @using BlazorAdmin.Servers.Core.Services 14 | @using BlazorAdmin.Servers.Core.States 15 | @using Microsoft.AspNetCore.Authorization 16 | @using Microsoft.AspNetCore.Components.Authorization 17 | @using Microsoft.AspNetCore.Components.Forms 18 | @using Microsoft.AspNetCore.Components.Routing 19 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage 20 | @using Microsoft.AspNetCore.Components.Web 21 | @using Microsoft.AspNetCore.Components.Web.Virtualization 22 | @using Microsoft.EntityFrameworkCore 23 | @using Microsoft.Extensions.Localization 24 | @using Microsoft.JSInterop 25 | @using MudBlazor 26 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 27 | 28 | @inject IJSRuntime _jsRuntime; 29 | @inject IDbContextFactory _dbFactory; 30 | @inject IDialogService _dialogService; 31 | @inject ISnackbar _snackbarService; 32 | @inject IAccessService _accessService; 33 | 34 | @inject ProtectedLocalStorage _localStorage; 35 | @inject NavigationManager _navManager; 36 | @inject AuthenticationStateProvider _stateProvider; 37 | @inject IStringLocalizer Loc; 38 | 39 | @inject JwtHelper _jwtHelper; 40 | @inject NotificationHelper _notificationHelper; 41 | @inject ExternalAuthService _authService; 42 | @inject ThemeState _themeState; 43 | @inject MessageSender _messageSender; 44 | @inject LayoutState _layoutState; 45 | @inject IStringLocalizer _loc; 46 | 47 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Layout/wwwroot/js/drawer.js: -------------------------------------------------------------------------------- 1 | export function handleDrawerToggled(isOpen) { 2 | const layoutElement = document.querySelector(".mud-layout"); 3 | if (isOpen) { 4 | layoutElement.classList.replace("mud-drawer-close-responsive-md-left", "mud-drawer-open-responsive-md-left"); 5 | } else { 6 | layoutElement.classList.replace("mud-drawer-open-responsive-md-left", "mud-drawer-close-responsive-md-left"); 7 | } 8 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Log/BlazorAdmin.Log.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | true 18 | 19 | 20 | true 21 | 22 | 23 | true 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Log/Pages/AuditLog/Dialogs/AuditLogDetailDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Data.Constants 2 | @using BlazorAdmin.Servers.Core.Helper 3 | 4 | 5 | 6 |
7 |
8 | 9 | 字段详情 10 |
11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | @Loc["AuditLogDetailDialog_TableH1"] 21 | @Loc["AuditLogDetailDialog_TableH2"] 22 | @Loc["AuditLogDetailDialog_TableH3"] 23 | @Loc["AuditLogDetailDialog_TableH4"] 24 | 25 | 26 | @context.Number 27 | @context.PropertyName 28 | @context.OldValue 29 | @context.NewValue 30 | 31 | 32 |
33 |
34 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Log/Pages/AuditLog/Dialogs/AuditLogDetailDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using MudBlazor; 6 | 7 | namespace BlazorAdmin.Log.Pages.AuditLog.Dialogs 8 | { 9 | public partial class AuditLogDetailDialog 10 | { 11 | [Parameter] public Guid AuditLogId { get; set; } 12 | 13 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 14 | 15 | private List AuditLogDetails { get; set; } = new(); 16 | 17 | protected override async Task OnInitializedAsync() 18 | { 19 | await base.OnInitializedAsync(); 20 | await InitialAsync(); 21 | } 22 | 23 | private async Task InitialAsync() 24 | { 25 | using var context = await _dbFactory.CreateDbContextAsync(); 26 | AuditLogDetails = context.AuditLogDetails.Where(d => d.AuditLogId == AuditLogId) 27 | .Select(d => new AuditLogDetailModel 28 | { 29 | Id = d.Id, 30 | EntityName = d.EntityName, 31 | PropertyName = d.PropertyName, 32 | OldValue = d.OldValue, 33 | NewValue = d.NewValue, 34 | }).ToList(); 35 | 36 | if (AuditLogDetails.Count > 0) 37 | { 38 | var model = context.GetService().Model 39 | .FindEntityType(AuditLogDetails.First().EntityName); 40 | AuditLogDetails.ForEach(d => 41 | { 42 | d.Number = AuditLogDetails.IndexOf(d) + 1; 43 | d.EntityName = model!.GetComment()!; 44 | d.PropertyName = model!.FindDeclaredProperty(d.PropertyName)!.GetComment()!; 45 | }); 46 | } 47 | } 48 | 49 | private class AuditLogDetailModel 50 | { 51 | public int Id { get; set; } 52 | public int Number { get; set; } 53 | public string EntityName { get; set; } = null!; 54 | public string PropertyName { get; set; } = null!; 55 | public string? OldValue { get; set; } 56 | public string? NewValue { get; set; } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Log/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | 4 | @using BlazorAdmin.Servers.Core.Auth; 5 | @using BlazorAdmin.Servers.Core.Components.Pages; 6 | @using BlazorAdmin.Servers.Core.Data; 7 | @using BlazorAdmin.Servers.Core.Helper 8 | @using BlazorAdmin.Servers.Core.Resources; 9 | @using BlazorAdmin.Servers.Core.Services; 10 | @using Microsoft.AspNetCore.Authorization 11 | @using Microsoft.AspNetCore.Components.Authorization 12 | @using Microsoft.AspNetCore.Components.Forms 13 | @using Microsoft.AspNetCore.Components.Routing 14 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 15 | @using Microsoft.AspNetCore.Components.Web 16 | @using Microsoft.AspNetCore.Components.Web.Virtualization 17 | @using Microsoft.EntityFrameworkCore; 18 | @using Microsoft.Extensions.Localization; 19 | @using Microsoft.JSInterop 20 | @using MudBlazor 21 | 22 | @inject IJSRuntime _jsRuntime; 23 | @inject IDbContextFactory _dbFactory; 24 | @inject IDialogService _dialogService; 25 | @inject ISnackbar _snackbarService; 26 | @inject IAccessService _accessService; 27 | 28 | @inject JwtHelper _jwtHelper; 29 | @inject AuthenticationStateProvider _stateProvider; 30 | @inject ExternalAuthService _authService; 31 | @inject ProtectedLocalStorage _localStorage; 32 | @inject NavigationManager _navManager; 33 | @inject IStringLocalizer Loc; 34 | 35 | 36 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/BlazorAdmin.Metric.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | True 16 | True 17 | MetricCulture.resx 18 | 19 | 20 | 21 | 22 | ResXFileCodeGenerator 23 | MetricCulture.Designer.cs 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/MetricModule.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Metric.Core; 2 | using BlazorAdmin.Servers.Core.Modules; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace BlazorAdmin.Metric 6 | { 7 | public class MetricModule : IModule 8 | { 9 | public IServiceCollection Add(IServiceCollection services) 10 | { 11 | services.AddSingleton(new MetricEventListener()); 12 | return services; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using ApexCharts 2 | @using BlazorAdmin.Metric.Core 3 | @using BlazorAdmin.Metric.Resources 4 | @using BlazorAdmin.Servers.Core.States 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.Extensions.Localization 7 | @using MudBlazor 8 | 9 | @inject MetricEventListener _metricEventListener; 10 | @inject ThemeState _themeState; 11 | @inject IStringLocalizer _loc; -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/wwwroot/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aishang2015/BlazorAdmin/599d53e2f701a6abdd3f985a95093e8429ff3c20/src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/wwwroot/background.png -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Metric/wwwroot/exampleJsInterop.js: -------------------------------------------------------------------------------- 1 | // This is a JavaScript module that is loaded on demand. It can export any number of 2 | // functions, and may import other JavaScript modules if required. 3 | 4 | export function showPrompt(message) { 5 | return prompt(message, 'Type anything here'); 6 | } 7 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/BlazorAdmin.Rbac.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | RbacCulture.resx 25 | True 26 | True 27 | 28 | 29 | 30 | 31 | RbacCulture.Designer.cs 32 | PublicResXFileCodeGenerator 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Components/IconSelect.razor.css: -------------------------------------------------------------------------------- 1 |  2 | .icon-item { 3 | } 4 | 5 | .icon-item:hover { 6 | background-color: var(--mud-palette-table-hover); 7 | } 8 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Components/MenuTreeSelect.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 |
3 | 7 | 9 |
10 | 11 | @Loc["MenuPage_UpMenuTitleText"] 12 | 13 |
14 | 15 |
16 | 18 | 19 | 20 | 21 | 22 | @context.Value.MenuName 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Menu/Menu.razor.css: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Organization/Dialogs/MemberSelect.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 7 | 9 | 10 | @foreach (var user in _users) 11 | { 12 | 13 |
14 | @if (string.IsNullOrEmpty(user.Avatar)) 15 | { 16 | 17 | @user.RealName.First() 18 | 19 | } 20 | else 21 | { 22 | 23 | 24 | 25 | } 26 | 27 | @user.RealName 28 | 29 | 30 | @if (user.IsInOrg) 31 | { 32 | 用户已在组织中 33 | } 34 |
35 |
36 | } 37 |
38 |
39 |
40 | 41 |
42 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Role/Dialogs/CreateRoleDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 6 | 7 | 10 |
11 | 12 | @Loc["RolePage_SubmitText"] 14 |
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Role/Dialogs/CreateRoleDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using MudBlazor; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BlazorAdmin.Rbac.Pages.Role.Dialogs 6 | { 7 | public partial class CreateRoleDialog 8 | { 9 | private Dictionary InputAttributes { get; set; } = 10 | new Dictionary() 11 | { 12 | { "autocomplete", "off2" }, 13 | }; 14 | 15 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 16 | 17 | private RoleCreateModel RoleModel = new(); 18 | 19 | private async Task CreateSubmit() 20 | { 21 | using var context = _dbFactory.CreateDbContext(); 22 | if (context.Roles.Any(u => u.Name == RoleModel.RoleName)) 23 | { 24 | _snackbarService.Add("角色名称重复!", Severity.Error); 25 | return; 26 | } 27 | 28 | context.Roles.Add(new Servers.Core.Data.Entities.Rbac.Role 29 | { 30 | Name = RoleModel.RoleName, 31 | IsEnabled = true 32 | }); 33 | await context.SaveChangesAuditAsync(); 34 | _snackbarService.Add("创建成功!", Severity.Success); 35 | MudDialog?.Close(DialogResult.Ok(true)); 36 | } 37 | 38 | private record RoleCreateModel 39 | { 40 | [Required(ErrorMessage = "请输入角色名称")] 41 | [MaxLength(200, ErrorMessage = "角色名称位数过长")] 42 | public string? RoleName { get; set; } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Role/Dialogs/UpdateRoleDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 6 | 7 | 10 |
11 | 12 | @Loc["RolePage_SubmitText"] 14 |
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/Role/Dialogs/UpdateRoleDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using MudBlazor; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BlazorAdmin.Rbac.Pages.Role.Dialogs 6 | { 7 | public partial class UpdateRoleDialog 8 | { 9 | private Dictionary InputAttributes { get; set; } = 10 | new Dictionary() 11 | { 12 | { "autocomplete", "off2" }, 13 | }; 14 | 15 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 16 | 17 | [Parameter] public int RoleId { get; set; } 18 | 19 | private RoleUpdateModel RoleModel = new(); 20 | 21 | protected override async Task OnInitializedAsync() 22 | { 23 | using var context = await _dbFactory.CreateDbContextAsync(); 24 | var role = context.Roles.Find(RoleId); 25 | if (role != null) 26 | { 27 | RoleModel = new RoleUpdateModel 28 | { 29 | Id = role.Id, 30 | RoleName = role.Name, 31 | }; 32 | } 33 | else 34 | { 35 | _snackbarService.Add("角色不存在!", Severity.Error); 36 | } 37 | } 38 | 39 | private async Task UpdateSumbit() 40 | { 41 | using var context = _dbFactory.CreateDbContext(); 42 | if (context.Roles.Any(u => u.Name == RoleModel.RoleName && u.Id != RoleModel.Id)) 43 | { 44 | _snackbarService.Add("角色名称重复!", Severity.Error); 45 | return; 46 | } 47 | 48 | var role = context.Roles.Find(RoleId); 49 | if (role != null) 50 | { 51 | role.Name = RoleModel.RoleName!; 52 | await context.SaveChangesAuditAsync(); 53 | _snackbarService.Add("更新成功!", Severity.Success); 54 | MudDialog?.Close(DialogResult.Ok(true)); 55 | } 56 | else 57 | { 58 | _snackbarService.Add("角色信息不存在!", Severity.Error); 59 | } 60 | } 61 | 62 | private record RoleUpdateModel 63 | { 64 | public int Id { get; set; } 65 | 66 | [Required(ErrorMessage = "请输入角色名称")] 67 | [MaxLength(200, ErrorMessage = "角色名称位数过长")] 68 | public string? RoleName { get; set; } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/ChangePasswordDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 6 | 7 | 9 |
10 | 11 | @Loc["UserPage_SubmitText"] 13 |
14 |
15 |
16 |
17 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/ChangePasswordDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Helper; 2 | using Microsoft.AspNetCore.Components; 3 | using MudBlazor; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace BlazorAdmin.Rbac.Pages.User.Dialogs 7 | { 8 | public partial class ChangePasswordDialog 9 | { 10 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 11 | [Parameter] public int UserId { get; set; } 12 | 13 | private PasswordChangeModel PasswordModel = new(); 14 | 15 | private async Task Submit() 16 | { 17 | using var context = _dbFactory.CreateDbContext(); 18 | var user = context.Users.Find(UserId); 19 | if (user != null) 20 | { 21 | user.PasswordHash = HashHelper.HashPassword(PasswordModel.Password!); 22 | await context.SaveChangesAuditAsync(); 23 | _snackbarService.Add("密码修改成功!", Severity.Success); 24 | MudDialog?.Close(DialogResult.Ok(true)); 25 | } 26 | else 27 | { 28 | _snackbarService.Add("用户信息不存在!", Severity.Error); 29 | } 30 | } 31 | 32 | private record PasswordChangeModel 33 | { 34 | [Required(ErrorMessage = "请输入密码")] 35 | [MinLength(4, ErrorMessage = "密码位数过短")] 36 | [MaxLength(100, ErrorMessage = "密码位数过长")] 37 | [RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", ErrorMessage = "密码中必须包含大小写字母以及数字")] 38 | public string? Password { get; set; } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/CreateUserDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 6 | 7 | 10 | 13 | 16 | 19 | 21 |
22 | 23 | @Loc["UserPage_SubmitText"] 25 |
26 |
27 |
28 |
29 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/CreateUserDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Helper; 2 | using Microsoft.AspNetCore.Components; 3 | using MudBlazor; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace BlazorAdmin.Rbac.Pages.User.Dialogs 7 | { 8 | public partial class CreateUserDialog 9 | { 10 | private Dictionary InputAttributes { get; set; } = 11 | new Dictionary() 12 | { 13 | { "autocomplete", "off2" }, 14 | }; 15 | 16 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 17 | 18 | private UserCreateModel UserModel = new(); 19 | 20 | private async Task CreateSubmit() 21 | { 22 | using var context = _dbFactory.CreateDbContext(); 23 | if (context.Users.Any(u => u.Name == UserModel.UserName)) 24 | { 25 | _snackbarService.Add("用户名重复!", Severity.Error); 26 | return; 27 | } 28 | 29 | context.Users.Add(new Servers.Core.Data.Entities.Rbac.User 30 | { 31 | IsEnabled = true, 32 | Name = UserModel.UserName!, 33 | RealName = UserModel.RealName!, 34 | PasswordHash = HashHelper.HashPassword(UserModel.Password!), 35 | Email = UserModel.Email, 36 | PhoneNumber = UserModel.PhoneNumber 37 | }); 38 | await context.SaveChangesAuditAsync(); 39 | _snackbarService.Add("创建成功!", Severity.Success); 40 | MudDialog?.Close(DialogResult.Ok(true)); 41 | } 42 | 43 | private record UserCreateModel 44 | { 45 | [Required(ErrorMessage = "请输入用户名")] 46 | [MaxLength(200, ErrorMessage = "用户名位数过长")] 47 | public string? UserName { get; set; } 48 | 49 | [Required(ErrorMessage = "请输入姓名")] 50 | [MaxLength(200, ErrorMessage = "姓名位数过长")] 51 | public string? RealName { get; set; } 52 | 53 | [Required(ErrorMessage = "请输入密码")] 54 | [MinLength(4, ErrorMessage = "密码位数过短")] 55 | [MaxLength(100, ErrorMessage = "密码位数过长")] 56 | [RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$", ErrorMessage = "密码中必须包含大小写字母以及数字")] 57 | public string? Password { get; set; } 58 | 59 | [EmailAddress(ErrorMessage = "请输入正确的邮箱地址")] 60 | public string? Email { get; set; } 61 | 62 | [MaxLength(30, ErrorMessage = "电话号码长度过长")] 63 | public string? PhoneNumber { get; set; } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/UpdateUserDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 | 6 | 7 | 10 | 13 | 16 | 19 |
20 | 21 | @Loc["UserPage_SubmitText"] 23 |
24 |
25 |
26 |
27 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/UserRoleDialog.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 |
6 | @foreach (var role in RoleList) 7 | { 8 | @role.Name 9 | } 10 |
11 |
12 | 13 | @Loc["UserPage_SubmitText"] 15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/Pages/User/Dialogs/UserRoleDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Rbac; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.EntityFrameworkCore; 4 | using MudBlazor; 5 | 6 | namespace BlazorAdmin.Rbac.Pages.User.Dialogs 7 | { 8 | public partial class UserRoleDialog 9 | { 10 | 11 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 12 | 13 | [Parameter] public int UserId { get; set; } 14 | 15 | private List RoleList = new(); 16 | 17 | private Dictionary CheckedDic = new Dictionary(); 18 | 19 | protected override async Task OnInitializedAsync() 20 | { 21 | using var context = await _dbFactory.CreateDbContextAsync(); 22 | RoleList = await context.Roles.Where(r => r.IsEnabled && !r.IsDeleted).ToListAsync(); 23 | 24 | var userRoles = await context.UserRoles.Where(ur => ur.UserId == UserId).ToListAsync(); 25 | 26 | foreach (var role in RoleList) 27 | { 28 | CheckedDic[role.Id] = userRoles.Any(ur => ur.RoleId == role.Id); 29 | } 30 | } 31 | 32 | private async Task SubmitUserRole() 33 | { 34 | using var context = await _dbFactory.CreateDbContextAsync(); 35 | var userRoles = await context.UserRoles.Where(ur => ur.UserId == UserId).ToListAsync(); 36 | 37 | var deleteRoles = userRoles.Where(ur => !CheckedDic[ur.RoleId]); 38 | context.UserRoles.RemoveRange(deleteRoles); 39 | var addRoles = CheckedDic.Where(kv => userRoles.All(ur => kv.Key != ur.RoleId) && kv.Value); 40 | context.UserRoles.AddRange(addRoles.Select(kv => new UserRole 41 | { 42 | UserId = UserId, 43 | RoleId = kv.Key, 44 | })); 45 | 46 | await context.SaveChangesAuditAsync(); 47 | 48 | _snackbarService.Add("提交成功!", Severity.Success); 49 | MudDialog?.Close(DialogResult.Ok(true)); 50 | 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | 4 | @using BlazorAdmin.Rbac.Components; 5 | @using BlazorAdmin.Rbac.Resources; 6 | @using BlazorAdmin.Servers.Core.Auth; 7 | @using BlazorAdmin.Servers.Core.Components.Pages; 8 | @using BlazorAdmin.Servers.Core.Components.Select; 9 | @using BlazorAdmin.Servers.Core.Data; 10 | @using BlazorAdmin.Servers.Core.Helper 11 | @using BlazorAdmin.Servers.Core.Resources; 12 | @using BlazorAdmin.Servers.Core.Services; 13 | @using Microsoft.AspNetCore.Authorization 14 | @using Microsoft.AspNetCore.Components.Authorization 15 | @using Microsoft.AspNetCore.Components.Forms 16 | @using Microsoft.AspNetCore.Components.Routing 17 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 18 | @using Microsoft.AspNetCore.Components.Web 19 | @using Microsoft.AspNetCore.Components.Web.Virtualization 20 | @using Microsoft.EntityFrameworkCore; 21 | @using Microsoft.Extensions.Localization; 22 | @using Microsoft.JSInterop 23 | @using MudBlazor 24 | 25 | @inject IJSRuntime _jsRuntime; 26 | @inject IDbContextFactory _dbFactory; 27 | @inject IDialogService _dialogService; 28 | @inject ISnackbar _snackbarService; 29 | @inject IAccessService _accessService; 30 | 31 | @inject JwtHelper _jwtHelper; 32 | @inject AuthenticationStateProvider _stateProvider; 33 | @inject ExternalAuthService _authService; 34 | @inject ProtectedLocalStorage _localStorage; 35 | @inject NavigationManager _navManager; 36 | @inject IStringLocalizer Loc; 37 | @inject IJobService _jobService; 38 | 39 | 40 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Rbac/wwwroot/js/sort.js: -------------------------------------------------------------------------------- 1 | export function setSortable(pageRef) { 2 | let list = document.getElementsByClassName("mud-treeview"); 3 | for (let l of list) { 4 | Sortable.create(l, { 5 | handle: '.draghandle', 6 | //group: 'nested', 7 | animation: 150, 8 | fallbackOnBody: true, 9 | swapThreshold: 0.65, 10 | onEnd: function (/**Event*/evt) { 11 | //console.log(evt.clone); 12 | 13 | let id = ''; 14 | let children = evt.clone.getElementsByTagName("div"); 15 | for (var i = 0; i < children.length; i++) { 16 | var child = children[i]; 17 | var classNames = child.className.split(' '); 18 | for (var j = 0; j < classNames.length; j++) { 19 | if (classNames[j] === 'identify') { 20 | id = child.innerText; 21 | break; 22 | } 23 | } 24 | if (id !== '') { 25 | break; 26 | } 27 | } 28 | pageRef.invokeMethodAsync('DragEnd', Number(id), evt.oldIndex, evt.newIndex); 29 | } 30 | }); 31 | } 32 | 33 | //let list2 = document.getElementsByClassName("mud-treeview-item"); 34 | //for (let l of list2) { 35 | // Sortable.create(l, { 36 | // handle: '.hidden-btn', 37 | // animation: 150, 38 | // onEnd: function (/**Event*/evt) { 39 | // console.log(evt); 40 | 41 | // pageRef.invokeMethodAsync('DragEnd', evt.oldIndex, evt.newIndex); 42 | // } 43 | // }); 44 | //} 45 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/BlazorAdmin.Setting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | True 16 | True 17 | SettingCulture.resx 18 | 19 | 20 | 21 | 22 | ResXFileCodeGenerator 23 | SettingCulture.Designer.cs 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/Pages/Setting/Com/JwtCom.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 | 5 | 7 | 9 | 11 | 12 |
13 | 14 | 16 | @_loc["JwtComGenerateNew"] 17 | 18 | 20 | @_loc["JwtComSave"] 21 | 22 |
23 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/Pages/Setting/Dialogs/ConfirmUpdateRsa.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | 3 | 4 |
5 |
6 | 7 | @_loc["JwtComConfirmQuestion"] 8 |
9 |
10 | 11 | 13 | @_loc["JwtComConfirmText"] 14 | 15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/Pages/Setting/Dialogs/ConfirmUpdateRsa.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using MudBlazor; 3 | 4 | namespace BlazorAdmin.Setting.Pages.Setting.Dialogs 5 | { 6 | public partial class ConfirmUpdateRsa 7 | { 8 | 9 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 10 | 11 | private void Confirm() 12 | { 13 | MudDialog?.Close(DialogResult.Ok(true)); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/Pages/Setting/SettingPage.razor: -------------------------------------------------------------------------------- 1 | @page "/setting" 2 | @using BlazorAdmin.Servers.Core.Helper 3 | 4 | @rendermode RenderMode.InteractiveServer 5 | @attribute [StreamRendering] 6 | 7 |
8 | 9 | 10 | 11 | 12 |
13 | 14 | @foreach (var group in SettingGroups) 15 | { 16 | 17 |
18 | 19 | 20 | @group.Name 21 | 22 |
23 |
24 | } 25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/Pages/Setting/SettingPage.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Setting.Pages.Setting.Com; 2 | using MudBlazor; 3 | 4 | namespace BlazorAdmin.Setting.Pages.Setting 5 | { 6 | public partial class SettingPage 7 | { 8 | private MudListItem? SelectedItem; 9 | 10 | private SettingModel? SelectedValue; 11 | 12 | private List SettingGroups = new(); 13 | 14 | private Dictionary SettingComDic = new(); 15 | 16 | protected override async Task OnInitializedAsync() 17 | { 18 | await base.OnInitializedAsync(); 19 | SettingGroups = new List{ 20 | new SettingModel 21 | { 22 | Name = _loc["JwtComTitle"], 23 | Icon = Icons.Material.Filled.Security 24 | }, 25 | }; 26 | SettingComDic = new Dictionary 27 | { 28 | {_loc["JwtComTitle"],typeof(JwtCom)}, 29 | }; 30 | SelectedValue = SettingGroups.First(); 31 | } 32 | 33 | private class SettingModel 34 | { 35 | public string Name { get; set; } = null!; 36 | 37 | public string Icon { get; set; } = null!; 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Modules/BlazorAdmin.Setting/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | 4 | @using BlazorAdmin.Servers.Core.Auth; 5 | @using BlazorAdmin.Servers.Core.Components.Pages; 6 | @using BlazorAdmin.Servers.Core.Data; 7 | @using BlazorAdmin.Servers.Core.Helper 8 | @using BlazorAdmin.Servers.Core.Resources; 9 | @using BlazorAdmin.Servers.Core.Services; 10 | @using BlazorAdmin.Setting.Resources 11 | @using Microsoft.AspNetCore.Authorization 12 | @using Microsoft.AspNetCore.Components.Authorization 13 | @using Microsoft.AspNetCore.Components.Forms 14 | @using Microsoft.AspNetCore.Components.Routing 15 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 16 | @using Microsoft.AspNetCore.Components.Web 17 | @using Microsoft.AspNetCore.Components.Web.Virtualization 18 | @using Microsoft.EntityFrameworkCore; 19 | @using Microsoft.Extensions.Localization; 20 | @using Microsoft.JSInterop 21 | @using MudBlazor 22 | 23 | @inject IJSRuntime _jsRuntime; 24 | @inject IDbContextFactory _dbFactory; 25 | @inject IDialogService _dialogService; 26 | @inject ISnackbar _snackbarService; 27 | @inject IAccessService _accessService; 28 | 29 | @inject JwtHelper _jwtHelper; 30 | @inject AuthenticationStateProvider _stateProvider; 31 | @inject ExternalAuthService _authService; 32 | @inject ProtectedLocalStorage _localStorage; 33 | @inject NavigationManager _navManager; 34 | @inject IStringLocalizer Loc; 35 | @inject IStringLocalizer _loc; 36 | 37 | 38 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/ApiAuthorizeAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace BlazorAdmin.Servers.Core.Auth 4 | { 5 | public class ApiAuthorizeAttribute : AuthorizeAttribute 6 | { 7 | public ApiAuthorizeAttribute() 8 | { 9 | // 可以在这里设置默认的策略或其他属性 10 | Policy = "ApiAuthorizePolicy"; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/ApiAuthorizeHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace BlazorAdmin.Servers.Core.Auth 4 | { 5 | public class ApiAuthorizeHandler : AuthorizationHandler 6 | { 7 | protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ApiAuthorizeRequirement requirement) 8 | { 9 | context.Succeed(requirement); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/ApiAuthorizeRequirement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace BlazorAdmin.Servers.Core.Auth 4 | { 5 | public class ApiAuthorizeRequirement : IAuthorizationRequirement 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/BlazorAuthorizationMiddlewareResultHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Authorization.Policy; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace BlazorAdmin.Servers.Core.Auth 6 | { 7 | 8 | // https://github.com/dotnet/aspnetcore/issues/52063 9 | // AuthorizeRouteView 不起作用 10 | public class BlazorAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler 11 | { 12 | public Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult) 13 | { 14 | // 检查是否是自定义的授权策略 15 | if (policy.Requirements.OfType().Any() && 16 | !authorizeResult.Succeeded) 17 | { 18 | // 返回401 19 | context.Response.StatusCode = 401; 20 | return Task.CompletedTask; 21 | } 22 | 23 | return next(context); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/JwtAuthStateProvider.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Constants; 2 | using BlazorAdmin.Servers.Core.Helper; 3 | using Microsoft.AspNetCore.Components.Authorization; 4 | using Microsoft.AspNetCore.Http; 5 | using System.Security.Claims; 6 | 7 | namespace BlazorAdmin.Servers.Core.Auth 8 | { 9 | public class JwtAuthStateProvider : AuthenticationStateProvider 10 | { 11 | private readonly IHttpContextAccessor _contextAccessor; 12 | 13 | private readonly JwtHelper _jwtHelper; 14 | 15 | private AuthenticationState currentUser = new AuthenticationState(new ClaimsPrincipal()); 16 | 17 | public JwtAuthStateProvider(ExternalAuthService service, IHttpContextAccessor httpContextAccessor, 18 | JwtHelper jwtHelper) 19 | { 20 | _contextAccessor = httpContextAccessor; 21 | _jwtHelper = jwtHelper; 22 | service.UserChanged += (newUser) => 23 | { 24 | currentUser = new AuthenticationState(newUser); 25 | NotifyAuthenticationStateChanged(Task.FromResult(currentUser)); 26 | }; 27 | 28 | var tokenCookie = _contextAccessor.HttpContext?.Request.Cookies 29 | .FirstOrDefault(c => c.Key == CommonConstant.UserToken).Value; 30 | if (!string.IsNullOrEmpty(tokenCookie)) 31 | { 32 | var user = _jwtHelper.ValidToken(tokenCookie); 33 | if (user != null) 34 | { 35 | currentUser = new AuthenticationState(user); 36 | } 37 | } 38 | } 39 | 40 | public override Task GetAuthenticationStateAsync() => Task.FromResult(currentUser); 41 | } 42 | 43 | public class ExternalAuthService 44 | { 45 | public event Action? UserChanged; 46 | 47 | private JwtHelper _jwtHelper; 48 | 49 | public ExternalAuthService(JwtHelper jwtHelper) 50 | { 51 | _jwtHelper = jwtHelper; 52 | } 53 | 54 | public void SetCurrentUser(string token) 55 | { 56 | var user = _jwtHelper.ValidToken(token); 57 | if (user == null) 58 | { 59 | user = new ClaimsPrincipal(); 60 | } 61 | if (UserChanged is not null) 62 | { 63 | UserChanged(user); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/JwtOptionsExtension.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data; 2 | using BlazorAdmin.Servers.Core.Data.Constants; 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.IdentityModel.Tokens; 7 | using System.Security.Cryptography; 8 | 9 | namespace BlazorAdmin.Servers.Core.Auth 10 | { 11 | public static class JwtOptionsExtension 12 | { 13 | 14 | public static async void InitialJwtOptions(JwtBearerOptions options) 15 | { 16 | using var scope = CurrentApplication.Application.Services.CreateScope(); 17 | var dbContextFactory = scope.ServiceProvider.GetRequiredService>(); 18 | using var context = await dbContextFactory.CreateDbContextAsync(); 19 | 20 | var issuer = context.Settings.FirstOrDefault(s => s.Key == JwtConstant.JwtIssue)!.Value; 21 | var audience = context.Settings.FirstOrDefault(s => s.Key == JwtConstant.JwtAudience)!.Value; 22 | var privateKey = context.Settings.FirstOrDefault(s => s.Key == JwtConstant.JwtSigningRsaPrivateKey)!.Value; 23 | var publicKey = context.Settings.FirstOrDefault(s => s.Key == JwtConstant.JwtSigningRsaPublicKey)!.Value; 24 | 25 | var rsa = RSA.Create(); 26 | rsa.ImportRSAPublicKey(Convert.FromBase64String(publicKey), out int publicReadBytes); 27 | rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateKey), out int privateReadBytes); 28 | var securityKey = new RsaSecurityKey(rsa); 29 | options.TokenValidationParameters = new TokenValidationParameters() 30 | { 31 | ValidAudience = audience, 32 | ValidateAudience = false, 33 | 34 | ValidIssuer = issuer, 35 | ValidateIssuer = false, 36 | 37 | IssuerSigningKey = securityKey, 38 | 39 | ValidateIssuerSigningKey = true, 40 | ValidateLifetime = true 41 | }; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Auth/UserStateExtension.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Extension; 2 | using Microsoft.AspNetCore.Components.Authorization; 3 | 4 | namespace BlazorAdmin.Servers.Core.Auth 5 | { 6 | public static class UserStateExtension 7 | { 8 | public static async Task GetUserIdAsync(this AuthenticationStateProvider authenticationStateProvider) 9 | { 10 | var state = await authenticationStateProvider.GetAuthenticationStateAsync(); 11 | return state.User.GetUserId(); 12 | } 13 | 14 | public static async Task GetUserNameAsync(this AuthenticationStateProvider authenticationStateProvider) 15 | { 16 | var state = await authenticationStateProvider.GetAuthenticationStateAsync(); 17 | return state.User.GetUserName(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Chat/ChatMessageReceivedModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Chat 2 | { 3 | public class ChatMessageReceivedModel 4 | { 5 | /// 6 | /// 接收人 7 | /// 8 | public int? ReceiverId { get; set; } 9 | 10 | /// 11 | /// 频道(指定频道发送时) 12 | /// 13 | public int? ChannelId { get; set; } 14 | 15 | /// 16 | /// 发送人 17 | /// 18 | public int SenderId { get; set; } 19 | 20 | /// 21 | /// 发送内容 22 | /// 23 | public string? Content { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Chat/ChatMessageSendModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Chat 2 | { 3 | public record ChatMessageSendModel 4 | { 5 | /// 6 | /// 频道(指定频道发送时) 7 | /// 8 | public int? ChannelId { get; set; } 9 | 10 | /// 11 | /// 接收人(指定人发送时) 12 | /// 13 | public int? ReceiverId { get; set; } 14 | 15 | /// 16 | /// 发送人 17 | /// 18 | public int SenderId { get; set; } 19 | 20 | /// 21 | /// 发送内容 22 | /// 23 | public string? Content { get; set; } 24 | 25 | /// 26 | /// 消息类型 27 | /// 28 | public int MessageType { get; set; } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Chat/MessageSender.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data; 2 | using BlazorAdmin.Servers.Core.Helper; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System.Collections.Concurrent; 6 | 7 | namespace BlazorAdmin.Servers.Core.Chat 8 | { 9 | public class MessageSender 10 | { 11 | private readonly IServiceProvider _serviceProvider; 12 | 13 | private readonly ConcurrentDictionary _specialUserDic = new(); 14 | 15 | public MessageSender(IServiceProvider serviceProvider) 16 | { 17 | _serviceProvider = serviceProvider; 18 | } 19 | 20 | [Obsolete] 21 | public async Task SendSystemMessage(int targetUserId, string content) 22 | { 23 | var senderId = await GetUserId("SystemNotification"); 24 | if (senderId == null) 25 | { 26 | return false; 27 | } 28 | 29 | await ChannelHelper.Instance.Writer.WriteAsync(new ChatMessageSendModel 30 | { 31 | SenderId = senderId.Value, 32 | Content = content, 33 | ReceiverId = targetUserId, 34 | MessageType = 1 35 | }); 36 | return true; 37 | } 38 | 39 | [Obsolete] 40 | public async Task SendChannelMessage(int senderId, int? targetChannel, 41 | int? targetUserId, string? content, int type = 1) 42 | { 43 | await ChannelHelper.Instance.Writer.WriteAsync(new ChatMessageSendModel 44 | { 45 | SenderId = senderId, 46 | Content = content, 47 | ChannelId = targetChannel, 48 | ReceiverId = targetUserId, 49 | MessageType = type 50 | }); 51 | return true; 52 | } 53 | 54 | [Obsolete] 55 | private async Task GetUserId(string name) 56 | { 57 | if (!_specialUserDic.TryGetValue(name, out var sourceId)) 58 | { 59 | using var scope = _serviceProvider.CreateScope(); 60 | var factory = scope.ServiceProvider.GetRequiredService>(); 61 | using var context = await factory.CreateDbContextAsync(); 62 | 63 | var user = context.Users.FirstOrDefault(u => u.Name == name); 64 | return user?.Id; 65 | } 66 | 67 | return sourceId; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Dialogs/CommonDeleteDialog.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | @using BlazorAdmin.Servers.Core.Auth; 4 | @using BlazorAdmin.Servers.Core.Data; 5 | @using BlazorAdmin.Servers.Core.Helper 6 | @using BlazorAdmin.Servers.Core.Resources; 7 | @using BlazorAdmin.Servers.Core.Services; 8 | @using Microsoft.AspNetCore.Authorization 9 | @using Microsoft.AspNetCore.Components.Authorization 10 | @using Microsoft.AspNetCore.Components.Forms 11 | @using Microsoft.AspNetCore.Components.Routing 12 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 13 | @using Microsoft.AspNetCore.Components.Web 14 | @using Microsoft.AspNetCore.Components.Web.Virtualization 15 | @using Microsoft.EntityFrameworkCore; 16 | @using Microsoft.Extensions.Localization; 17 | @using Microsoft.JSInterop 18 | @using MudBlazor 19 | 20 | @inject IJSRuntime _jsRuntime; 21 | @inject IDbContextFactory _dbFactory; 22 | @inject IDialogService _dialogService; 23 | @inject ISnackbar _snackbarService; 24 | @inject IAccessService _accessService; 25 | 26 | @inject JwtHelper _jwtHelper; 27 | @inject AuthenticationStateProvider _stateProvider; 28 | @inject ExternalAuthService _authService; 29 | @inject ProtectedLocalStorage _localStorage; 30 | @inject NavigationManager _navManager; 31 | @inject IStringLocalizer _loc; 32 | 33 | 34 | 35 |
36 |
37 | 38 | @Title 39 |
40 |
41 | 42 | 43 | @if (_isLoading) 44 | { 45 | 46 | } 47 | else 48 | { 49 | @ConfirmButtonText 50 | } 51 | 52 |
53 |
54 |
55 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Dialogs/CommonDeleteDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using MudBlazor; 3 | 4 | namespace BlazorAdmin.Servers.Core.Components.Dialogs 5 | { 6 | public partial class CommonDeleteDialog 7 | { 8 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 9 | 10 | [Parameter] public string? Title { get; set; } 11 | 12 | [Parameter] public string? ConfirmButtonText { get; set; } 13 | 14 | [Parameter] public EventCallback ConfirmCallBack { get; set; } 15 | 16 | private bool _isLoading = false; 17 | 18 | protected override void OnInitialized() 19 | { 20 | base.OnInitialized(); 21 | Title ??= _loc["CommonDeleteDialogTitle"]; 22 | ConfirmButtonText ??= _loc["CommonDeleteDialogConfirmButtonText"]; 23 | } 24 | 25 | private async Task ConfirmDelete() 26 | { 27 | _isLoading = true; 28 | await ConfirmCallBack.InvokeAsync(new CommonDialogEventArgs()); 29 | _isLoading = false; 30 | MudDialog?.Close(DialogResult.Ok(true)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Dialogs/CommonDialogEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Components.Dialogs 2 | { 3 | public record CommonDialogEventArgs 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Dialogs/ConfirmUserPasswordDialog.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Auth; 2 | using BlazorAdmin.Servers.Core.Helper; 3 | using BlazorAdmin.Servers.Core.Resources; 4 | using Microsoft.AspNetCore.Components; 5 | using Microsoft.AspNetCore.Components.Authorization; 6 | using MudBlazor; 7 | using System.ComponentModel.DataAnnotations; 8 | 9 | namespace BlazorAdmin.Servers.Core.Components.Dialogs 10 | { 11 | public partial class ConfirmUserPasswordDialog 12 | { 13 | private Dictionary _inputAttributes = 14 | new Dictionary() 15 | { 16 | { "autocomplete", "new-password2" }, 17 | }; 18 | 19 | private bool _isLoading = false; 20 | 21 | private PasswordModel _passwordModel = new PasswordModel(); 22 | 23 | [CascadingParameter] IMudDialogInstance? MudDialog { get; set; } 24 | 25 | [Inject] public AuthenticationStateProvider? AuthStateProvider { get; set; } 26 | 27 | [Parameter] public EventCallback ConfirmCallBack { get; set; } 28 | 29 | private async Task ConfirmPassword() 30 | { 31 | _isLoading = true; 32 | using var context = await _dbFactory.CreateDbContextAsync(); 33 | 34 | var userId = await AuthStateProvider!.GetUserIdAsync(); 35 | var user = context.Users.Find(userId); 36 | if (user == null) 37 | { 38 | _snackbarService.Add(_loc["NotFindUser"], Severity.Error); 39 | MudDialog?.Close(DialogResult.Cancel()); 40 | return; 41 | } 42 | var isPwdValid = HashHelper.VerifyPassword(user.PasswordHash, _passwordModel.Password!); 43 | if (!isPwdValid) 44 | { 45 | _snackbarService.Add(_loc["PasswordValidFail"], Severity.Error); 46 | MudDialog?.Close(DialogResult.Cancel()); 47 | return; 48 | } 49 | 50 | await ConfirmCallBack.InvokeAsync(new CommonDialogEventArgs()); 51 | _isLoading = false; 52 | MudDialog?.Close(DialogResult.Ok(true)); 53 | } 54 | 55 | private class PasswordModel 56 | { 57 | [Required(ErrorMessageResourceName = "Login_PasswordHelpText", 58 | ErrorMessageResourceType = typeof(CusCulture))] 59 | public string? Password { get; set; } 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Pages/PageDataGridConfig.cs: -------------------------------------------------------------------------------- 1 | using MudBlazor; 2 | 3 | namespace BlazorAdmin.Servers.Core.Components.Pages 4 | { 5 | public class PageDataGridConfig 6 | { 7 | public static bool Dense { get; private set; } = true; 8 | 9 | public static bool Filterable { get; private set; } = false; 10 | 11 | public static ResizeMode ColumnResizeMode { get; private set; } = ResizeMode.Column; 12 | 13 | public static SortMode SortMode { get; private set; } = SortMode.None; 14 | 15 | public static bool Groupable { get; private set; } = false; 16 | 17 | public static bool Virtualize { get; private set; } = true; 18 | 19 | public static bool FixedHeader { get; private set; } = true; 20 | 21 | public static int Elevation { get; private set; } = 1; 22 | 23 | public static bool Outlined { get; private set; } = false; 24 | 25 | public static string Style { get; private set; } = "flex: 1;"; 26 | 27 | public static bool HorizontalScrollbar = true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Components/Pages/PageHeader.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using BlazorAdmin 3 | @using BlazorAdmin.Servers.Core.Auth; 4 | @using BlazorAdmin.Servers.Core.Data; 5 | @using BlazorAdmin.Servers.Core.Helper 6 | @using BlazorAdmin.Servers.Core.Resources; 7 | @using BlazorAdmin.Servers.Core.Services; 8 | @using Microsoft.AspNetCore.Authorization 9 | @using Microsoft.AspNetCore.Components.Authorization 10 | @using Microsoft.AspNetCore.Components.Forms 11 | @using Microsoft.AspNetCore.Components.Routing 12 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage; 13 | @using Microsoft.AspNetCore.Components.Web 14 | @using Microsoft.AspNetCore.Components.Web.Virtualization 15 | @using Microsoft.EntityFrameworkCore; 16 | @using Microsoft.Extensions.Localization; 17 | @using Microsoft.JSInterop 18 | @using MudBlazor 19 | 20 | @inject IJSRuntime _jsRuntime; 21 | @inject IDbContextFactory _dbFactory; 22 | @inject IDialogService _dialogService; 23 | @inject ISnackbar _snackbarService; 24 | @inject IAccessService _accessService; 25 | 26 | @inject JwtHelper _jwtHelper; 27 | @inject AuthenticationStateProvider _stateProvider; 28 | @inject ExternalAuthService _authService; 29 | @inject ProtectedLocalStorage _localStorage; 30 | @inject NavigationManager _navManager; 31 | @inject IStringLocalizer _loc; 32 | 33 | 34 | 35 | @Title 36 | 37 | 38 | @ChildContent 39 | 40 | 41 | @code { 42 | 43 | [Parameter] public string? Title { get; set; } 44 | 45 | [Parameter] public RenderFragment? ChildContent { get; set; } 46 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/CurrentApplication.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | 3 | namespace BlazorAdmin.Servers.Core 4 | { 5 | public static class CurrentApplication 6 | { 7 | public static WebApplication Application { get; set; } = null!; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Attributes/IgnoreAudit.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Data.Attributes 2 | { 3 | public class IgnoreAuditAttribute : Attribute 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Constants/ClaimConstant.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Data.Constants 2 | { 3 | public record ClaimConstant 4 | { 5 | public const string UserId = "UserId"; 6 | 7 | public const string UserName = "UserName"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Constants/CommonConstant.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Data.Constants 2 | { 3 | public record CommonConstant 4 | { 5 | public const string UserId = "UserId"; 6 | 7 | public const string UserToken = "AccessToken"; 8 | 9 | public const string UserTabs = "UserTabs"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Constants/JwtConstant.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Data.Constants 2 | { 3 | public record JwtConstant 4 | { 5 | public const string JwtIssue = "JwtIssuer"; 6 | public const string JwtAudience = "JwtAudience"; 7 | public const string JwtSigningRsaPublicKey = "JwtSigningRsaPublicKey"; 8 | public const string JwtSigningRsaPrivateKey = "JwtSigningRsaPrivateKey"; 9 | public const string JwtExpireMinute = "JwtExpireMinute"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Ai/AiConfig.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Ai 6 | { 7 | [Table("AI_CONFIG")] 8 | [Comment("AI配置")] 9 | [IgnoreAudit] 10 | public class AiConfig 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("配置名称")] 16 | public string? ConfigName { get; set; } 17 | 18 | [Comment("接口地址")] 19 | public string? Endpoint { get; set; } 20 | 21 | [Comment("API密钥")] 22 | public string? ApiKey { get; set; } 23 | 24 | [Comment("模型名称")] 25 | public string? ModelName { get; set; } 26 | 27 | [Comment("输入单价(每百万Token)")] 28 | public decimal? InputPricePerToken { get; set; } 29 | 30 | [Comment("输出单价(每百万Token)")] 31 | public decimal? OutputPricePerToken { get; set; } 32 | 33 | [Comment("上下文长度")] 34 | public int ContextLength { get; set; } 35 | 36 | [Comment("配置描述")] 37 | public string? Description { get; set; } 38 | 39 | [Comment("是否启用")] 40 | public bool IsEnabled { get; set; } 41 | 42 | [Comment("是否删除")] 43 | public bool IsDeleted { get; set; } 44 | } 45 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Ai/AiPrompt.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Ai 6 | { 7 | [Table("AI_PROMPT")] 8 | [Comment("AI提示词配置")] 9 | [IgnoreAudit] 10 | public class AiPrompt 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("提示词名称")] 16 | public string? PromptName { get; set; } 17 | 18 | [Comment("提示词内容")] 19 | public string? PromptContent { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Ai/AiRequestRecord.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Ai 6 | { 7 | [Table("AI_REQUEST_RECORD")] 8 | [Comment("AI请求记录")] 9 | [IgnoreAudit] 10 | public class AiRequestRecord 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("Ai配置Id")] 16 | public int? AiConfigId { get; set; } 17 | 18 | [Comment("请求时间")] 19 | public DateTime RequestTime { get; set; } 20 | 21 | [Comment("耗时")] 22 | public int ElapsedMilliseconds { get; set; } 23 | 24 | [Comment("请求Token数")] 25 | public int RequestTokens { get; set; } 26 | 27 | [Comment("响应Token数")] 28 | public int ResponseTokens { get; set; } 29 | 30 | [Comment("总价")] 31 | public decimal TotalPrice { get; set; } 32 | 33 | [Comment("请求内容")] 34 | public string? RequestContent { get; set; } 35 | 36 | [Comment("响应内容")] 37 | public string? ResponseContent { get; set; } 38 | } 39 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/Group.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("群聊")] 8 | [Table("CHAT_GROUP")] 9 | [IgnoreAudit] 10 | public class Group 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("名称")] 16 | public string? Name { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/GroupMember.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("群聊成员")] 8 | [Table("CHAT_GROUP_MEMBER")] 9 | [IgnoreAudit] 10 | public class GroupMember 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("群聊ID")] 16 | public int GroupId { get; set; } 17 | 18 | [Comment("群聊成员ID")] 19 | public int MemberId { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/GroupMessage.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("群聊消息")] 8 | [Table("CHAT_GROUP_MESSAGE")] 9 | [IgnoreAudit] 10 | public class GroupMessage 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("群聊ID")] 16 | public int GroupId { get; set; } 17 | 18 | [Comment("消息类型")] 19 | public int MessageType { get; set; } 20 | 21 | [Comment("发送人")] 22 | public int SenderId { get; set; } 23 | 24 | [Comment("发送时间")] 25 | public DateTime SendTime { get; set; } 26 | 27 | [Comment("发送内容")] 28 | public string? Content { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/GroupSetting.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("群聊设置")] 8 | [Table("CHAT_GROUP_SETTING")] 9 | [IgnoreAudit] 10 | public class GroupSetting 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("所属用户")] 16 | public int UserId { get; set; } 17 | 18 | [Comment("所在群聊")] 19 | public int GroupId { get; set; } 20 | 21 | [Comment("显示顺序")] 22 | public int Order { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/NotReadedMessage.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("未读消息")] 8 | [Table("CHAT_NOT_READED_MESSAGE")] 9 | [IgnoreAudit] 10 | public class NotReadedMessage 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("用户")] 16 | public int UserId { get; set; } 17 | 18 | [Comment("群聊ID")] 19 | public int? GroupId { get; set; } 20 | 21 | [Comment("发送用户ID")] 22 | public int? SendUserId { get; set; } 23 | 24 | [Comment("消息ID")] 25 | public int MessageId { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/PrivateMessage.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("单聊消息")] 8 | [Table("CHAT_PRIVATE_MESSAGE")] 9 | [Index(nameof(ReceiverId))] 10 | [Index(nameof(SenderId))] 11 | [IgnoreAudit] 12 | public class PrivateMessage 13 | { 14 | [Comment("主键")] 15 | public int Id { get; set; } 16 | 17 | [Comment("消息类型")] 18 | public int MessageType { get; set; } 19 | 20 | [Comment("发送人")] 21 | public int SenderId { get; set; } 22 | 23 | [Comment("接收人")] 24 | public int ReceiverId { get; set; } 25 | 26 | [Comment("发送时间")] 27 | public DateTime SendTime { get; set; } 28 | 29 | [Comment("发送内容")] 30 | public string? Content { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Chat/PrivateSetting.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Chat 6 | { 7 | [Comment("单聊设置")] 8 | [Table("CHAT_PRIVATE_SETTING")] 9 | [IgnoreAudit] 10 | public class PrivateSetting 11 | { 12 | [Comment("主键")] 13 | public int Id { get; set; } 14 | 15 | [Comment("所属用户")] 16 | public int UserId { get; set; } 17 | 18 | [Comment("对话用户")] 19 | public int OtherUserId { get; set; } 20 | 21 | [Comment("显示顺序")] 22 | public int Order { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Log/AuditLog.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Log 6 | { 7 | [Table("LOG_AUDIT")] 8 | [Comment("审计日志")] 9 | [IgnoreAudit] 10 | [Index(nameof(TransactionId))] 11 | [Index(nameof(OperateTime))] 12 | public class AuditLog 13 | { 14 | [Comment("主键")] 15 | [DatabaseGenerated(DatabaseGeneratedOption.None)] 16 | public Guid Id { get; set; } 17 | 18 | [Comment("事务Id")] 19 | public Guid TransactionId { get; set; } 20 | 21 | [Comment("用户Id")] 22 | public int UserId { get; set; } 23 | 24 | [Comment("实体名称")] 25 | public string EntityName { get; set; } = null!; 26 | 27 | [Comment("2删除 3修改 4添加")] 28 | public int Operation { get; set; } 29 | 30 | [Comment("操作时间")] 31 | public DateTime OperateTime { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Log/AuditLogDetail.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Log 6 | { 7 | [Table("LOG_AUDIT_DETAIL")] 8 | [Comment("审计日志详情")] 9 | [IgnoreAudit] 10 | [Index(nameof(AuditLogId))] 11 | public class AuditLogDetail 12 | { 13 | [Comment("主键")] 14 | public int Id { get; set; } 15 | 16 | [Comment("审计日志Id")] 17 | public Guid AuditLogId { get; set; } 18 | 19 | [Comment("实体名称")] 20 | public string EntityName { get; set; } = null!; 21 | 22 | [Comment("属性名")] 23 | public string PropertyName { get; set; } = null!; 24 | 25 | [Comment("旧值")] 26 | public string? OldValue { get; set; } 27 | 28 | [Comment("新值")] 29 | public string? NewValue { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Log/LoginLog.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorAdmin.Servers.Core.Data.Entities.Log 6 | { 7 | [Table("LOG_LOGIN")] 8 | [Comment("登录日志")] 9 | [Index(nameof(UserName))] 10 | [Index(nameof(Time))] 11 | [IgnoreAudit] 12 | public class LoginLog 13 | { 14 | [Comment("主键")] 15 | public int Id { get; set; } 16 | 17 | [Comment("登录名")] 18 | public string UserName { get; set; } = null!; 19 | 20 | [Comment("登录时间")] 21 | public DateTime Time { get; set; } 22 | 23 | [Comment("登录客户端")] 24 | public string? Agent { get; set; } 25 | 26 | [Comment("登录IP")] 27 | public string? Ip { get; set; } 28 | 29 | [Comment("是否成功")] 30 | public bool IsSuccessd { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Notification/Notification.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Notification 5 | { 6 | /// 7 | /// 系统通知实体 8 | /// 9 | [IgnoreAudit] 10 | public class Notification 11 | { 12 | /// 13 | /// 主键Id 14 | /// 15 | [Key] 16 | public int Id { get; set; } 17 | 18 | /// 19 | /// 通知标题 20 | /// 21 | public string Title { get; set; } = string.Empty; 22 | 23 | /// 24 | /// 通知内容 25 | /// 26 | public string Content { get; set; } = string.Empty; 27 | 28 | /// 29 | /// 发送者Id 30 | /// 31 | public int SenderId { get; set; } 32 | 33 | /// 34 | /// 发送时间 35 | /// 36 | public DateTime SendTime { get; set; } 37 | 38 | /// 39 | /// 通知类型(1:系统通知 2:个人通知) 40 | /// 41 | public int Type { get; set; } 42 | 43 | /// 44 | /// 通知状态(0:草稿 1:已发送) 45 | /// 46 | public int Status { get; set; } 47 | } 48 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Notification/NotificationReceiver.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Attributes; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Notification 5 | { 6 | /// 7 | /// 通知接收记录实体 8 | /// 9 | [IgnoreAudit] 10 | public class NotificationReceiver 11 | { 12 | /// 13 | /// 主键Id 14 | /// 15 | [Key] 16 | public int Id { get; set; } 17 | 18 | /// 19 | /// 通知Id 20 | /// 21 | public int NotificationId { get; set; } 22 | 23 | /// 24 | /// 接收者Id 25 | /// 26 | public int ReceiverId { get; set; } 27 | 28 | /// 29 | /// 是否已读 30 | /// 31 | public bool IsRead { get; set; } 32 | 33 | /// 34 | /// 阅读时间 35 | /// 36 | public DateTime? ReadTime { get; set; } 37 | } 38 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/Menu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_MENU")] 7 | [Comment("菜单")] 8 | public class Menu 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("上级ID")] 14 | public int? ParentId { get; set; } 15 | 16 | [Comment("菜单图标")] 17 | public string? Icon { get; set; } 18 | 19 | [Comment("菜单名称")] 20 | public string? Name { get; set; } 21 | 22 | [Comment("类型 1 菜单 2按钮")] 23 | public int Type { get; set; } 24 | 25 | [Comment("路由")] 26 | public string? Route { get; set; } 27 | 28 | [Comment("元素标识")] 29 | public string? Identify { get; set; } 30 | 31 | [Comment("排序")] 32 | public int Order { get; set; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/Organization.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_ORGANIZATION")] 7 | [Comment("组织")] 8 | public class Organization 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("上级ID")] 14 | public int? ParentId { get; set; } 15 | 16 | [Comment("组织名称")] 17 | public string Name { get; set; } = null!; 18 | 19 | [Comment("排序")] 20 | public int Order { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/OrganizationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_ORGANIZATION_USER")] 7 | [Comment("组织用户")] 8 | public class OrganizationUser 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("组织Id")] 14 | public int OrganizationId { get; set; } 15 | 16 | [Comment("用户Id")] 17 | public int UserId { get; set; } 18 | 19 | [Comment("是否是负责人")] 20 | public bool IsLeader { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/Role.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_ROLE")] 7 | [Comment("角色")] 8 | public class Role 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("角色名")] 14 | public string? Name { get; set; } 15 | 16 | [Comment("是否启用")] 17 | public bool IsEnabled { get; set; } 18 | 19 | [Comment("是否删除")] 20 | public bool IsDeleted { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/RoleMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_ROLE_MENU")] 7 | [Comment("角色的菜单")] 8 | public class RoleMenu 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("角色id")] 14 | public int RoleId { get; set; } 15 | 16 | [Comment("菜单id")] 17 | public int MenuId { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/User.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_USER")] 7 | [Comment("用户")] 8 | public class User 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("用户头像")] 14 | public string? Avatar { get; set; } 15 | 16 | [Comment("用户名")] 17 | public string Name { get; set; } = null!; 18 | 19 | [Comment("姓名")] 20 | public string RealName { get; set; } = null!; 21 | 22 | [Comment("密码哈希")] 23 | public string PasswordHash { get; set; } = null!; 24 | 25 | [Comment("电子邮件")] 26 | public string? Email { get; set; } 27 | 28 | [Comment("手机号码")] 29 | public string? PhoneNumber { get; set; } 30 | 31 | [Comment("是否启用")] 32 | public bool IsEnabled { get; set; } 33 | 34 | [Comment("是否删除")] 35 | public bool IsDeleted { get; set; } 36 | 37 | [Comment("是否是特殊用户")] 38 | public bool IsSpecial { get; set; } 39 | 40 | [Comment("一定时间内登录失败次数")] 41 | public DateTime? LoginValiedTime { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Rbac/UserRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Rbac 5 | { 6 | [Table("RBAC_USER_ROLE")] 7 | [Comment("用户角色")] 8 | public class UserRole 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("用户id")] 14 | public int UserId { get; set; } 15 | 16 | [Comment("角色id")] 17 | public int RoleId { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Setting/Setting.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Setting 5 | { 6 | [Table("SYSTEM_SETTING")] 7 | [Comment("系统设置")] 8 | public class Setting 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("键")] 14 | public string Key { get; set; } = null!; 15 | 16 | [Comment("值")] 17 | public string Value { get; set; } = null!; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Entities/Setting/UserSetting.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Entities.Setting 5 | { 6 | [Table("SYSTEM_USER_SETTING")] 7 | [Comment("用户设置")] 8 | public class UserSetting 9 | { 10 | [Comment("主键")] 11 | public int Id { get; set; } 12 | 13 | [Comment("用户")] 14 | public int UserId { get; set; } 15 | 16 | [Comment("键")] 17 | public string Key { get; set; } = null!; 18 | 19 | [Comment("值")] 20 | public string Value { get; set; } = null!; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Extensions/OrganizationSetExtensions.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Rbac; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Extensions 5 | { 6 | public static class OrganizationSetExtensions 7 | { 8 | public static List GetAllSubOrganiations(this DbSet organizations, int orgId) 9 | { 10 | var orgList = organizations.AsNoTracking().ToList(); 11 | return GetSubOrganiationIdRecursive(orgList, orgId); 12 | } 13 | 14 | private static List GetSubOrganiationIdRecursive(this List organizations, int orgId) 15 | { 16 | var result = new List(); 17 | var findOrg = organizations.FirstOrDefault(o => o.Id == orgId); 18 | if (findOrg != null) 19 | { 20 | result.Add(findOrg); 21 | } 22 | result.AddRange(organizations.Where(o => o.ParentId == orgId) 23 | .SelectMany(o => GetSubOrganiationIdRecursive(organizations, o.Id))); 24 | return result; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Data/Extensions/SettingSetExtensions.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Entities.Setting; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace BlazorAdmin.Servers.Core.Data.Extensions 5 | { 6 | public static class SettingSetExtensions 7 | { 8 | public static string? GetSettingValue(this DbSet settings, string key) 9 | { 10 | return settings.FirstOrDefault(s => s.Key == key)?.Value; 11 | } 12 | 13 | public static void SetSettingValue(this DbSet settings, string key, string? value) 14 | { 15 | var setting = settings.FirstOrDefault(s => s.Key == key); 16 | if (setting == null) 17 | { 18 | settings.Add(new Setting { Key = key, Value = value ?? string.Empty }); 19 | } 20 | else 21 | { 22 | setting.Value = value ?? string.Empty; 23 | settings.Update(setting); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Dynamic/DynamicEntityAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Dynamic 2 | { 3 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 4 | public class DynamicEntityAttribute : Attribute 5 | { 6 | public string? Title { get; set; } 7 | 8 | public bool HaveNumberColumn { get; set; } = true; 9 | 10 | public bool AllowEdit { get; set; } 11 | 12 | public bool AllowDelete { get; set; } 13 | 14 | public bool AllowAdd { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Dynamic/DynamicEntityInfo.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Dynamic 2 | { 3 | public class DynamicEntityInfo 4 | { 5 | public string EntityName { get; set; } = null!; 6 | 7 | public Type EntityType { get; set; } = null!; 8 | 9 | public bool HaveNumberColumn { get; set; } = true; 10 | 11 | public string? Title { get; set; } 12 | 13 | public bool AllowEdit { get; set; } = true; 14 | 15 | public bool AllowDelete { get; set; } = true; 16 | 17 | public bool AllowAdd { get; set; } = true; 18 | 19 | public List DynamicPropertyInfos { get; set; } = new(); 20 | } 21 | 22 | public class DynamicPropertyInfo 23 | { 24 | public string PropertyName { get; set; } = null!; 25 | 26 | public Type PropertyType { get; set; } = null!; 27 | 28 | public string? Title { get; set; } 29 | 30 | public string? Format { get; set; } 31 | 32 | public int Order { get; set; } 33 | 34 | public bool IsKey { get; set; } 35 | 36 | public bool IsDisplay { get; set; } = true; 37 | 38 | public bool AllowEdit { get; set; } = true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Dynamic/DynamicPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Dynamic 2 | { 3 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 4 | public class DynamicPropertyAttribute : Attribute 5 | { 6 | public string? Title { get; set; } 7 | 8 | public string? Format { get; set; } 9 | 10 | public int Order { get; set; } 11 | 12 | public bool IsKey { get; set; } 13 | 14 | public bool IsDisplay { get; set; } = true; 15 | 16 | public bool AllowEdit { get; set; } = true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Extension/ClaimsPrincipalExtensions.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Constants; 2 | using System.Security.Claims; 3 | 4 | namespace BlazorAdmin.Servers.Core.Extension 5 | { 6 | public static class ClaimsPrincipalExtensions 7 | { 8 | public static int GetUserId(this ClaimsPrincipal user) 9 | { 10 | var userId = user.Claims.FirstOrDefault(c => c.Type == ClaimConstant.UserId)!.Value; 11 | return int.Parse(userId); 12 | } 13 | 14 | public static string GetUserName(this ClaimsPrincipal user) 15 | { 16 | return user.Claims.FirstOrDefault(c => c.Type == ClaimConstant.UserName)!.Value; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Extension/QueryableExtension.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Extension; 2 | using System.Linq.Expressions; 3 | 4 | namespace BlazorAdmin.Servers.Core.Extension 5 | { 6 | public static class QueryableExtension 7 | { 8 | public static IQueryable And(this IQueryable queryable, Expression> predicate) where T : class 9 | => queryable.Where(predicate); 10 | 11 | public static IQueryable AndIf(this IQueryable queryable, bool condition, Expression> predicate) where T : class 12 | => condition ? queryable.Where(predicate) : queryable; 13 | 14 | public static IQueryable AndIfExist(this IQueryable queryable, string? value, 15 | Expression> predicate) where T : class 16 | => string.IsNullOrEmpty(value) ? queryable : queryable.Where(predicate); 17 | 18 | public static IQueryable AndIfExist(this IQueryable queryable, TData value, 19 | Expression> predicate) where T : class 20 | => value is null ? queryable : queryable.Where(predicate); 21 | 22 | public static IQueryable OrderBy(this IQueryable queryable, params (Expression>, bool)[] keySelectors) where T : class 23 | { 24 | foreach (var keySelector in keySelectors) 25 | { 26 | if (queryable is IOrderedQueryable) 27 | { 28 | queryable = keySelector.Item2 ? 29 | (queryable as IOrderedQueryable).ThenBy(keySelector.Item1) : 30 | (queryable as IOrderedQueryable).ThenByDescending(keySelector.Item1); 31 | } 32 | else 33 | { 34 | queryable = keySelector.Item2 ? 35 | queryable.OrderBy(keySelector.Item1) : 36 | queryable.OrderByDescending(keySelector.Item1); 37 | 38 | } 39 | } 40 | return queryable; 41 | } 42 | 43 | public static IQueryable QueryPage(this IQueryable queryable, int page, int size) 44 | { 45 | return queryable.Skip((page - 1) * size).Take(size); 46 | } 47 | 48 | public static IList AndIf(this IList queryable, bool condition, Func predicate) where T : class 49 | => condition ? queryable.Where(predicate).ToList() : queryable; 50 | } 51 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/ChannelHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Channels; 2 | 3 | namespace BlazorAdmin.Servers.Core.Helper 4 | { 5 | public class ChannelHelper 6 | { 7 | private static readonly Lazy> lazy = 8 | new(() => new ChannelHelper()); 9 | 10 | private readonly ChannelWriter _writer; 11 | private readonly ChannelReader _reader; 12 | 13 | static ChannelHelper() 14 | { 15 | } 16 | 17 | private ChannelHelper() 18 | { 19 | var channelOptions = new BoundedChannelOptions(1000) 20 | { 21 | // 满了后的行为 22 | FullMode = BoundedChannelFullMode.DropOldest, 23 | SingleWriter = false 24 | }; 25 | var channel = Channel.CreateBounded(channelOptions); 26 | _writer = channel.Writer; 27 | _reader = channel.Reader; 28 | } 29 | 30 | public static ChannelHelper Instance 31 | { 32 | get 33 | { 34 | return lazy.Value; 35 | } 36 | } 37 | 38 | public ChannelWriter Writer => _writer; 39 | 40 | public ChannelReader Reader => _reader; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/EventHelper.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Helper 2 | { 3 | public class EventHelper 4 | { 5 | public TModel? Data { get; private set; } 6 | 7 | public event Func? OnChange; 8 | 9 | public void NotifyStateChanged(TModel model) 10 | { 11 | Data = model; 12 | OnChange?.Invoke(model); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/HashHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | 4 | namespace BlazorAdmin.Servers.Core.Helper 5 | { 6 | public static class HashHelper 7 | { 8 | public static string HashPwd(string pwd) 9 | { 10 | byte[] salt = new byte[16]; // 生成16字节的随机盐 11 | RandomNumberGenerator.Create().GetBytes(salt); 12 | 13 | // 使用PBKDF2算法生成哈希值 14 | var pbkdf2 = new Rfc2898DeriveBytes(pwd, salt, 10000, HashAlgorithmName.SHA256); 15 | byte[] hash = pbkdf2.GetBytes(32); 16 | return Encoding.UTF8.GetString(hash); 17 | } 18 | 19 | public static string HashPassword(string password) 20 | { 21 | var salt = new byte[16]; 22 | RandomNumberGenerator.Create().GetBytes(salt); 23 | using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256); 24 | var saltString = Convert.ToBase64String(salt); 25 | var hashString = Convert.ToBase64String(pbkdf2.GetBytes(32)); 26 | return $"{saltString}:{hashString}"; 27 | } 28 | 29 | public static bool VerifyPassword(string hashPwd, string password) 30 | { 31 | string[] passwordParts = hashPwd.Split(':', 2); 32 | byte[] salt = Convert.FromBase64String(passwordParts.First()); 33 | byte[] hash = Convert.FromBase64String(passwordParts.Last()); 34 | 35 | using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256); 36 | return pbkdf2.GetBytes(32).SequenceEqual(hash); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/RandomHelper.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Servers.Core.Helper 2 | { 3 | public static class RandomHelper 4 | { 5 | public static string RandomNumber(int length) 6 | { 7 | if (length > 9) 8 | { 9 | length = 9; 10 | } 11 | if (length < 4) 12 | { 13 | length = 4; 14 | } 15 | var random = new Random(); 16 | 17 | int number = random.Next((int)Math.Pow(10, length - 1), (int)Math.Pow(10, length) - 1); 18 | return number.ToString(); 19 | } 20 | 21 | public static string RandomString(int length) 22 | { 23 | const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 24 | var random = new Random(); 25 | return new string(Enumerable.Repeat(chars, length) 26 | .Select(s => s[random.Next(s.Length)]).ToArray()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/ReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.SqlTypes; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace BlazorAdmin.Core.Helper 10 | { 11 | public static class ReflectionHelper 12 | { 13 | public static int GetNonNullPropertyCount(object obj) 14 | { 15 | if (obj == null) 16 | { 17 | throw new ArgumentNullException(nameof(obj)); 18 | } 19 | 20 | int count = 0; 21 | Type type = obj.GetType(); 22 | PropertyInfo[] properties = type.GetProperties( 23 | BindingFlags.DeclaredOnly | 24 | BindingFlags.Public | 25 | BindingFlags.Instance); 26 | 27 | 28 | foreach (PropertyInfo property in properties) 29 | { 30 | object value = property.GetValue(obj); 31 | if (value != null && !IsEmpty(value)) 32 | { 33 | count++; 34 | } 35 | } 36 | 37 | return count; 38 | } 39 | 40 | private static bool IsEmpty(object value) 41 | { 42 | if (value == null) 43 | return true; 44 | 45 | var type = value.GetType(); 46 | 47 | if (type.IsArray) 48 | { 49 | var asArray = (Array)value; 50 | return asArray.Length == 0; 51 | } 52 | 53 | if (typeof(System.Collections.ICollection).IsAssignableFrom(type)) 54 | { 55 | var asICollection = (System.Collections.ICollection)value; 56 | return asICollection.Count == 0; 57 | } 58 | 59 | if (type == typeof(string)) 60 | { 61 | return string.IsNullOrEmpty((string)value); 62 | } 63 | 64 | return false; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Helper/SeleniumHelper.cs: -------------------------------------------------------------------------------- 1 | using OpenQA.Selenium; 2 | using OpenQA.Selenium.Edge; 3 | 4 | namespace BlazorAdmin.Servers.Core.Helper 5 | { 6 | public static class SeleniumHelper 7 | { 8 | // var author = driver.FindElement(By.CssSelector("a[rel='author']"))?.Text; 9 | // driver.Quit() 10 | public static EdgeDriver InitialEdgeDriver(string url, bool isHeadless = false) 11 | { 12 | var edgeOptions = new EdgeOptions(); 13 | edgeOptions.PageLoadStrategy = PageLoadStrategy.Eager; // 或者 14 | 15 | if (isHeadless) 16 | { 17 | edgeOptions.AddArgument("--headless"); 18 | edgeOptions.AddArgument("--disable-gpu"); 19 | } 20 | 21 | var driver = new EdgeDriver(edgeOptions); 22 | driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(5000); 23 | 24 | driver.Navigate().GoToUrl(url); 25 | 26 | IWindow window = driver.Manage().Window; 27 | window.Maximize(); 28 | 29 | return driver; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Modules/IModule.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace BlazorAdmin.Servers.Core.Modules 5 | { 6 | public interface IModule 7 | { 8 | public IServiceCollection Add(IServiceCollection services) => services; 9 | 10 | public WebApplication Use(WebApplication app) => app; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Services/LoopBackgroundService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | 3 | namespace BlazorAdmin.Servers.Core.Services 4 | { 5 | public abstract class LoopBackgroundService : BackgroundService 6 | { 7 | protected int IntervalMilliSeconds { get; set; } = 1000; 8 | 9 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 10 | { 11 | await Task.Yield(); 12 | while (!stoppingToken.IsCancellationRequested) 13 | { 14 | await Task.Delay(IntervalMilliSeconds, stoppingToken); 15 | await ExecuteLoopBodyAsync(stoppingToken); 16 | } 17 | } 18 | 19 | protected abstract Task ExecuteLoopBodyAsync(CancellationToken stoppingToken); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Servers.Core/Services/TestJob.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Quartz; 3 | 4 | namespace BlazorAdmin.Servers.Core.Services 5 | { 6 | public class TestJob : IJob 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public TestJob(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public async Task Execute(IJobExecutionContext context) 16 | { 17 | _logger.LogInformation("TestJob executed at {0}", DateTime.Now); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/BlazorAdmin.Web.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | enable 5 | enable 6 | Linux 7 | none 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/App.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 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 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/App.razor.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace BlazorAdmin.Web.Components 3 | { 4 | public partial class App 5 | { 6 | protected override async Task OnInitializedAsync() 7 | { 8 | await base.OnInitializedAsync(); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/AuthorizedLayout.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Layout.Components.Culture 2 | @using BlazorAdmin.Layout.Components.NavMenus 3 | @using BlazorAdmin.Layout.Components.NavTabs 4 | @using BlazorAdmin.Layout.Components.Notification 5 | @using BlazorAdmin.Layout.Components.Themes 6 | @using BlazorAdmin.Layout.Components.UserAvatar 7 | @using BlazorAdmin.Servers.Core.Helper 8 | @using BlazorAdmin.Servers.Core.States 9 | @using BlazorAdmin.Web.Components.Shared 10 | @using MudBlazor.Utilities 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | @Child 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/AuthorizedLayout.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace BlazorAdmin.Web.Components.Layout 4 | { 5 | public partial class AuthorizedLayout 6 | { 7 | [Parameter] public RenderFragment? Child { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/EmptyLayout.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Layout.Components.Themes 2 | @using BlazorAdmin.Servers.Core.Helper 3 | @using BlazorAdmin.Servers.Core.States 4 | @inherits LayoutComponentBase 5 | 6 | 7 | 8 |
9 | @Body 10 |
11 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/EmptyLayout.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace BlazorAdmin.Web.Components.Layout 4 | { 5 | public partial class EmptyLayout 6 | { 7 | [Parameter] public RenderFragment? ChildContent { get; set; } 8 | 9 | protected override async Task OnInitializedAsync() 10 | { 11 | await base.OnInitializedAsync(); 12 | } 13 | 14 | protected override async Task OnAfterRenderAsync(bool firstRender) 15 | { 16 | await base.OnAfterRenderAsync(firstRender); 17 | if (firstRender) 18 | { 19 | _themeState.IsDarkChangeEvent += StateHasChanged; 20 | _themeState.ThemeChangeEvent += StateHasChanged; 21 | _themeState.LoadTheme(); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Layout.Components.Themes 2 | @using BlazorAdmin.Servers.Core.Helper 3 | @using BlazorAdmin.Servers.Core.States 4 | @using BlazorAdmin.Web.Components.Shared 5 | @inherits LayoutComponentBase 6 | 7 | 8 | 9 | BlazorAdmin 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | @Body 19 | 20 | 21 | 22 | 23 | @Body 24 | 25 | 26 | 27 | 28 | 29 |
@context
30 |
31 |
32 | 33 |
34 | An unhandled error has occurred. 35 | Reload 36 | 🗙 37 |
38 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Layout/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row ::deep .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | text-decoration: none; 28 | } 29 | 30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { 31 | text-decoration: underline; 32 | } 33 | 34 | .top-row ::deep a:first-child { 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | } 38 | 39 | @media (max-width: 640.98px) { 40 | .top-row { 41 | justify-content: space-between; 42 | } 43 | 44 | .top-row ::deep a, .top-row ::deep .btn-link { 45 | margin-left: 0; 46 | } 47 | } 48 | 49 | @media (min-width: 641px) { 50 | .page { 51 | flex-direction: row; 52 | } 53 | 54 | .sidebar { 55 | width: 250px; 56 | height: 100vh; 57 | position: sticky; 58 | top: 0; 59 | } 60 | 61 | .top-row { 62 | position: sticky; 63 | top: 0; 64 | z-index: 1; 65 | } 66 | 67 | .top-row.auth ::deep a:first-child { 68 | flex: 1; 69 | text-align: right; 70 | width: 0; 71 | } 72 | 73 | .top-row, article { 74 | padding-left: 2rem !important; 75 | padding-right: 1.5rem !important; 76 | } 77 | } 78 | 79 | #blazor-error-ui { 80 | bottom: 0; 81 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 82 | display: none; 83 | left: 0; 84 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 9000; 88 | } 89 | 90 | #blazor-error-ui .dismiss { 91 | cursor: pointer; 92 | position: absolute; 93 | right: 0.75rem; 94 | top: 0.5rem; 95 | } 96 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Pages/Error.razor: -------------------------------------------------------------------------------- 1 | @page "/Error" 2 | @using System.Diagnostics 3 | @using BlazorAdmin.Servers.Core.Helper 4 | @using BlazorAdmin.Servers.Core.States 5 | 6 | Error 7 | 8 |

Error.

9 |

An error occurred while processing your request.

10 | 11 | @if (ShowRequestId) 12 | { 13 |

14 | Request ID: @RequestId 15 |

16 | } 17 | 18 |

Development Mode

19 |

20 | Swapping to Development environment will display more detailed information about the error that occurred. 21 |

22 |

23 | The Development environment shouldn't be enabled for deployed applications. 24 | It can result in displaying sensitive information from exceptions to end users. 25 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 26 | and restarting the app. 27 |

28 | 29 | @code{ 30 | [CascadingParameter] 31 | private HttpContext? HttpContext { get; set; } 32 | 33 | private string? RequestId { get; set; } 34 | private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 35 | 36 | protected override void OnInitialized() => 37 | RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; 38 | } 39 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Pages/Home.razor.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Web.Components.Pages 2 | { 3 | public partial class Home 4 | { 5 | private string Value { get; } = """ 6 | ### BlazorAdmin 7 | 8 | A simple management project template written using Blazor and MudBlazor. 9 | 10 | --- 11 | 12 | #### Credentials: 13 | 14 | Username:BlazorAdmin 15 | 16 | Password:BlazorAdmin 17 | 18 | --- 19 | 20 | #### Features: 21 | 22 | - Support Interactive Auto Render Mode 23 | 24 | - Implemented RBAC 25 | 26 | - JWT Authentication 27 | 28 | - Built on Mudblazor 29 | 30 | - Theme light/dark switch 31 | 32 | - Localization 33 | 34 | - Audit/Login Log 35 | 36 | - Modularization 37 | 38 | --- 39 | 40 | #### Technology stack: 41 | 42 | - .NET 8 43 | 44 | - Blazor 45 | 46 | - MudBlazor 47 | 48 | - Entity Framework 8 49 | 50 | 51 | """; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Routes.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @using BlazorAdmin.Web.Components.Layout 4 | @using BlazorAdmin.Web.Components.Shared 5 | @using Microsoft.AspNetCore.Components.Authorization 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Routes.razor.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace BlazorAdmin.Web.Components 4 | { 5 | public partial class Routes 6 | { 7 | public static List AdditionalAssemblies = new List() 8 | { 9 | typeof(BlazorAdmin.Layout._Imports).Assembly, 10 | typeof(Rbac._Imports).Assembly, 11 | typeof(Log._Imports).Assembly, 12 | typeof(Setting._Imports).Assembly, 13 | typeof(About.Client._Imports).Assembly, 14 | typeof(Metric._Imports).Assembly, 15 | typeof(Ai._Imports).Assembly, 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/Loading.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @rendermode InteractiveServer 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/Loading.razor.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorAdmin.Web.Components.Shared 2 | { 3 | public partial class Loading 4 | { 5 | protected override Task OnInitializedAsync() 6 | { 7 | return base.OnInitializedAsync(); 8 | } 9 | 10 | protected override async Task OnAfterRenderAsync(bool firstRender) 11 | { 12 | await base.OnAfterRenderAsync(firstRender); 13 | if (firstRender) 14 | { 15 | _themeState.LoadTheme(); 16 | //await _authService.SetCurrentUser(); 17 | var state = await _stateProvider.GetAuthenticationStateAsync(); 18 | if (state.User.Identity == null || !state.User.Identity.IsAuthenticated) 19 | { 20 | _navManager.NavigateTo("/login"); 21 | } 22 | 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/LoggerErrorBoundary.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.AspNetCore.Components.Web; 3 | 4 | namespace BlazorAdmin.Web.Components.Shared 5 | { 6 | public class LoggerErrorBoundary : ErrorBoundary 7 | { 8 | [Inject] ILogger Logger { get; set; } = null!; 9 | 10 | protected override async Task OnErrorAsync(Exception exception) 11 | { 12 | Logger.LogError(exception, string.Empty); 13 | await base.OnErrorAsync(exception); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/NoAuthorizedPage.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | @using BlazorAdmin.Web.Components.Layout 4 | 5 | @rendermode InteractiveServer 6 | 7 | @layout EmptyLayout 8 | 9 | @page "/noauthorized" 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 | @Loc["NoAuhtorized_Text"] 48 | 49 | @Loc["NoAuhtorized_ChangeUserText"] 50 | 51 | 52 | 53 | 54 |
-------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/NoAuthorizedPage.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorAdmin.Servers.Core.Data.Constants; 2 | using Microsoft.JSInterop; 3 | 4 | namespace BlazorAdmin.Web.Components.Shared 5 | { 6 | public partial class NoAuthorizedPage 7 | { 8 | private async Task LogoutClick() 9 | { 10 | var cookieUtil = await _jsRuntime.InvokeAsync("import", "./js/cookieUtil.js"); 11 | await cookieUtil.InvokeVoidAsync("setCookie", CommonConstant.UserToken, string.Empty); 12 | 13 | _navManager.NavigateTo("/login", true); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/NoAuthorizedPage.razor.css: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | margin-bottom: 50px; 7 | } 8 | 9 | .tree { 10 | position: relative; 11 | width: 50px; 12 | height: 50px; 13 | transform-style: preserve-3d; 14 | transform: rotateX(-20deg) rotateY(30deg); 15 | animation: treeAnimate 5s linear infinite; 16 | } 17 | 18 | @keyframes treeAnimate { 19 | 0% { 20 | transform: rotateX(-20deg) rotateY(360deg); 21 | } 22 | 23 | 100% { 24 | transform: rotateX(-20deg) rotateY(0deg); 25 | } 26 | } 27 | 28 | .tree div { 29 | position: absolute; 30 | top: -50px; 31 | left: 0; 32 | width: 100%; 33 | height: 100%; 34 | transform-style: preserve-3d; 35 | transform: translateY(calc(25px * var(--x))) translateZ(0px); 36 | } 37 | 38 | .tree div.branch span { 39 | position: absolute; 40 | top: 0; 41 | left: 0; 42 | width: 100%; 43 | height: 100%; 44 | background: linear-gradient(90deg, #69c069, #77dd77); 45 | clip-path: polygon(50% 0%, 0% 100%, 100% 100%); 46 | border-bottom: 5px solid #00000019; 47 | transform-origin: bottom; 48 | transform: rotateY(calc(90deg * var(--i))) rotateX(30deg) translateZ(28.5px); 49 | } 50 | 51 | .tree div.stem span { 52 | position: absolute; 53 | top: 110px; 54 | /* updated top value */ 55 | left: calc(50% - 7.5px); 56 | width: 15px; 57 | height: 50%; 58 | background: linear-gradient(90deg, #bb4622, #df7214); 59 | border-bottom: 5px solid #00000019; 60 | transform-origin: bottom; 61 | transform: rotateY(calc(90deg * var(--i))) translateZ(7.5px); 62 | } 63 | 64 | .shadow { 65 | position: absolute; 66 | top: 0; 67 | left: 0; 68 | width: 100%; 69 | height: 100%; 70 | background: rgba(0, 0, 0, 0.4); 71 | filter: blur(20px); 72 | transform-style: preserve-3d; 73 | transform: rotateX(90deg) translateZ(-65px); 74 | } 75 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/NotFoundPage.razor: -------------------------------------------------------------------------------- 1 | @using BlazorAdmin.Servers.Core.Helper 2 | @using BlazorAdmin.Servers.Core.States 3 | 4 | 5 | 6 |
7 | @Loc["NotFound_Text"] 8 | @Loc["BackToHome_Text"] 9 |
10 | 11 | @code { 12 | public void BackToHome() 13 | { 14 | _navManager.NavigateTo("/", true); 15 | } 16 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/Shared/NotFoundPage.razor.css: -------------------------------------------------------------------------------- 1 | .loader { 2 | border: 0 solid transparent; 3 | border-radius: 50%; 4 | width: 100px; 5 | height: 100px; 6 | } 7 | 8 | .loader::before, 9 | .loader::after { 10 | content: ''; 11 | border: 7px solid #ccc; 12 | border-radius: 50%; 13 | width: inherit; 14 | height: inherit; 15 | position: absolute; 16 | animation: loader 2s linear infinite; 17 | opacity: 0; 18 | } 19 | 20 | .loader::before { 21 | animation-delay: 1s; 22 | } 23 | 24 | @keyframes loader { 25 | 0% { 26 | transform: scale(1); 27 | opacity: 0; 28 | } 29 | 30 | 50% { 31 | opacity: 1; 32 | } 33 | 34 | 100% { 35 | transform: scale(0); 36 | opacity: 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Components/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using BlazorAdmin.Layout.States 4 | @using BlazorAdmin.Servers.Core.Auth 5 | @using BlazorAdmin.Servers.Core.Chat 6 | @using BlazorAdmin.Servers.Core.Data 7 | @using BlazorAdmin.Servers.Core.Data.Constants 8 | @using BlazorAdmin.Servers.Core.Helper 9 | @using BlazorAdmin.Servers.Core.Resources 10 | @using BlazorAdmin.Servers.Core.Services 11 | @using BlazorAdmin.Servers.Core.States 12 | @using BlazorAdmin.Web 13 | @using BlazorAdmin.Web.Components 14 | @using Microsoft.AspNetCore.Authorization 15 | @using Microsoft.AspNetCore.Components.Authorization 16 | @using Microsoft.AspNetCore.Components.Forms 17 | @using Microsoft.AspNetCore.Components.Routing 18 | @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage 19 | @using Microsoft.AspNetCore.Components.Web 20 | @using Microsoft.AspNetCore.Components.Web.Virtualization 21 | @using Microsoft.EntityFrameworkCore 22 | @using Microsoft.Extensions.Localization 23 | @using Microsoft.JSInterop 24 | @using MudBlazor 25 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 26 | 27 | @inject IJSRuntime _jsRuntime; 28 | @inject IDbContextFactory _dbFactory; 29 | @inject IDialogService _dialogService; 30 | @inject ISnackbar _snackbarService; 31 | @inject IAccessService _accessService; 32 | @inject IHttpContextAccessor _httpAccessor; 33 | 34 | @inject ProtectedLocalStorage _localStorage; 35 | @inject NavigationManager _navManager; 36 | @inject AuthenticationStateProvider _stateProvider; 37 | @inject IStringLocalizer Loc; 38 | @inject IStringLocalizer _commonLoc; 39 | 40 | @inject JwtHelper _jwtHelper; 41 | @inject NotificationHelper _notificationHelper; 42 | @inject ExternalAuthService _authService; 43 | @inject ThemeState _themeState; 44 | @inject MessageSender _messageSender; 45 | 46 | @attribute [Authorize] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Controllers/CultureController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Localization; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace BlazorAdmin.Controllers 5 | { 6 | [Route("api/[controller]/[action]")] 7 | [ApiController] 8 | public class CultureController : ControllerBase 9 | { 10 | public IActionResult Set(string culture, string redirectUri) 11 | { 12 | if (culture != null) 13 | { 14 | HttpContext.Response.Cookies.Append( 15 | CookieRequestCultureProvider.DefaultCookieName, 16 | CookieRequestCultureProvider.MakeCookieValue( 17 | new RequestCulture(culture, culture))); 18 | } 19 | 20 | return LocalRedirect(redirectUri); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 4 | USER app 5 | WORKDIR /app 6 | EXPOSE 37318 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 9 | ARG BUILD_CONFIGURATION=Release 10 | WORKDIR /src 11 | COPY ["BlazorAdmin.Web/BlazorAdmin.Web.csproj", "BlazorAdmin.Web/"] 12 | COPY ["BlazorAdmin.Core/BlazorAdmin.Core.csproj", "BlazorAdmin.Core/"] 13 | COPY ["BlazorAdmin.Servers.Core.Data/BlazorAdmin.Servers.Core.Data.csproj", "BlazorAdmin.Servers.Core.Data/"] 14 | COPY ["BlazorAdmin.Modules/BlazorAdmin.Log/BlazorAdmin.Log.csproj", "BlazorAdmin.Modules/BlazorAdmin.Log/"] 15 | COPY ["BlazorAdmin.Modules/BlazorAdmin.Rbac/BlazorAdmin.Rbac.csproj", "BlazorAdmin.Modules/BlazorAdmin.Rbac/"] 16 | COPY ["BlazorAdmin.Modules/BlazorAdmin.Setting/BlazorAdmin.Setting.csproj", "BlazorAdmin.Modules/BlazorAdmin.Setting/"] 17 | RUN dotnet restore "./BlazorAdmin.Web/./BlazorAdmin.Web.csproj" 18 | COPY . . 19 | WORKDIR "/src/BlazorAdmin.Web" 20 | RUN dotnet build "./BlazorAdmin.Web.csproj" -c $BUILD_CONFIGURATION -o /app/build 21 | 22 | FROM build AS publish 23 | ARG BUILD_CONFIGURATION=Release 24 | RUN dotnet publish "./BlazorAdmin.Web.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 25 | 26 | FROM base AS final 27 | WORKDIR /app 28 | COPY --from=publish /app/publish . 29 | ENTRYPOINT ["dotnet", "BlazorAdmin.Web.dll"] -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aishang2015/BlazorAdmin/599d53e2f701a6abdd3f985a95093e8429ff3c20/src/BlazorAdmin/BlazorAdmin.Web/Program.cs -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "dotnetRunMessages": true, 10 | "applicationUrl": "http://localhost:5161" 11 | }, 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Docker": { 20 | "commandName": "Docker", 21 | "launchBrowser": true, 22 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", 23 | "environmentVariables": { 24 | "ASPNETCORE_HTTP_PORTS": "8080" 25 | }, 26 | "publishAllPorts": true 27 | } 28 | }, 29 | "$schema": "http://json.schemastore.org/launchsettings.json", 30 | "iisSettings": { 31 | "windowsAuthentication": false, 32 | "anonymousAuthentication": true, 33 | "iisExpress": { 34 | "applicationUrl": "http://localhost:8532", 35 | "sslPort": 0 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Kestrel": { 4 | "Endpoints": { 5 | "Http": { 6 | "Url": "http://0.0.0.0:37219" 7 | } 8 | } 9 | }, 10 | "Serilog": { 11 | "MinimumLevel": { 12 | "Default": "Information", 13 | "Override": { 14 | "Microsoft": "Warning", 15 | "Microsoft.Hosting.Lifetime": "Information", 16 | "Microsoft.AspNetCore": "Warning", 17 | "Microsoft.AspNetCore.Authentication": "Warning", 18 | "System": "Warning", 19 | 20 | // EF 21 | "Microsoft.EntityFrameworkCore.Infrastructure": "Information", 22 | "Microsoft.EntityFrameworkCore.Database.Connection": "Information", 23 | "Microsoft.EntityFrameworkCore.Database.Command": "Information", 24 | "Microsoft.EntityFrameworkCore.Database.Transaction": "Information", 25 | 26 | // Quartz 27 | "Quartz": "Warning" 28 | } 29 | }, 30 | "WriteTo": [ 31 | { "Name": "Console" }, 32 | { 33 | "Name": "File", 34 | "Args": { 35 | "path": "logs/log-.txt", 36 | "restrictedToMinimumLevel": "Debug", 37 | "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3} {SourceContext:l}] {Message:lj}{NewLine}{Exception}", 38 | "rollingInterval": "Day", 39 | "rollOnFileSizeLimit": true, 40 | "shared": true, 41 | "fileSizeLimitBytes": 10000000, 42 | "retainedFileCountLimit": 30 43 | } 44 | } 45 | ] 46 | }, 47 | "AllowedHosts": "*", 48 | "Application": { 49 | "DatabaseProvider": "Sqlite", // Supported values: Sqlite, SqlServer,PostgreSQL 50 | "ConnectionString": "Data Source=DB/BlazorAdmin20250522.db;Cache=Shared", 51 | "UseQuartz": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aishang2015/BlazorAdmin/599d53e2f701a6abdd3f985a95093e8429ff3c20/src/BlazorAdmin/BlazorAdmin.Web/wwwroot/favicon.png -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/wwwroot/images/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aishang2015/BlazorAdmin/599d53e2f701a6abdd3f985a95093e8429ff3c20/src/BlazorAdmin/BlazorAdmin.Web/wwwroot/images/back.jpg -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/wwwroot/js/common.js: -------------------------------------------------------------------------------- 1 | export function downloadFileFromBase64(base64String, fileName) { 2 | // 将base64字符串转换为Blob对象 3 | const byteCharacters = atob(base64String); 4 | const byteNumbers = new Array(byteCharacters.length); 5 | for (let i = 0; i < byteCharacters.length; i++) { 6 | byteNumbers[i] = byteCharacters.charCodeAt(i); 7 | } 8 | const byteArray = new Uint8Array(byteNumbers); 9 | const blob = new Blob([byteArray]); 10 | 11 | // 创建下载链接 12 | const downloadLink = document.createElement('a'); 13 | downloadLink.href = URL.createObjectURL(blob); 14 | downloadLink.download = fileName; 15 | 16 | // 添加到文档并触发点击 17 | document.body.appendChild(downloadLink); 18 | downloadLink.click(); 19 | 20 | // 清理 21 | document.body.removeChild(downloadLink); 22 | URL.revokeObjectURL(downloadLink.href); 23 | } -------------------------------------------------------------------------------- /src/BlazorAdmin/BlazorAdmin.Web/wwwroot/js/cookieUtil.js: -------------------------------------------------------------------------------- 1 | export function setCookie(key, value) { 2 | var cookies = document.cookie.split('; '); 3 | var isExist = false; 4 | for (var i = 0; i < cookies.length; i++) { 5 | var parts = cookies[i].split('='); 6 | if (parts[0] === key) { 7 | isExist = true; 8 | parts[1] = encodeURIComponent(value); 9 | document.cookie = parts.join('='); 10 | break; 11 | } 12 | } 13 | 14 | if (!isExist) { 15 | document.cookie = [key, encodeURIComponent(value)].join('='); 16 | } 17 | } 18 | 19 | export function getCookie(key) { 20 | var cookies = document.cookie.split('; '); 21 | var value = ''; 22 | for (var i = 0; i < cookies.length; i++) { 23 | var parts = cookies[i].split('='); 24 | if (parts[0] === key) { 25 | value = decodeURIComponent(parts[1]); 26 | break; 27 | } 28 | } 29 | 30 | return value; 31 | } --------------------------------------------------------------------------------