From b1a69d50e71d039572d9d77d11b4ccfe8870f096 Mon Sep 17 00:00:00 2001
From: wanggang <76527413@qq.com>
Date: Mon, 26 Jun 2023 17:46:40 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E6=A1=A3=E5=92=8CUI?=
=?UTF-8?q?=E5=8E=9F=E5=9E=8B=E8=8F=9C=E5=8D=95=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/demo/.editorconfig | 536 +
docs/demo/.gitattributes | 3 +
docs/demo/.gitignore | 16 +
docs/demo/.vscode/launch.json | 35 +
docs/demo/.vscode/tasks.json | 41 +
docs/demo/Demo.sln | 48 +
docs/demo/Directory.Packages.props | 39 +
docs/demo/NuGet.Config | 7 +
docs/demo/README.md | 37 +
.../Captcha/CaptchaController.cs | 47 +
.../Controllers/ConnectionStringController.cs | 14 +
.../Controllers/PermissionController.cs | 14 +
.../Identity/Controllers/TenantController.cs | 14 +
.../Identity/Controllers/TokenController.cs | 208 +
.../Identity/Controllers/UserController.cs | 73 +
.../Identity/Data/IdentityConfiguration.cs | 90 +
.../Identity/Data/IdentityDbContext.cs | 12 +
.../Identity/Data/IdentityDbSeed.cs | 257 +
.../Identity/Entities/BaseData/Class1.cs | 642 +
.../Entities/SystemManagement/Department.cs | 12 +
.../SystemManagement/DictionaryItem.cs | 10 +
.../Entities/SystemManagement/Permission.cs | 32 +
.../SystemManagement/PermissionType.cs | 18 +
.../Entities/SystemManagement/Post.cs | 14 +
.../Entities/SystemManagement/Role.cs | 14 +
.../SystemManagement/RolePermission.cs | 20 +
.../Entities/SystemManagement/Token.cs | 9 +
.../Entities/SystemManagement/User.cs | 36 +
.../Entities/SystemManagement/UserRole.cs | 16 +
.../Entities/SystemManagementAttribute.cs | 8 +
.../Entities/Tenants/ConnectionString.cs | 17 +
.../Identity/Entities/Tenants/Tenant.cs | 18 +
.../Identity/Entities/TenantsAttribute.cs | 8 +
.../Identity/IdentityModule.cs | 16 +
.../Identity/Models/LoginRequestModel.cs | 40 +
.../Identity/Models/LoginResponseModel.cs | 18 +
.../Identity/Models/UserInfoModel.cs | 9 +
.../WTA.Application/Identity/TenantService.cs | 35 +
.../Localization/LocalizationController.cs | 46 +
.../Monitor/Controllers/Monitor.cs | 12 +
.../Monitor/Controllers/MonitorController.cs | 30 +
.../Controllers/SystemMonitorAttribute.cs | 8 +
.../Monitor/Entities/JobItem.cs | 15 +
.../Monitor/Entities/UserLogin.cs | 26 +
.../WTA.Application/Monitor/MonitorModule.cs | 9 +
.../Monitor/UserLoginSrevice.cs | 60 +
.../WTA.Application/WTA.Application.csproj | 7 +
.../src/WTA.Infrastructure/Resources/en.json | 16 +
.../src/WTA.Infrastructure/Resources/zh.json | 130 +
.../WTA.Infrastructure.csproj | 19 +
.../WTA.Shared/Application/IExportModel.cs | 5 +
.../WTA.Shared/Application/IImportModel.cs | 5 +
.../src/WTA.Shared/Application/IResource.cs | 5 +
.../Application/IResourceService.cs | 5 +
.../WTA.Shared/Application/PaginationModel.cs | 22 +
.../WTA.Shared/Attributes/AddOnlyAttribute.cs | 6 +
.../Attributes/ComponentAttribute.cs | 12 +
.../Attributes/DbContextAttribute.cs | 5 +
.../Attributes/DisplayOnlyAttribute.cs | 6 +
.../Attributes/ExpressionAttribute.cs | 12 +
.../WTA.Shared/Attributes/GenericAttribute.cs | 12 +
.../WTA.Shared/Attributes/GroupAttribute.cs | 6 +
.../WTA.Shared/Attributes/HiddenAttribute.cs | 6 +
.../Attributes/HtmlClassAttribute.cs | 13 +
.../WTA.Shared/Attributes/IconAttribute.cs | 14 +
.../Attributes/IgnoreMultiTenancyAttribute.cs | 6 +
.../Attributes/IgnoreUpdateAttribute.cs | 6 +
.../Attributes/ImplementAttribute.cs | 26 +
.../Attributes/ImporterHeaderAttribute.cs | 11 +
.../WTA.Shared/Attributes/ModuleAttribute.cs | 5 +
.../Attributes/MultipleAttribute.cs | 6 +
.../Attributes/NavigationAttribute.cs | 12 +
.../Attributes/OperatorTypeAttribute.cs | 16 +
.../WTA.Shared/Attributes/OptionsAttribute.cs | 12 +
.../WTA.Shared/Attributes/OrderAttribute.cs | 13 +
.../Authentication/AuthenticateResult.cs | 11 +
.../Authentication/CustomClaimsPrincipal.cs | 44 +
.../CustomJwtBearerPostConfigureOptions.cs | 21 +
.../CustomJwtSecurityTokenHandler.cs | 20 +
.../Authentication/IAuthenticationService.cs | 6 +
.../Authentication/IdentityOptions.cs | 14 +
.../src/WTA.Shared/Captcha/CaptchaService.cs | 20 +
.../src/WTA.Shared/Captcha/ICaptchaService.cs | 6 +
.../WTA.Shared/Controllers/BaseController.cs | 44 +
.../Controllers/ControllerModelConvention.cs | 36 +
.../Controllers/GenericController.cs | 193 +
.../GenericControllerFeatureProvider.cs | 32 +
...enericControllerNameConventionAttribute.cs | 28 +
.../GenericControllerRouteConvention.cs | 54 +
.../Controllers/HttpMethodDefaultAttribute.cs | 10 +
.../SlugifyParameterTransformer.cs | 12 +
.../demo/src/WTA.Shared/Data/BaseDbContext.cs | 237 +
docs/demo/src/WTA.Shared/Data/EfRepository.cs | 64 +
docs/demo/src/WTA.Shared/Data/IDbConfig.cs | 7 +
docs/demo/src/WTA.Shared/Data/IDbSeed.cs | 8 +
docs/demo/src/WTA.Shared/Data/IRepository.cs | 26 +
docs/demo/src/WTA.Shared/Data/OperatorType.cs | 42 +
.../CustomDisplayMetadataProvider.cs | 46 +
.../CustomModelMetaDataProvider.cs | 18 +
.../DataAnnotations/CustomModelMetadata.cs | 14 +
.../CustomValidationMetadataProvider.cs | 23 +
.../DependencyInjection/PlatformType.cs | 10 +
docs/demo/src/WTA.Shared/Domain/BaseEntity.cs | 63 +
.../src/WTA.Shared/Domain/BaseParentEntity.cs | 12 +
.../src/WTA.Shared/Domain/BaseTreeEntity.cs | 23 +
.../src/WTA.Shared/Domain/BaseViewEntity.cs | 7 +
.../src/WTA.Shared/Domain/IAuditEntity.cs | 11 +
.../demo/src/WTA.Shared/Domain/IBaseEntity.cs | 9 +
.../WTA.Shared/Domain/ISoftDeleteEntity.cs | 6 +
.../WTA.Shared/Domain/PropertyAttribute.cs | 20 +
.../demo/src/WTA.Shared/EventBus/BaseEvent.cs | 17 +
.../EventBus/DefaultEventPublisher.cs | 31 +
.../WTA.Shared/EventBus/EntityCreatedEvent.cs | 8 +
.../WTA.Shared/EventBus/EntityDeletedEvent.cs | 8 +
.../WTA.Shared/EventBus/EntityUpdatedEvent.cs | 8 +
.../src/WTA.Shared/EventBus/IEventHander.cs | 6 +
.../WTA.Shared/EventBus/IEventPublisher.cs | 6 +
.../ClosedXmlExportImportService.cs | 140 +
.../ExportImport/IExportImportService.cs | 12 +
.../Extensions/BaseEntityExtensions.cs | 43 +
.../WTA.Shared/Extensions/DbSetExtensions.cs | 19 +
.../Extensions/DictionaryExtensions.cs | 12 +
.../Extensions/DisplayExtensions.cs | 42 +
.../WTA.Shared/Extensions/EnumExtensions.cs | 14 +
.../Extensions/EnumerableExtensions.cs | 9 +
.../WTA.Shared/Extensions/HubExtensions.cs | 11 +
.../WTA.Shared/Extensions/JsonExtensions.cs | 21 +
.../Extensions/JsonSchemaExtensions.cs | 342 +
.../Extensions/ModelBuilderExtensions.cs | 23 +
.../ModelStateDictionaryExtensions.cs | 13 +
.../Extensions/NullabilityExtensions.cs | 22 +
.../WTA.Shared/Extensions/ObjectExtensions.cs | 9 +
.../Extensions/QueryableExtensions.cs | 110 +
.../Extensions/ServiceProviderExtensions.cs | 98 +
.../WTA.Shared/Extensions/StringExtensions.cs | 97 +
.../WTA.Shared/Extensions/TypeExtensions.cs | 33 +
.../GuidGenerators/GuidGenerator.cs | 58 +
.../GuidGenerators/IGuidGenerator.cs | 6 +
.../GuidGenerators/SequentialGuidType.cs | 19 +
.../WTA.Shared/Identity/IPasswordHasher.cs | 8 +
.../src/WTA.Shared/Identity/PasswordHasher.cs | 24 +
docs/demo/src/WTA.Shared/Job/IJobService.cs | 6 +
.../Localization/JsonStringLocalizer.cs | 84 +
.../JsonStringLocalizerFactory.cs | 18 +
.../src/WTA.Shared/Mappers/FromInjection.cs | 32 +
.../src/WTA.Shared/Mappers/IObjectMapper.cs | 8 +
.../Mappers/ObjectMapperExtensions.cs | 31 +
.../src/WTA.Shared/Mappers/ToInjection.cs | 67 +
.../WTA.Shared/Mappers/ValueInjecterMapper.cs | 34 +
docs/demo/src/WTA.Shared/Module/BaseModule.cs | 14 +
.../src/WTA.Shared/Monitor/BaseService.cs | 56 +
.../src/WTA.Shared/Monitor/IMonitorService.cs | 6 +
.../src/WTA.Shared/Monitor/LinuxService.cs | 165 +
.../Monitor/MonitorHostedService.cs | 59 +
.../src/WTA.Shared/Monitor/MonitorModel.cs | 78 +
.../src/WTA.Shared/Monitor/WindowsService.cs | 96 +
.../Options/EmbeddedConfigureOptions.cs | 26 +
.../demo/src/WTA.Shared/Resources/Resource.cs | 5 +
.../src/WTA.Shared/Resources/calibril.ttf | Bin 0 -> 1471248 bytes
docs/demo/src/WTA.Shared/SignalR/PageHub.cs | 83 +
.../WTA.Shared/SignalR/SignalCommandREvent.cs | 9 +
.../SignalR/SignalRConnectedEvent.cs | 9 +
.../SignalR/SignalRDisconnectedEvent.cs | 7 +
.../SignalR/SignalRHeartbeatEvent.cs | 6 +
.../WTA.Shared/Swagger/CustomSwaggerFilter.cs | 36 +
.../Swagger/CustomSwaggerGenOptions.cs | 32 +
.../src/WTA.Shared/Tenants/ITenantService.cs | 8 +
docs/demo/src/WTA.Shared/WTA.Shared.csproj | 34 +
docs/demo/src/WTA.Shared/WebApp.cs | 673 +
docs/demo/src/WTA/.config/dotnet-tools.json | 12 +
.../src/WTA/Controllers/HomeController.cs | 16 +
docs/demo/src/WTA/Program.cs | 1 +
.../PublishProfiles/FolderProfile.pubxml | 22 +
.../src/WTA/Properties/launchSettings.json | 28 +
docs/demo/src/WTA/Views/Home/Index.cshtml | 1 +
docs/demo/src/WTA/WTA.csproj | 15 +
.../demo/src/WTA/appsettings.Development.json | 8 +
docs/demo/src/WTA/appsettings.json | 12 +
docs/demo/src/WTA/wwwroot/.eslintrc.json | 25 +
docs/demo/src/WTA/wwwroot/.prettierrc.json | 21 +
.../src/WTA/wwwroot/.vscode/extensions.json | 5 +
.../src/WTA/wwwroot/.vscode/settings.json | 6 +
docs/demo/src/WTA/wwwroot/api/user.js | 102 +
docs/demo/src/WTA/wwwroot/app.js | 26 +
docs/demo/src/WTA/wwwroot/assets/docs/test.md | 18 +
.../src/WTA/wwwroot/assets/icons/create.svg | 1 +
.../src/WTA/wwwroot/assets/icons/delete.svg | 1 +
.../src/WTA/wwwroot/assets/icons/details.svg | 1 +
.../src/WTA/wwwroot/assets/icons/export.svg | 1 +
.../src/WTA/wwwroot/assets/icons/file.svg | 1 +
.../src/WTA/wwwroot/assets/icons/fold.svg | 1 +
.../src/WTA/wwwroot/assets/icons/folder.svg | 1 +
.../wwwroot/assets/icons/fullscreen-exit.svg | 4 +
.../WTA/wwwroot/assets/icons/fullscreen.svg | 4 +
.../src/WTA/wwwroot/assets/icons/home.svg | 1 +
.../src/WTA/wwwroot/assets/icons/import.svg | 1 +
.../src/WTA/wwwroot/assets/icons/index.svg | 1 +
.../src/WTA/wwwroot/assets/icons/lang.svg | 1 +
.../src/WTA/wwwroot/assets/icons/unfold.svg | 1 +
.../src/WTA/wwwroot/assets/icons/update.svg | 1 +
docs/demo/src/WTA/wwwroot/assets/logo.svg | 4 +
.../src/WTA/wwwroot/components/chart/index.js | 37 +
.../WTA/wwwroot/components/form/form-input.js | 93 +
.../WTA/wwwroot/components/form/form-item.js | 93 +
.../src/WTA/wwwroot/components/form/index.js | 75 +
.../src/WTA/wwwroot/components/icon/index.js | 34 +
.../src/WTA/wwwroot/components/list/index.js | 390 +
.../WTA/wwwroot/components/markdown/index.js | 41 +
docs/demo/src/WTA/wwwroot/config/settings.js | 3 +
docs/demo/src/WTA/wwwroot/favicon.ico | Bin 0 -> 5430 bytes
docs/demo/src/WTA/wwwroot/index.html | 47 +
docs/demo/src/WTA/wwwroot/layouts/footer.js | 12 +
docs/demo/src/WTA/wwwroot/layouts/header.js | 168 +
docs/demo/src/WTA/wwwroot/layouts/index.js | 28 +
docs/demo/src/WTA/wwwroot/layouts/locale.js | 36 +
docs/demo/src/WTA/wwwroot/layouts/logo.js | 17 +
.../demo/src/WTA/wwwroot/layouts/menu-item.js | 55 +
docs/demo/src/WTA/wwwroot/layouts/menu.js | 24 +
.../lib/@element-plus/icons-vue/index.js | 9349 +++
.../lib/@microsoft/signalr/signalr.esm.js | 2568 +
.../wwwroot/lib/@vue-office/excel/index.css | 765 +
.../@vue-office/excel/vue-office-excel.mjs | 54424 ++++++++++++++++
.../WTA/wwwroot/lib/@vue/devtools-api/shim.js | 160 +
.../WTA/wwwroot/lib/@vueuse/core/index.mjs | 7387 +++
.../WTA/wwwroot/lib/@vueuse/shared/index.mjs | 1790 +
.../lib/better-mock/mock.browser.esm.js | 8842 +++
.../wwwroot/lib/detect-it/detect-it.esm.js | 8 +
.../wwwroot/lib/echarts/echarts.esm.min.js | 45 +
.../WTA/wwwroot/lib/element-plus/index.css | 1 +
.../lib/element-plus/index.full.min.mjs | 78 +
.../lib/element-plus/locale/en.min.mjs | 2 +
.../lib/element-plus/locale/zh-cn.min.mjs | 2 +
.../theme-chalk/dark/css-vars.css | 1 +
.../github-markdown.min.css | 881 +
.../WTA/wwwroot/lib/highlightjs/highlight.css | 111 +
.../wwwroot/lib/highlightjs/highlight.min.js | 1174 +
.../wwwroot/lib/jwt-decode/jwt-decode.esm.js | 2 +
.../demo/src/WTA/wwwroot/lib/linq/linq.min.js | 1 +
.../src/WTA/wwwroot/lib/lodash/lodash.esm.js | 18 +
.../src/WTA/wwwroot/lib/marked/marked.esm.js | 2778 +
.../wwwroot/lib/mermaid/mermaid.esm.min.mjs | 3 +
.../WTA/wwwroot/lib/nprogress/nprogress.css | 74 +
.../lib/nprogress/nprogress.vite-esm.js | 288 +
.../wwwroot/lib/pinia/pinia.esm-browser.js | 1987 +
.../WTA/wwwroot/lib/pubsub-js/pubsub.esm.js | 206 +
docs/demo/src/WTA/wwwroot/lib/qs/shim.js | 1837 +
.../WTA/wwwroot/lib/resize-detector/index.js | 314 +
.../wwwroot/lib/tailwindcss/tailwind.min.css | 1 +
.../demo/src/WTA/wwwroot/lib/vue-demi/shim.js | 34 +
.../wwwroot/lib/vue-echarts/index.esm.min.js | 2 +
.../lib/vue-i18n/vue-i18n.esm-browser.prod.js | 6 +
.../lib/vue-router/vue-router.esm-browser.js | 3613 +
.../WTA/wwwroot/lib/vue/vue.esm-browser.js | 15377 +++++
.../wwwroot/lib/vue/vue.esm-browser.prod.js | 1 +
docs/demo/src/WTA/wwwroot/locale/index.js | 13 +
docs/demo/src/WTA/wwwroot/main.css | 8 +
docs/demo/src/WTA/wwwroot/main.js | 20 +
docs/demo/src/WTA/wwwroot/mixins/style.js | 60 +
docs/demo/src/WTA/wwwroot/request/index.js | 97 +
.../src/WTA/wwwroot/resize-detector/index.js | 314 +
docs/demo/src/WTA/wwwroot/router/index.js | 143 +
docs/demo/src/WTA/wwwroot/signalr/index.js | 41 +
docs/demo/src/WTA/wwwroot/store/app.js | 31 +
docs/demo/src/WTA/wwwroot/store/index.js | 7 +
docs/demo/src/WTA/wwwroot/styles/site.css | 137 +
docs/demo/src/WTA/wwwroot/utils/index.js | 120 +
docs/demo/src/WTA/wwwroot/views/403.js | 3 +
docs/demo/src/WTA/wwwroot/views/404.js | 3 +
docs/demo/src/WTA/wwwroot/views/home.js | 7 +
docs/demo/src/WTA/wwwroot/views/list.js | 32 +
docs/demo/src/WTA/wwwroot/views/login.js | 44 +
docs/demo/src/WTA/wwwroot/views/monitor.js | 216 +
...®—ç³»ç»ŸæŠ€æœ¯è¦æ±‚2023.6.15 V1.1(1).docx | Bin 0 -> 20037 bytes
273 files changed, 124178 insertions(+)
create mode 100644 docs/demo/.editorconfig
create mode 100644 docs/demo/.gitattributes
create mode 100644 docs/demo/.gitignore
create mode 100644 docs/demo/.vscode/launch.json
create mode 100644 docs/demo/.vscode/tasks.json
create mode 100644 docs/demo/Demo.sln
create mode 100644 docs/demo/Directory.Packages.props
create mode 100644 docs/demo/NuGet.Config
create mode 100644 docs/demo/README.md
create mode 100644 docs/demo/src/WTA.Application/Captcha/CaptchaController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Controllers/ConnectionStringController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Controllers/PermissionController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Controllers/TenantController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Controllers/TokenController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Controllers/UserController.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Data/IdentityConfiguration.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Data/IdentityDbContext.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/BaseData/Class1.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Department.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/DictionaryItem.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Permission.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/PermissionType.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Post.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Role.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/RolePermission.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Token.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/User.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/UserRole.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/SystemManagementAttribute.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/Tenants/ConnectionString.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/Tenants/Tenant.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Entities/TenantsAttribute.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/IdentityModule.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Models/LoginRequestModel.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Models/LoginResponseModel.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/Models/UserInfoModel.cs
create mode 100644 docs/demo/src/WTA.Application/Identity/TenantService.cs
create mode 100644 docs/demo/src/WTA.Application/Localization/LocalizationController.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/Controllers/Monitor.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/Controllers/MonitorController.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/Controllers/SystemMonitorAttribute.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/Entities/JobItem.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/Entities/UserLogin.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/MonitorModule.cs
create mode 100644 docs/demo/src/WTA.Application/Monitor/UserLoginSrevice.cs
create mode 100644 docs/demo/src/WTA.Application/WTA.Application.csproj
create mode 100644 docs/demo/src/WTA.Infrastructure/Resources/en.json
create mode 100644 docs/demo/src/WTA.Infrastructure/Resources/zh.json
create mode 100644 docs/demo/src/WTA.Infrastructure/WTA.Infrastructure.csproj
create mode 100644 docs/demo/src/WTA.Shared/Application/IExportModel.cs
create mode 100644 docs/demo/src/WTA.Shared/Application/IImportModel.cs
create mode 100644 docs/demo/src/WTA.Shared/Application/IResource.cs
create mode 100644 docs/demo/src/WTA.Shared/Application/IResourceService.cs
create mode 100644 docs/demo/src/WTA.Shared/Application/PaginationModel.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/AddOnlyAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/ComponentAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/DbContextAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/DisplayOnlyAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/ExpressionAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/GenericAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/GroupAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/HiddenAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/HtmlClassAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/IconAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/IgnoreMultiTenancyAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/IgnoreUpdateAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/ImplementAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/ImporterHeaderAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/ModuleAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/MultipleAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/NavigationAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/OperatorTypeAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/OptionsAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Attributes/OrderAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/AuthenticateResult.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/CustomClaimsPrincipal.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/CustomJwtBearerPostConfigureOptions.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/CustomJwtSecurityTokenHandler.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/IAuthenticationService.cs
create mode 100644 docs/demo/src/WTA.Shared/Authentication/IdentityOptions.cs
create mode 100644 docs/demo/src/WTA.Shared/Captcha/CaptchaService.cs
create mode 100644 docs/demo/src/WTA.Shared/Captcha/ICaptchaService.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/BaseController.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/ControllerModelConvention.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/GenericController.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/GenericControllerFeatureProvider.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/GenericControllerNameConventionAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/GenericControllerRouteConvention.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/HttpMethodDefaultAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/Controllers/SlugifyParameterTransformer.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/BaseDbContext.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/EfRepository.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/IDbConfig.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/IDbSeed.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/IRepository.cs
create mode 100644 docs/demo/src/WTA.Shared/Data/OperatorType.cs
create mode 100644 docs/demo/src/WTA.Shared/DataAnnotations/CustomDisplayMetadataProvider.cs
create mode 100644 docs/demo/src/WTA.Shared/DataAnnotations/CustomModelMetaDataProvider.cs
create mode 100644 docs/demo/src/WTA.Shared/DataAnnotations/CustomModelMetadata.cs
create mode 100644 docs/demo/src/WTA.Shared/DataAnnotations/CustomValidationMetadataProvider.cs
create mode 100644 docs/demo/src/WTA.Shared/DependencyInjection/PlatformType.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/BaseEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/BaseParentEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/BaseTreeEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/BaseViewEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/IAuditEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/IBaseEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/ISoftDeleteEntity.cs
create mode 100644 docs/demo/src/WTA.Shared/Domain/PropertyAttribute.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/BaseEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/DefaultEventPublisher.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/EntityCreatedEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/EntityDeletedEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/EntityUpdatedEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/IEventHander.cs
create mode 100644 docs/demo/src/WTA.Shared/EventBus/IEventPublisher.cs
create mode 100644 docs/demo/src/WTA.Shared/ExportImport/ClosedXmlExportImportService.cs
create mode 100644 docs/demo/src/WTA.Shared/ExportImport/IExportImportService.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/BaseEntityExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/DbSetExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/DictionaryExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/DisplayExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/EnumExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/EnumerableExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/HubExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/JsonExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/JsonSchemaExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/ModelBuilderExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/ModelStateDictionaryExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/NullabilityExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/ObjectExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/QueryableExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/ServiceProviderExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/StringExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Extensions/TypeExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/GuidGenerators/GuidGenerator.cs
create mode 100644 docs/demo/src/WTA.Shared/GuidGenerators/IGuidGenerator.cs
create mode 100644 docs/demo/src/WTA.Shared/GuidGenerators/SequentialGuidType.cs
create mode 100644 docs/demo/src/WTA.Shared/Identity/IPasswordHasher.cs
create mode 100644 docs/demo/src/WTA.Shared/Identity/PasswordHasher.cs
create mode 100644 docs/demo/src/WTA.Shared/Job/IJobService.cs
create mode 100644 docs/demo/src/WTA.Shared/Localization/JsonStringLocalizer.cs
create mode 100644 docs/demo/src/WTA.Shared/Localization/JsonStringLocalizerFactory.cs
create mode 100644 docs/demo/src/WTA.Shared/Mappers/FromInjection.cs
create mode 100644 docs/demo/src/WTA.Shared/Mappers/IObjectMapper.cs
create mode 100644 docs/demo/src/WTA.Shared/Mappers/ObjectMapperExtensions.cs
create mode 100644 docs/demo/src/WTA.Shared/Mappers/ToInjection.cs
create mode 100644 docs/demo/src/WTA.Shared/Mappers/ValueInjecterMapper.cs
create mode 100644 docs/demo/src/WTA.Shared/Module/BaseModule.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/BaseService.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/IMonitorService.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/LinuxService.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/MonitorHostedService.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/MonitorModel.cs
create mode 100644 docs/demo/src/WTA.Shared/Monitor/WindowsService.cs
create mode 100644 docs/demo/src/WTA.Shared/Options/EmbeddedConfigureOptions.cs
create mode 100644 docs/demo/src/WTA.Shared/Resources/Resource.cs
create mode 100644 docs/demo/src/WTA.Shared/Resources/calibril.ttf
create mode 100644 docs/demo/src/WTA.Shared/SignalR/PageHub.cs
create mode 100644 docs/demo/src/WTA.Shared/SignalR/SignalCommandREvent.cs
create mode 100644 docs/demo/src/WTA.Shared/SignalR/SignalRConnectedEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/SignalR/SignalRDisconnectedEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/SignalR/SignalRHeartbeatEvent.cs
create mode 100644 docs/demo/src/WTA.Shared/Swagger/CustomSwaggerFilter.cs
create mode 100644 docs/demo/src/WTA.Shared/Swagger/CustomSwaggerGenOptions.cs
create mode 100644 docs/demo/src/WTA.Shared/Tenants/ITenantService.cs
create mode 100644 docs/demo/src/WTA.Shared/WTA.Shared.csproj
create mode 100644 docs/demo/src/WTA.Shared/WebApp.cs
create mode 100644 docs/demo/src/WTA/.config/dotnet-tools.json
create mode 100644 docs/demo/src/WTA/Controllers/HomeController.cs
create mode 100644 docs/demo/src/WTA/Program.cs
create mode 100644 docs/demo/src/WTA/Properties/PublishProfiles/FolderProfile.pubxml
create mode 100644 docs/demo/src/WTA/Properties/launchSettings.json
create mode 100644 docs/demo/src/WTA/Views/Home/Index.cshtml
create mode 100644 docs/demo/src/WTA/WTA.csproj
create mode 100644 docs/demo/src/WTA/appsettings.Development.json
create mode 100644 docs/demo/src/WTA/appsettings.json
create mode 100644 docs/demo/src/WTA/wwwroot/.eslintrc.json
create mode 100644 docs/demo/src/WTA/wwwroot/.prettierrc.json
create mode 100644 docs/demo/src/WTA/wwwroot/.vscode/extensions.json
create mode 100644 docs/demo/src/WTA/wwwroot/.vscode/settings.json
create mode 100644 docs/demo/src/WTA/wwwroot/api/user.js
create mode 100644 docs/demo/src/WTA/wwwroot/app.js
create mode 100644 docs/demo/src/WTA/wwwroot/assets/docs/test.md
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/create.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/delete.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/details.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/export.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/file.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/fold.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/folder.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/fullscreen-exit.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/fullscreen.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/home.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/import.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/index.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/lang.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/unfold.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/icons/update.svg
create mode 100644 docs/demo/src/WTA/wwwroot/assets/logo.svg
create mode 100644 docs/demo/src/WTA/wwwroot/components/chart/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/form/form-input.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/form/form-item.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/form/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/icon/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/list/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/components/markdown/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/config/settings.js
create mode 100644 docs/demo/src/WTA/wwwroot/favicon.ico
create mode 100644 docs/demo/src/WTA/wwwroot/index.html
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/footer.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/header.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/locale.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/logo.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/menu-item.js
create mode 100644 docs/demo/src/WTA/wwwroot/layouts/menu.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@element-plus/icons-vue/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@microsoft/signalr/signalr.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@vue-office/excel/index.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@vue-office/excel/vue-office-excel.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@vue/devtools-api/shim.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@vueuse/core/index.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/@vueuse/shared/index.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/better-mock/mock.browser.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/detect-it/detect-it.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/echarts/echarts.esm.min.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/element-plus/index.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/element-plus/index.full.min.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/element-plus/locale/en.min.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/element-plus/locale/zh-cn.min.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/element-plus/theme-chalk/dark/css-vars.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/github-markdown-css/github-markdown.min.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/highlightjs/highlight.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/highlightjs/highlight.min.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/jwt-decode/jwt-decode.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/linq/linq.min.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/lodash/lodash.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/marked/marked.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/mermaid/mermaid.esm.min.mjs
create mode 100644 docs/demo/src/WTA/wwwroot/lib/nprogress/nprogress.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/nprogress/nprogress.vite-esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/pinia/pinia.esm-browser.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/pubsub-js/pubsub.esm.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/qs/shim.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/resize-detector/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/tailwindcss/tailwind.min.css
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue-demi/shim.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue-echarts/index.esm.min.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue-i18n/vue-i18n.esm-browser.prod.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue-router/vue-router.esm-browser.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue/vue.esm-browser.js
create mode 100644 docs/demo/src/WTA/wwwroot/lib/vue/vue.esm-browser.prod.js
create mode 100644 docs/demo/src/WTA/wwwroot/locale/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/main.css
create mode 100644 docs/demo/src/WTA/wwwroot/main.js
create mode 100644 docs/demo/src/WTA/wwwroot/mixins/style.js
create mode 100644 docs/demo/src/WTA/wwwroot/request/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/resize-detector/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/router/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/signalr/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/store/app.js
create mode 100644 docs/demo/src/WTA/wwwroot/store/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/styles/site.css
create mode 100644 docs/demo/src/WTA/wwwroot/utils/index.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/403.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/404.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/home.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/list.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/login.js
create mode 100644 docs/demo/src/WTA/wwwroot/views/monitor.js
create mode 100644 docs/åŒ—æ±½æ¨¡å¡‘é”€å”®ç»“ç®—ç³»ç»ŸæŠ€æœ¯è¦æ±‚2023.6.15 V1.1(1).docx
diff --git a/docs/demo/.editorconfig b/docs/demo/.editorconfig
new file mode 100644
index 00000000..20273079
--- /dev/null
+++ b/docs/demo/.editorconfig
@@ -0,0 +1,536 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.cs]
+indent_size = 4
+dotnet_sort_system_directives_first = true
+
+# Don't use this. qualifier
+dotnet_style_qualification_for_field = true:suggestion
+dotnet_style_qualification_for_property = true:suggestion
+
+# use int x = .. over Int32
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+
+# use int.MaxValue over Int32.MaxValue
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Require var all the time.
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Disallow throw expressions.
+csharp_style_throw_expression = false:suggestion
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+# Namespace settings
+csharp_style_namespace_declarations = file_scoped:silent
+
+# Brace settings
+csharp_prefer_braces = true:silent# Prefer curly braces even for one line of code
+
+[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
+indent_size = 2
+
+# Xml config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
+
+[*.json]
+indent_size = 2
+
+[*.{ps1,psm1}]
+indent_size = 4
+
+[*.sh]
+indent_size = 4
+end_of_line = lf
+
+[*.{razor,cshtml}]
+charset = utf-8-bom
+
+[*.{cs,vb}]
+
+# SYSLIB1054: Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time
+dotnet_diagnostic.SYSLIB1054.severity = warning
+
+# CA1018: Mark attributes with AttributeUsageAttribute
+dotnet_diagnostic.CA1018.severity = warning
+
+# CA1047: Do not declare protected member in sealed type
+dotnet_diagnostic.CA1047.severity = warning
+
+# CA1305: Specify IFormatProvider
+dotnet_diagnostic.CA1305.severity = warning
+
+# CA1416: Validate platform compatibility
+dotnet_diagnostic.CA1416.severity = warning
+
+# CA1507: Use nameof to express symbol names
+dotnet_diagnostic.CA1507.severity = warning
+
+# CA1725: Parameter names should match base declaration
+dotnet_diagnostic.CA1725.severity = suggestion
+
+# CA1802: Use literals where appropriate
+dotnet_diagnostic.CA1802.severity = warning
+
+# CA1805: Do not initialize unnecessarily
+dotnet_diagnostic.CA1805.severity = warning
+
+# CA1810: Do not initialize unnecessarily
+dotnet_diagnostic.CA1810.severity = warning
+
+# CA1821: Remove empty Finalizers
+dotnet_diagnostic.CA1821.severity = warning
+
+# CA1822: Make member static
+dotnet_diagnostic.CA1822.severity = warning
+dotnet_code_quality.CA1822.api_surface = private, internal
+
+# CA1823: Avoid unused private fields
+dotnet_diagnostic.CA1823.severity = warning
+
+# CA1825: Avoid zero-length array allocations
+dotnet_diagnostic.CA1825.severity = warning
+
+# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
+dotnet_diagnostic.CA1826.severity = warning
+
+# CA1827: Do not use Count() or LongCount() when Any() can be used
+dotnet_diagnostic.CA1827.severity = warning
+
+# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used
+dotnet_diagnostic.CA1828.severity = warning
+
+# CA1829: Use Length/Count property instead of Count() when available
+dotnet_diagnostic.CA1829.severity = warning
+
+# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder
+dotnet_diagnostic.CA1830.severity = warning
+
+# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
+# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
+# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
+dotnet_diagnostic.CA1831.severity = warning
+dotnet_diagnostic.CA1832.severity = warning
+dotnet_diagnostic.CA1833.severity = warning
+
+# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
+dotnet_diagnostic.CA1834.severity = warning
+
+# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
+dotnet_diagnostic.CA1835.severity = warning
+
+# CA1836: Prefer IsEmpty over Count
+dotnet_diagnostic.CA1836.severity = warning
+
+# CA1837: Use 'Environment.ProcessId'
+dotnet_diagnostic.CA1837.severity = warning
+
+# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
+dotnet_diagnostic.CA1838.severity = warning
+
+# CA1839: Use 'Environment.ProcessPath'
+dotnet_diagnostic.CA1839.severity = warning
+
+# CA1840: Use 'Environment.CurrentManagedThreadId'
+dotnet_diagnostic.CA1840.severity = warning
+
+# CA1841: Prefer Dictionary.Contains methods
+dotnet_diagnostic.CA1841.severity = warning
+
+# CA1842: Do not use 'WhenAll' with a single task
+dotnet_diagnostic.CA1842.severity = warning
+
+# CA1843: Do not use 'WaitAll' with a single task
+dotnet_diagnostic.CA1843.severity = warning
+
+# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
+dotnet_diagnostic.CA1844.severity = warning
+
+# CA1845: Use span-based 'string.Concat'
+dotnet_diagnostic.CA1845.severity = warning
+
+# CA1846: Prefer AsSpan over Substring
+dotnet_diagnostic.CA1846.severity = warning
+
+# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
+dotnet_diagnostic.CA1847.severity = warning
+
+# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
+dotnet_diagnostic.CA1854.severity = warning
+
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = warning
+
+# CA2008: Do not create tasks without passing a TaskScheduler
+dotnet_diagnostic.CA2008.severity = warning
+
+# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value
+dotnet_diagnostic.CA2009.severity = warning
+
+# CA2011: Avoid infinite recursion
+dotnet_diagnostic.CA2011.severity = warning
+
+# CA2012: Use ValueTask correctly
+dotnet_diagnostic.CA2012.severity = warning
+
+# CA2013: Do not use ReferenceEquals with value types
+dotnet_diagnostic.CA2013.severity = warning
+
+# CA2014: Do not use stackalloc in loops.
+dotnet_diagnostic.CA2014.severity = warning
+
+# CA2016: Forward the 'CancellationToken' parameter to methods that take one
+dotnet_diagnostic.CA2016.severity = warning
+
+# CA2200: Rethrow to preserve stack details
+dotnet_diagnostic.CA2200.severity = warning
+
+# CA2208: Instantiate argument exceptions correctly
+dotnet_diagnostic.CA2208.severity = warning
+
+# CA2245: Do not assign a property to itself
+dotnet_diagnostic.CA2245.severity = warning
+
+# CA2246: Assigning symbol and its member in the same statement
+dotnet_diagnostic.CA2246.severity = warning
+
+# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
+dotnet_diagnostic.CA2249.severity = warning
+
+# IDE0005: Remove unnecessary usings
+dotnet_diagnostic.IDE0005.severity = warning
+
+# IDE0011: Curly braces to surround blocks of code
+dotnet_diagnostic.IDE0011.severity = warning
+
+# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
+dotnet_diagnostic.IDE0020.severity = warning
+
+# IDE0029: Use coalesce expression (non-nullable types)
+dotnet_diagnostic.IDE0029.severity = warning
+
+# IDE0030: Use coalesce expression (nullable types)
+dotnet_diagnostic.IDE0030.severity = warning
+
+# IDE0031: Use null propagation
+dotnet_diagnostic.IDE0031.severity = warning
+
+# IDE0035: Remove unreachable code
+dotnet_diagnostic.IDE0035.severity = warning
+
+# IDE0036: Order modifiers
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+dotnet_diagnostic.IDE0036.severity = warning
+
+# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
+dotnet_diagnostic.IDE0038.severity = warning
+
+# IDE0043: Format string contains invalid placeholder
+dotnet_diagnostic.IDE0043.severity = warning
+
+# IDE0044: Make field readonly
+dotnet_diagnostic.IDE0044.severity = warning
+
+# IDE0051: Remove unused private members
+dotnet_diagnostic.IDE0051.severity = warning
+
+# IDE0055: All formatting rules
+dotnet_diagnostic.IDE0055.severity = suggestion
+
+# IDE0059: Unnecessary assignment to a value
+dotnet_diagnostic.IDE0059.severity = warning
+
+# IDE0060: Remove unused parameter
+dotnet_code_quality_unused_parameters = non_public:suggestion
+dotnet_diagnostic.IDE0060.severity = warning
+
+# IDE0062: Make local function static
+dotnet_diagnostic.IDE0062.severity = warning
+
+# IDE0161: Convert to file-scoped namespace
+dotnet_diagnostic.IDE0161.severity = warning
+
+# IDE0200: Lambda expression can be removed
+dotnet_diagnostic.IDE0200.severity = warning
+
+# IDE2000: Disallow multiple blank lines
+dotnet_style_allow_multiple_blank_lines_experimental = false:silent
+dotnet_diagnostic.IDE2000.severity = warning
+
+[{eng/tools/**.cs,**/{test,testassets,samples,Samples,perf,scripts,stress}/**.cs}]
+# CA1018: Mark attributes with AttributeUsageAttribute
+dotnet_diagnostic.CA1018.severity = suggestion
+# CA1507: Use nameof to express symbol names
+dotnet_diagnostic.CA1507.severity = suggestion
+# CA1802: Use literals where appropriate
+dotnet_diagnostic.CA1802.severity = suggestion
+# CA1805: Do not initialize unnecessarily
+dotnet_diagnostic.CA1805.severity = suggestion
+# CA1810: Do not initialize unnecessarily
+dotnet_diagnostic.CA1810.severity = suggestion
+# CA1822: Make member static
+dotnet_diagnostic.CA1822.severity = suggestion
+# CA1823: Avoid zero-length array allocations
+dotnet_diagnostic.CA1825.severity = suggestion
+# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly
+dotnet_diagnostic.CA1826.severity = suggestion
+# CA1827: Do not use Count() or LongCount() when Any() can be used
+dotnet_diagnostic.CA1827.severity = suggestion
+# CA1829: Use Length/Count property instead of Count() when available
+dotnet_diagnostic.CA1829.severity = suggestion
+# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
+dotnet_diagnostic.CA1834.severity = suggestion
+# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
+dotnet_diagnostic.CA1835.severity = suggestion
+# CA1837: Use 'Environment.ProcessId'
+dotnet_diagnostic.CA1837.severity = suggestion
+# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
+dotnet_diagnostic.CA1838.severity = suggestion
+# CA1841: Prefer Dictionary.Contains methods
+dotnet_diagnostic.CA1841.severity = suggestion
+# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
+dotnet_diagnostic.CA1844.severity = suggestion
+# CA1845: Use span-based 'string.Concat'
+dotnet_diagnostic.CA1845.severity = suggestion
+# CA1846: Prefer AsSpan over Substring
+dotnet_diagnostic.CA1846.severity = suggestion
+# CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
+dotnet_diagnostic.CA1847.severity = suggestion
+# CA1854: Prefer the IDictionary.TryGetValue(TKey, out TValue) method
+dotnet_diagnostic.CA1854.severity = suggestion
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = suggestion
+# CA2008: Do not create tasks without passing a TaskScheduler
+dotnet_diagnostic.CA2008.severity = suggestion
+# CA2012: Use ValueTask correctly
+dotnet_diagnostic.CA2012.severity = suggestion
+# CA2249: Use string.Contains instead of string.IndexOf to improve readability.
+dotnet_diagnostic.CA2249.severity = suggestion
+# IDE0005: Remove unnecessary usings
+dotnet_diagnostic.IDE0005.severity = suggestion
+# IDE0020: Use pattern matching to avoid is check followed by a cast (with variable)
+dotnet_diagnostic.IDE0020.severity = suggestion
+# IDE0029: Use coalesce expression (non-nullable types)
+dotnet_diagnostic.IDE0029.severity = suggestion
+# IDE0030: Use coalesce expression (nullable types)
+dotnet_diagnostic.IDE0030.severity = suggestion
+# IDE0031: Use null propagation
+dotnet_diagnostic.IDE0031.severity = suggestion
+# IDE0038: Use pattern matching to avoid is check followed by a cast (without variable)
+dotnet_diagnostic.IDE0038.severity = suggestion
+# IDE0044: Make field readonly
+dotnet_diagnostic.IDE0044.severity = suggestion
+# IDE0051: Remove unused private members
+dotnet_diagnostic.IDE0051.severity = suggestion
+# IDE0059: Unnecessary assignment to a value
+dotnet_diagnostic.IDE0059.severity = suggestion
+# IDE0060: Remove unused parameters
+dotnet_diagnostic.IDE0060.severity = suggestion
+# IDE0062: Make local function static
+dotnet_diagnostic.IDE0062.severity = suggestion
+# IDE0200: Lambda expression can be removed
+dotnet_diagnostic.IDE0200.severity = suggestion
+
+# CA2016: Forward the 'CancellationToken' parameter to methods that take one
+dotnet_diagnostic.CA2016.severity = suggestion
+
+# Defaults for content in the shared src/ and shared runtime dir
+
+[{**/Shared/runtime/**.{cs,vb},src/Shared/test/Shared.Tests/runtime/**.{cs,vb},**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}]
+# CA1822: Make member static
+dotnet_diagnostic.CA1822.severity = silent
+# IDE0011: Use braces
+dotnet_diagnostic.IDE0011.severity = silent
+# IDE0055: Fix formatting
+dotnet_diagnostic.IDE0055.severity = silent
+# IDE0060: Remove unused parameters
+dotnet_diagnostic.IDE0060.severity = silent
+# IDE0062: Make local function static
+dotnet_diagnostic.IDE0062.severity = silent
+# IDE0161: Convert to file-scoped namespace
+dotnet_diagnostic.IDE0161.severity = silent
+
+[{**/Shared/**.cs,**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}]
+# IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included.
+dotnet_diagnostic.IDE0005.severity = silent
+dotnet_style_qualification_for_field = true:suggestion
+dotnet_style_qualification_for_property = true:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+[*.cs]
+#### å‘½åæ ·å¼ ####
+
+# 命å规则
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# 符å·è§„范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# å‘½åæ ·å¼
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+csharp_using_directive_placement = outside_namespace:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_conditional_delegate_call = true:suggestion
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_prefer_static_local_function = true:suggestion
+csharp_style_prefer_readonly_struct = true:suggestion
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+[*.vb]
+#### å‘½åæ ·å¼ ####
+
+# 命å规则
+
+dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
+dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
+dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
+
+dotnet_naming_rule.类型_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.severity = suggestion
+dotnet_naming_rule.类型_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.symbols = 类型
+dotnet_naming_rule.类型_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.style = å¸•æ–¯å¡æ‹¼å†™æ³•
+
+dotnet_naming_rule.éžå—段æˆå‘˜_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.severity = suggestion
+dotnet_naming_rule.éžå—段æˆå‘˜_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.symbols = éžå—段æˆå‘˜
+dotnet_naming_rule.éžå—段æˆå‘˜_should_be_å¸•æ–¯å¡æ‹¼å†™æ³•.style = å¸•æ–¯å¡æ‹¼å†™æ³•
+
+# 符å·è§„范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.类型.required_modifiers =
+
+dotnet_naming_symbols.éžå—段æˆå‘˜.applicable_kinds = property, event, method
+dotnet_naming_symbols.éžå—段æˆå‘˜.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
+dotnet_naming_symbols.éžå—段æˆå‘˜.required_modifiers =
+
+# å‘½åæ ·å¼
+
+dotnet_naming_style.以_i_开始.required_prefix = I
+dotnet_naming_style.以_i_开始.required_suffix =
+dotnet_naming_style.以_i_开始.word_separator =
+dotnet_naming_style.以_i_开始.capitalization = pascal_case
+
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.required_prefix =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.required_suffix =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.word_separator =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.capitalization = pascal_case
+
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.required_prefix =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.required_suffix =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.word_separator =
+dotnet_naming_style.å¸•æ–¯å¡æ‹¼å†™æ³•.capitalization = pascal_case
diff --git a/docs/demo/.gitattributes b/docs/demo/.gitattributes
new file mode 100644
index 00000000..314766e9
--- /dev/null
+++ b/docs/demo/.gitattributes
@@ -0,0 +1,3 @@
+* text=auto eol=lf
+*.{cmd,[cC][mM][dD]} text eol=crlf
+*.{bat,[bB][aA][tT]} text eol=crlf
diff --git a/docs/demo/.gitignore b/docs/demo/.gitignore
new file mode 100644
index 00000000..bfcbf6ee
--- /dev/null
+++ b/docs/demo/.gitignore
@@ -0,0 +1,16 @@
+*.bak
+
+#fe
+node_modules/
+dist/
+
+#be
+.vs/
+bin/
+obj/
+*.suo
+*.user
+*.db
+*.db-shm
+*.db-wal
+
diff --git a/docs/demo/.vscode/launch.json b/docs/demo/.vscode/launch.json
new file mode 100644
index 00000000..558e1798
--- /dev/null
+++ b/docs/demo/.vscode/launch.json
@@ -0,0 +1,35 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/src/WTA/bin/Debug/net7.0/WTA.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/src/WTA",
+ "stopAtEntry": false,
+ // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/demo/.vscode/tasks.json b/docs/demo/.vscode/tasks.json
new file mode 100644
index 00000000..6fef5425
--- /dev/null
+++ b/docs/demo/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/src/WTA/WTA.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/src/WTA/WTA.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/src/WTA/WTA.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/demo/Demo.sln b/docs/demo/Demo.sln
new file mode 100644
index 00000000..85a99122
--- /dev/null
+++ b/docs/demo/Demo.sln
@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33717.318
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WTA", "src\WTA\WTA.csproj", "{FFACA971-25FC-4652-A510-8BFC76E42D87}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WTA.Shared", "src\WTA.Shared\WTA.Shared.csproj", "{146358B1-1BD3-41B0-8D20-E613F422BA49}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WTA.Infrastructure", "src\WTA.Infrastructure\WTA.Infrastructure.csproj", "{8A09D8E5-2DB8-4741-BFBF-0542968F4D26}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WTA.Application", "src\WTA.Application\WTA.Application.csproj", "{82A8512D-456F-4849-BA9D-953B0C5E194A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{F181D9F7-4185-4AE2-B32B-A57411029F69}"
+ ProjectSection(SolutionItems) = preProject
+ Directory.Packages.props = Directory.Packages.props
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FFACA971-25FC-4652-A510-8BFC76E42D87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FFACA971-25FC-4652-A510-8BFC76E42D87}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FFACA971-25FC-4652-A510-8BFC76E42D87}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FFACA971-25FC-4652-A510-8BFC76E42D87}.Release|Any CPU.Build.0 = Release|Any CPU
+ {146358B1-1BD3-41B0-8D20-E613F422BA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {146358B1-1BD3-41B0-8D20-E613F422BA49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {146358B1-1BD3-41B0-8D20-E613F422BA49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {146358B1-1BD3-41B0-8D20-E613F422BA49}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A09D8E5-2DB8-4741-BFBF-0542968F4D26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A09D8E5-2DB8-4741-BFBF-0542968F4D26}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A09D8E5-2DB8-4741-BFBF-0542968F4D26}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A09D8E5-2DB8-4741-BFBF-0542968F4D26}.Release|Any CPU.Build.0 = Release|Any CPU
+ {82A8512D-456F-4849-BA9D-953B0C5E194A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {82A8512D-456F-4849-BA9D-953B0C5E194A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {82A8512D-456F-4849-BA9D-953B0C5E194A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {82A8512D-456F-4849-BA9D-953B0C5E194A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {53B37CFF-A4EE-43D2-97DE-F714E9F12F66}
+ EndGlobalSection
+EndGlobal
diff --git a/docs/demo/Directory.Packages.props b/docs/demo/Directory.Packages.props
new file mode 100644
index 00000000..98774428
--- /dev/null
+++ b/docs/demo/Directory.Packages.props
@@ -0,0 +1,39 @@
+
+
+ true
+ net7.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/demo/NuGet.Config b/docs/demo/NuGet.Config
new file mode 100644
index 00000000..2d29d123
--- /dev/null
+++ b/docs/demo/NuGet.Config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/docs/demo/README.md b/docs/demo/README.md
new file mode 100644
index 00000000..fed40760
--- /dev/null
+++ b/docs/demo/README.md
@@ -0,0 +1,37 @@
+# 说明
+
+## 模å—划分
+
+1. ä¸€ä¸ªæ¨¡å—æœ‰å¤šä¸ªæ•°æ®åº“上下文
+1. 一个数æ®åº“上下文有多个实体é…置和ç§åé…ç½®
+1. æ¯ä¸ªå®žä½“é…置和ç§åé…置关è”到一个数æ®ä¸Šä¸‹æ–‡
+
+## æƒé™è‡ªåŠ¨ç”Ÿæˆ
+
+1. IResource æ ‡è®°èµ„æºï¼ŒIResourceService\ where TResource:IResource æ ‡è®°æœåŠ¡
+1. Entity 默认实现 IResource 接å£
+1. 泛型控制器 GenericControlle 默认实现 Entity çš„å¢žåˆ æ”¹æŸ¥å¯¼å…¥å¯¼å‡ºæ“作,其他自定义æ“作å¯ä»¥ç»§æ‰¿æ³›åž‹æŽ§åˆ¶å™¨
+1. éž Entity 资æºå¯ä»¥æ‰‹åŠ¨å®žçŽ° IResource å’Œ IResourceService 接å£
+
+## C# 到 JSON Schema ç±»åž‹æ˜ å°„
+
+### 值类型
+
+1. bool?=>boolean[nullable]
+1. int/long?=>integer[nullable]
+1. float/double/decimal?=>number[nullable]
+1. Guid/DateTime/Enum?=>string[nullable]
+
+### 引用类型
+
+1. string=>string
+1. object=>object
+1. IEnumerable=>array
+
+## æ ¼å¼åŒ–
+
+format ç”¨äºŽæ ¼å¼éªŒè¯
+
+## 输入
+
+input 用于输入控件
diff --git a/docs/demo/src/WTA.Application/Captcha/CaptchaController.cs b/docs/demo/src/WTA.Application/Captcha/CaptchaController.cs
new file mode 100644
index 00000000..01eb1de6
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Captcha/CaptchaController.cs
@@ -0,0 +1,47 @@
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.OutputCaching;
+using Microsoft.Extensions.Caching.Distributed;
+using WTA.Shared.Captcha;
+
+namespace WTA.Application.Captcha;
+
+[Route("api/[controller]")]
+public class CaptchaController : Controller
+{
+ private readonly IDistributedCache _cache;
+ private readonly ICaptchaService _captchaService;
+
+ public CaptchaController(IDistributedCache cache, ICaptchaService captchaService)
+ {
+ this._cache = cache;
+ this._captchaService = captchaService;
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ [OutputCache(NoStore = true)]
+ public IActionResult Index()
+ {
+ var code = string.Empty;
+ var builder = new StringBuilder();
+ builder.Append(code);
+ for (var i = 0; i < 4; i++)
+ {
+ var random = new byte[1];
+ using var generator = RandomNumberGenerator.Create();
+ generator.GetBytes(random);
+ builder.Append(new Random(Convert.ToInt32(random[0])).Next(0, 9));
+ }
+ code = builder.ToString();
+ var key = Guid.NewGuid().ToString();
+ this._cache.SetString(key, code, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(5) });
+ return Json(new
+ {
+ Captcha = this._captchaService.Create(code),
+ CaptchaKey = key
+ });
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Controllers/ConnectionStringController.cs b/docs/demo/src/WTA.Application/Identity/Controllers/ConnectionStringController.cs
new file mode 100644
index 00000000..62dd41dd
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Controllers/ConnectionStringController.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.Logging;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Shared.Controllers;
+using WTA.Shared.Data;
+
+namespace WTA.Application.Identity.Controllers;
+
+public class ConnectionStringController : GenericController
+{
+ public ConnectionStringController(ILogger logger, IRepository repository) : base(logger, repository)
+ {
+ this.Repository.DisableTenantFilter();
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Controllers/PermissionController.cs b/docs/demo/src/WTA.Application/Identity/Controllers/PermissionController.cs
new file mode 100644
index 00000000..0cc95b22
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Controllers/PermissionController.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.Logging;
+using WTA.Application.Identity.Entities.SystemManagement;
+using WTA.Shared.Controllers;
+using WTA.Shared.Data;
+
+namespace WTA.Application.Identity.Controllers;
+
+public class PermissionController : GenericController
+{
+ public PermissionController(ILogger logger, IRepository repository) : base(logger, repository)
+ {
+ this.Repository.DisableTenantFilter();
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Controllers/TenantController.cs b/docs/demo/src/WTA.Application/Identity/Controllers/TenantController.cs
new file mode 100644
index 00000000..e0947994
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Controllers/TenantController.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.Logging;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Shared.Controllers;
+using WTA.Shared.Data;
+
+namespace WTA.Application.Identity.Controllers;
+
+public class TenantController : GenericController
+{
+ public TenantController(ILogger logger, IRepository repository) : base(logger, repository)
+ {
+ this.Repository.DisableTenantFilter();
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Controllers/TokenController.cs b/docs/demo/src/WTA.Application/Identity/Controllers/TokenController.cs
new file mode 100644
index 00000000..5ebbe69c
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Controllers/TokenController.cs
@@ -0,0 +1,208 @@
+using System.Globalization;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+using WTA.Application.Identity.Entities.SystemManagement;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Application.Identity.Models;
+using WTA.Shared.Application;
+using WTA.Shared.Authentication;
+using WTA.Shared.Controllers;
+using WTA.Shared.Data;
+using WTA.Shared.Extensions;
+using WTA.Shared.Identity;
+
+namespace WTA.Application.Identity.Controllers;
+
+[Route("api/{culture=zh}/[controller]")]
+[ApiExplorerSettings(GroupName = nameof(IdentityModule))]
+public class TokenController : BaseController, IResourceService
+{
+ private readonly TokenValidationParameters _tokenValidationParameters;
+ private readonly IdentityOptions _identityOptions;
+ private readonly IPasswordHasher _passwordHasher;
+ private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
+ private readonly SigningCredentials _credentials;
+ private readonly IRepository _tenantRepository;
+ private readonly IRepository _userRepository;
+
+ public TokenController(TokenValidationParameters tokenValidationParameters,
+ JwtSecurityTokenHandler jwtSecurityTokenHandler,
+ SigningCredentials credentials,
+ IOptions identityOptions,
+ IPasswordHasher passwordHasher,
+ IRepository _tenantRepository,
+ IRepository userRepository)
+ {
+ this._tokenValidationParameters = tokenValidationParameters;
+ this._jwtSecurityTokenHandler = jwtSecurityTokenHandler;
+ this._credentials = credentials;
+ this._identityOptions = identityOptions.Value;
+ this._passwordHasher = passwordHasher;
+ this._tenantRepository = _tenantRepository;
+ this._userRepository = userRepository;
+ this._userRepository.DisableTenantFilter();
+ }
+
+ [HttpGet("[action]")]
+ [AllowAnonymous]
+ public object Create()
+ {
+ return typeof(LoginRequestModel).GetViewModel();
+ }
+
+ [HttpPost("[action]")]
+ [AllowAnonymous]
+ public IActionResult Create([FromBody] LoginRequestModel model)
+ {
+ if (this.ModelState.IsValid)
+ {
+ try
+ {
+ var additionalClaims = new List();
+ if (model.TenantId != null)
+ {
+ if (this._tenantRepository.AsNoTracking().Any(o => o.Id == model.TenantId))
+ {
+ additionalClaims.Add(new Claim(nameof(model.TenantId), model.TenantId?.ToString()!));
+ }
+ else
+ {//租户ä¸å˜åœ¨
+ this.ModelState.AddModelError(nameof(LoginRequestModel.TenantId), "租户ä¸å˜åœ¨");
+ }
+ }
+ if (this.ModelState.IsValid)
+ {
+ var userQuery = this._userRepository.Queryable();
+ var user = userQuery.FirstOrDefault(o => o.UserName == model.UserName);
+ if (!this._identityOptions.SupportsUserLockout)
+ {//未å¯ç”¨ç™»å½•é”定
+ if (user == null || user.PasswordHash != this._passwordHasher.HashPassword(model.Password, user.SecurityStamp!))
+ {
+ this.ModelState.AddModelError("", "ç”¨æˆ·åæˆ–密ç 错误");
+ }
+ }
+ else
+ {//å¯ç”¨ç™»å½•é”定
+ if (user != null)
+ {
+ if (user.LockoutEnd.HasValue)
+ {//å·²é”定
+ if (DateTime.UtcNow > user.LockoutEnd.Value)
+ {//超时则解é”
+ user.AccessFailedCount = 0;
+ user.LockoutEnd = null;
+ this._userRepository.SaveChanges();
+ }
+ else
+ {//æœªè¶…æ—¶ç¦æ¢ç™»å½•
+ var minutes = (user.LockoutEnd!.Value - DateTime.UtcNow).TotalMinutes.ToString("f0", CultureInfo.InvariantCulture);
+ this.ModelState.AddModelError(nameof(LoginRequestModel.UserName), $"用户已é”定,{minutes} 分钟åŽè§£é™¤é”定");
+ }
+ }
+ if (!user.LockoutEnd.HasValue)
+ {//未é”定
+ if (user.PasswordHash != this._passwordHasher.HashPassword(model.Password, user.SecurityStamp!))
+ {//密ç 䏿£ç¡®
+ user.AccessFailedCount++;
+ if (user.AccessFailedCount >= this._identityOptions.MaxFailedAccessAttempts)
+ {//超过次数则é”定
+ user.LockoutEnd = DateTime.UtcNow + this._identityOptions.DefaultLockoutTimeSpan;
+ var minutes = (user.LockoutEnd!.Value - DateTime.UtcNow).TotalMinutes.ToString("f0", CultureInfo.InvariantCulture);
+ this.ModelState.AddModelError(nameof(LoginRequestModel.UserName), $"用户已é”定,{minutes} 分钟åŽè§£é™¤é”定");
+ }
+ else
+ {//未超过次数æç¤ºå‰©ä½™æ¬¡æ•°
+ this.ModelState.AddModelError(nameof(LoginRequestModel.Password), $"密ç 错误,{this._identityOptions.MaxFailedAccessAttempts - user.AccessFailedCount}次失败åŽå°†é”定用户");
+ }
+ this._userRepository.SaveChanges();
+ }
+ }
+ }
+ else
+ {
+ this.ModelState.AddModelError(nameof(LoginRequestModel.UserName), "用户ä¸å˜åœ¨");
+ }
+ }
+ if (this.ModelState.IsValid)
+ {//éªŒè¯æˆåŠŸ
+ var roles = this._userRepository.AsNoTracking()
+ .Where(o => o.UserName == model.UserName)
+ .SelectMany(o => o.UserRoles)
+ .Select(o => o.Role.Name)
+ .ToList()
+ .Select(o => new Claim(this._tokenValidationParameters.RoleClaimType, o));
+ additionalClaims.AddRange(roles);
+ var subject = CreateSubject(model.UserName, additionalClaims);
+ return Json(new LoginResponseModel
+ {
+ AccessToken = CreateToken(subject, this._identityOptions.AccessTokenExpires),
+ RefreshToken = CreateToken(subject, model.RememberMe ? TimeSpan.FromDays(365) : this._identityOptions.RefreshTokenExpires),
+ ExpiresIn = (long)this._identityOptions.AccessTokenExpires.TotalSeconds
+ });
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.ToString());
+ return Problem(ex.ToString());
+ }
+ }
+ return BadRequest(this.ModelState.ToErrors());
+ }
+
+ [HttpPost("[action]")]
+ [AllowAnonymous]
+ public LoginResponseModel Refresh(string refreshToken)
+ {
+ var validationResult = this._jwtSecurityTokenHandler.ValidateTokenAsync(refreshToken, this._tokenValidationParameters).Result;
+ if (!validationResult.IsValid)
+ {
+ throw new Exception("RefreshToken验è¯å¤±è´¥", innerException: validationResult.Exception);
+ }
+ var subject = validationResult.ClaimsIdentity;
+ return new LoginResponseModel
+ {
+ AccessToken = CreateToken(subject, this._identityOptions.AccessTokenExpires),
+ RefreshToken = CreateToken(subject, validationResult.SecurityToken.ValidTo.Subtract(validationResult.SecurityToken.ValidFrom)),
+ ExpiresIn = (long)this._identityOptions.AccessTokenExpires.TotalSeconds
+ };
+ }
+
+ private ClaimsIdentity CreateSubject(string userName, List additionalClaims)
+ {
+ var claims = new List(additionalClaims) { new Claim(this._tokenValidationParameters.NameClaimType, userName) };
+ var subject = new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme);
+ return subject;
+ }
+
+ private string CreateToken(ClaimsIdentity subject, TimeSpan timeout)
+ {
+ var now = DateTime.UtcNow;
+ var tokenDescriptor = new SecurityTokenDescriptor()
+ {
+ // ç¾å‘者
+ Issuer = this._identityOptions.Issuer,
+ // 接收方
+ Audience = this._identityOptions.Audience,
+ // 凿®
+ SigningCredentials = _credentials,
+ // 声明
+ Subject = subject,
+ // ç¾å‘æ—¶é—´
+ IssuedAt = now,
+ // 生效时间
+ NotBefore = now,
+ // UTC 过期时间
+ Expires = now.Add(timeout),
+ };
+ var securityToken = this._jwtSecurityTokenHandler.CreateJwtSecurityToken(tokenDescriptor);
+ var token = this._jwtSecurityTokenHandler.WriteToken(securityToken);
+ return token;
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Controllers/UserController.cs b/docs/demo/src/WTA.Application/Identity/Controllers/UserController.cs
new file mode 100644
index 00000000..ea2075b1
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Controllers/UserController.cs
@@ -0,0 +1,73 @@
+using System.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+using WTA.Application.Identity.Entities.SystemManagement;
+using WTA.Shared.Attributes;
+using WTA.Shared.Authentication;
+using WTA.Shared.Controllers;
+using WTA.Shared.Data;
+using WTA.Shared.Extensions;
+
+namespace WTA.Application.Identity.Controllers;
+
+[Implement]
+public class UserController : GenericController, IAuthenticationService
+{
+ public UserController(ILogger logger, IRepository repository) : base(logger, repository)
+ {
+ this.Repository.DisableTenantFilter();
+ }
+
+ [HttpPost, Hidden]
+ public AuthenticateResult Authenticate(string name, string operation)
+ {
+ var query = this.Repository.AsNoTracking();
+ var result = new AuthenticateResult
+ {
+ Succeeded = query.Any(o => o.UserName == name &&
+ o.UserRoles.Any(o => o.Role.RolePermissions.Any(o => o.Permission.Type == PermissionType.Operation && o.Permission.Number == operation)))
+ };
+ if (result.Succeeded)
+ {
+ var rolePermissions = query
+ .Where(o => o.UserName == name)
+ .SelectMany(o => o.UserRoles)
+ .Select(o => o.Role)
+ .SelectMany(o => o.RolePermissions)
+ .Where(o => o.Permission.Children.Any(p => p.Number == operation))
+ .ToList();
+ result.EnableColumnLimit = rolePermissions.Any(o => o.EnableColumnLimit);
+ if (result.EnableColumnLimit)
+ {
+ result.Columns = rolePermissions.Where(o => o.EnableColumnLimit).SelectMany(o => o.Columns).Distinct().ToList();
+ }
+ result.EnableRowLimit = rolePermissions.Any(o => o.EnableRowLimit);
+ if (result.EnableRowLimit)
+ {
+ result.Rows = rolePermissions.Where(o => o.EnableColumnLimit).SelectMany(o => o.Rows).ToList();
+ }
+ }
+ return result;
+ }
+
+ [HttpPost, Hidden]
+ [Display(Name = "用户信æ¯")]
+ public User? Info()
+ {
+ var user = this.Repository
+ .AsNoTracking()
+ .Include(o => o.Department)
+ .Include(o => o.UserRoles)
+ .ThenInclude(o => o.Role)
+ .ThenInclude(o => o.RolePermissions)
+ .ThenInclude(o => o.Permission)
+ .FirstOrDefault(o => o.UserName == this.User.Identity!.Name);
+ if (user != null)
+ {
+ user.SecurityStamp = string.Empty;
+ user.PasswordHash = string.Empty;
+ }
+ return user!;
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Data/IdentityConfiguration.cs b/docs/demo/src/WTA.Application/Identity/Data/IdentityConfiguration.cs
new file mode 100644
index 00000000..24ac70f3
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Data/IdentityConfiguration.cs
@@ -0,0 +1,90 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using WTA.Application.Identity.Entities.SystemManagement;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Application.Monitor.Entities;
+using WTA.Shared.Extensions;
+
+namespace WTA.Shared.Data.Config;
+
+public class IdentityConfiguration : IDbConfig, IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration,
+ IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasIndex(o => o.Name).IsUnique();
+ builder.HasIndex(o => o.Number).IsUnique();
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasOne(o => o.Parent).WithMany(o => o.ConnectionStrings).HasForeignKey(o => o.ParentId).OnDelete(DeleteBehavior.Cascade);
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasOne(o => o.Post).WithMany(o => o.Users).HasForeignKey(o => o.PostId).OnDelete(DeleteBehavior.SetNull);
+ builder.HasOne(o => o.Department).WithMany(o => o.Users).HasForeignKey(o => o.DepartmentId).OnDelete(DeleteBehavior.SetNull);
+ builder.HasAlternateKey(o => o.UserName);
+ builder.HasIndex(o => o.NormalizedUserName).IsUnique();
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasAlternateKey(o => o.Number);
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property(o => o.Type).IsRequired();
+ builder.Property(o => o.Columns).HasConversion(p => p.ToJson(), p => p.FromJson>()!);
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasOne(o => o.User).WithMany(o => o.UserRoles).HasForeignKey(o => o.UserId).OnDelete(DeleteBehavior.Cascade);
+ builder.HasOne(o => o.Role).WithMany(o => o.UserRoles).HasForeignKey(o => o.RoleId).OnDelete(DeleteBehavior.Cascade);
+ builder.HasAlternateKey(o => new { o.UserId, o.RoleId });
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasOne(o => o.Role).WithMany(o => o.RolePermissions).HasForeignKey(o => o.RoleId).OnDelete(DeleteBehavior.Cascade);
+ builder.HasOne(o => o.Permission).WithMany(o => o.RolePermissions).HasForeignKey(o => o.PermissionId).OnDelete(DeleteBehavior.Cascade);
+ builder.HasAlternateKey(o => new { o.RoleId, o.PermissionId });
+ builder.Property(o => o.Columns).HasConversion(p => p.ToJson(), p => p.FromJson>()!);
+ builder.Property(o => o.Rows).HasConversion(p => p.ToJson(), p => p.FromJson>()!);
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasAlternateKey(o => o.Number);
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ }
+
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasAlternateKey(o => o.ConnectionId);
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Data/IdentityDbContext.cs b/docs/demo/src/WTA.Application/Identity/Data/IdentityDbContext.cs
new file mode 100644
index 00000000..776c4849
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Data/IdentityDbContext.cs
@@ -0,0 +1,12 @@
+using Microsoft.EntityFrameworkCore;
+using WTA.Shared.Attributes;
+
+namespace WTA.Shared.Data;
+
+[IgnoreMultiTenancy]
+public class IdentityDbContext : BaseDbContext
+{
+ public IdentityDbContext(DbContextOptions options) : base(options)
+ {
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs b/docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs
new file mode 100644
index 00000000..53d36ea6
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Data/IdentityDbSeed.cs
@@ -0,0 +1,257 @@
+using System.ComponentModel.DataAnnotations;
+using System.Reflection;
+using LinqToDB.Extensions;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.AspNetCore.Mvc.Routing;
+using Microsoft.EntityFrameworkCore;
+using WTA.Application.Identity.Entities.SystemManagement;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Application.Monitor.Entities;
+using WTA.Shared;
+using WTA.Shared.Application;
+using WTA.Shared.Attributes;
+using WTA.Shared.Data;
+using WTA.Shared.Extensions;
+using WTA.Shared.Identity;
+
+namespace WTA.Application.Identity.Data;
+
+public class IdentityDbSeed : IDbSeed
+{
+ private readonly IPasswordHasher _passwordHasher;
+ private readonly IActionDescriptorCollectionProvider _actionProvider;
+
+ public IdentityDbSeed(IPasswordHasher passwordHasher, IActionDescriptorCollectionProvider actionProvider)
+ {
+ this._passwordHasher = passwordHasher;
+ this._actionProvider = actionProvider;
+ }
+
+ public void Seed(IdentityDbContext context)
+ {
+ //ç¦ç”¨å¤šç§Ÿæˆ·å’Œè½¯åˆ 除过滤器
+ context.DisableTenantFilter = true; ;
+ context.DisableSoftDeleteFilter = true;
+
+ // 定时器åˆå§‹åŒ–
+ context.Set().Add(new JobItem { Name = "客户端监测", Cron = "* * * * *", Service = "WTA.Application.Monitor.UserLoginSrevice" });
+
+ // æ•°æ®å—å…¸åˆå§‹åŒ–
+ InitDictionaries(context);
+
+ //租户åˆå§‹åŒ–
+ var tenant = new Tenant
+ {
+ Name = "默认",
+ Number = "default",
+ DataBaseCreated = false,
+ ConnectionStrings = new List
+ {
+ new ConnectionString(){ Name="Identity",Value="Data Source=data2.db" }
+ }
+ }.SetIdBy(o => o.Number);
+ context.Set().Add(tenant);
+ var defaultTenantId = tenant.Id;
+
+ // æƒé™åˆå§‹åŒ–
+ InitPermissions(context);
+
+ //部门åˆå§‹åŒ–
+ context.Set().Add(
+ new Department
+ {
+ Name = "ä¼ä¸š",
+ Number = "Enterprise",
+ Children = new List
+ {
+ new Department {
+ Name="总ç»åŠž",
+ Number="Root",
+ Children=new List
+ {
+ new Department
+ {
+ Name="部门",
+ Number="Department"
+ }
+ }
+ }
+ }
+ }.UpdateId()
+ .UpdatePath());
+
+ // 角色åˆå§‹åŒ–
+ var superRole = new Role
+ {
+ IsReadonly = true,
+ Name = "超级管ç†å‘˜è§’色",
+ Number = "super",
+ }.SetIdBy(o => o.Number);
+ context.Set().ToList().ForEach(o => superRole.RolePermissions.Add(new RolePermission
+ {
+ IsReadonly = true,
+ RoleId = superRole.Id,
+ PermissionId = o.Id,
+ EnableColumnLimit = false,
+ Columns = o.Columns.Keys.ToList(),
+ // EnableRowLimit = true,
+ // RowLimit = "CreatorId = {User.Id}"
+ }.SetIdBy(o => new { o.RoleId, o.PermissionId })));
+ context.Set().Add(superRole);
+ context.SaveChanges();
+
+ // 用户åˆå§‹åŒ–
+ var superUser = new User
+ {
+ IsReadonly = true,
+ UserName = "super",
+ NormalizedUserName = "super".Normalize(),
+ Name = "超级管ç†å‘˜",
+ SecurityStamp = "123456",
+ PasswordHash = this._passwordHasher.HashPassword("123456", "123456"),
+ Properties = new Dictionary { { "key1", "value1" } }
+ }.SetIdBy(o => o.UserName);
+ superUser.UserRoles.Add(new UserRole { IsReadonly = true, UserId = superUser.Id, RoleId = superRole.Id }.SetIdBy(o => new { o.UserId, o.RoleId }));
+ context.Set().Add(superUser);
+ }
+
+ private void InitDictionaries(DbContext context)
+ {
+ }
+
+ private void InitPermissions(DbContext context)
+ {
+ //var controllerFeature = new ControllerFeature();
+ //this._partManager.PopulateFeature(controllerFeature);
+ //var controllerTypeInfos = controllerFeature.Controllers;
+ var actionDescriptors = this._actionProvider.ActionDescriptors.Items;
+
+ context.Set().Add(new Permission
+ {
+ IsReadonly = true,
+ Type = PermissionType.Resource,
+ Name = "首页",
+ Number = "home",
+ Path = "home",
+ Method = "POST",
+ Component = "home",
+ Icon = "home",
+ Order = -3,
+ }.UpdateId().UpdatePath());
+
+ //context.Set().Add(new Permission
+ //{
+ // IsExternal = true,
+ // IsReadonly = true,
+ // Type = PermissionType.Resource,
+ // Name = "帮助",
+ // Number = "help",
+ // Path = "https://element-plus.org/",
+ // Method = "GET",
+ // Icon = "ep-link",
+ // Order = 1000,
+ //}.UpdateId().UpdatePath());
+
+ WebApp.Current.Assemblies.SelectMany(o => o.GetTypes()).Where(o => o.IsClass && !o.IsAbstract && o.IsAssignableTo(typeof(IResource))).ForEach(resourceType =>
+ {
+ // 获å–列
+ var columns = resourceType.GetProperties()
+ //.Where(o => o.PropertyType.IsValueType || o.PropertyType == typeof(string))
+ .OrderBy(o => o.GetCustomAttribute()?.GetOrder())
+ .ToDictionary(o => o.Name, o => o.GetDisplayName());
+ // åˆ›å»ºèµ„æºæƒé™
+ var resourcePermission = new Permission
+ {
+ IsReadonly = true,
+ Type = PermissionType.Resource,
+ Name = resourceType.GetDisplayName(),
+ Number = resourceType.Name,
+ Path = resourceType.Name.ToSlugify(),
+ Component = resourceType.GetCustomAttribute()?.Component,
+ IsHidden = resourceType.HasAttribute(),
+ Icon = resourceType.GetCustomAttribute()?.Icon ?? IconAttribute.File,
+ Order = resourceType.GetCustomAttribute()?.Order ?? OrderAttribute.Default,
+ Columns = columns
+ }.UpdateId();
+ // 创建按钮æƒé™
+ var resourceServiceType = typeof(IResourceService<>).MakeGenericType(resourceType);
+ actionDescriptors
+ .Select(o => o as ControllerActionDescriptor)
+ .Where(o => o != null && o.ControllerTypeInfo.AsType().IsAssignableTo(resourceServiceType))
+ .ForEach(actionDescriptor =>
+ {
+ var operation = actionDescriptor?.ActionName!;
+ var methodInfo = actionDescriptor?.MethodInfo!;
+ var method = (methodInfo.GetCustomAttributes().FirstOrDefault(o => o.GetType().IsAssignableTo(typeof(HttpMethodAttribute)))
+ as HttpMethodAttribute)?.HttpMethods?.FirstOrDefault() ?? "POST";
+ if (method != "GET")
+ {
+ resourcePermission.Children.Add(new Permission
+ {
+ IsReadonly = true,
+ Type = PermissionType.Operation,
+ Name = methodInfo.GetDisplayName(),
+ Number = $"{actionDescriptor?.ControllerName}.{operation}",
+ Path = $"{operation.TrimEnd("Async").ToSlugify()}",
+ IsHidden = methodInfo.GetCustomAttributes().Any(),
+ Method = method,
+ Icon = methodInfo.GetCustomAttribute()?.Icon ?? $"{operation.TrimEnd("Async").ToSlugify()}",
+ Order = methodInfo.GetCustomAttribute()?.Order ?? OrderAttribute.Default,
+ HtmlClass = methodInfo.GetCustomAttribute()?.Class ?? HtmlClassAttribute.Default,
+ IsTop = methodInfo.GetCustomAttribute() != null
+ }.UpdateId());
+ }
+ });
+ // 实体分组
+ var groupAttribute = resourceType.GetCustomAttributes().FirstOrDefault(o => o.GetType().IsAssignableTo(typeof(GroupAttribute)));
+ if (groupAttribute != null)
+ {
+ var groupNumber = groupAttribute.GetType().Name;
+ var groupPermission = context.Set().FirstOrDefault(o => o.Number == groupAttribute.GetType().Name);
+ groupPermission ??= new Permission
+ {
+ Type = PermissionType.Group,
+ Name = groupAttribute.GetType().GetDisplayName(),
+ Number = groupNumber,
+ Path = $"{groupAttribute.GetType().Name.TrimEnd("Attribute").ToSlugify()}",
+ IsHidden = groupAttribute.GetType().HasAttribute(),
+ Icon = groupAttribute.GetType().GetCustomAttribute()?.Icon ?? IconAttribute.Folder,
+ Order = groupAttribute.GetType().GetCustomAttribute()?.Order ?? OrderAttribute.Default
+ }.UpdateId();
+ groupPermission.Children.Add(resourcePermission);
+ var moduleType = groupAttribute.GetType().GetCustomAttributes()
+ .Where(o => o.GetType().IsGenericType && o.GetType().GetGenericTypeDefinition() == typeof(ModuleAttribute<>))
+ .Select(o => o as ITypeAttribute).Select(o => o?.Type).FirstOrDefault();
+ if (moduleType != null)
+ {
+ var modulePermission = context.Set().FirstOrDefault(o => o.Number == moduleType.Name);
+ if (modulePermission == null)
+ {
+ modulePermission = new Permission
+ {
+ Type = PermissionType.Module,
+ Name = moduleType.GetDisplayName(),
+ Number = moduleType.Name,
+ Path = moduleType.Name.TrimEnd("Module").ToSlugify(),
+ IsHidden = moduleType.HasAttribute(),
+ Icon = moduleType.GetCustomAttribute()?.Icon ?? IconAttribute.Folder,
+ Order = moduleType.GetCustomAttribute()?.Order ?? OrderAttribute.Default
+ }.UpdateId();
+ context.Set().Add(modulePermission.UpdatePath());
+ }
+ modulePermission.Children.Add(groupPermission);
+ }
+ else
+ {
+ context.Set().AddOrUpdate(groupPermission.UpdatePath());
+ }
+ }
+ else
+ {
+ context.Set().Add(resourcePermission.UpdatePath());
+ }
+ context.SaveChanges();
+ });
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/BaseData/Class1.cs b/docs/demo/src/WTA.Application/Identity/Entities/BaseData/Class1.cs
new file mode 100644
index 00000000..023ac67a
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/BaseData/Class1.cs
@@ -0,0 +1,642 @@
+using System.ComponentModel.DataAnnotations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using WTA.Shared.Attributes;
+using WTA.Shared.Data;
+using WTA.Shared.Domain;
+using WTA.Shared.Module;
+
+namespace WTA.Application.Identity.Entities.BaseData;
+
+[Order(7)]
+[SystemManagement]
+[Display(Name = "物料主数æ®")]
+public class Class1 : BaseEntity
+{
+}
+
+[Order(8)]
+[SystemManagement]
+[Display(Name = "客户零件关系")]
+public class Class2 : BaseEntity
+{
+}
+
+[Order(9)]
+[SystemManagement]
+[Display(Name = "客户端替æ¢ä»¶å…³ç³»")]
+public class Class3 : BaseEntity
+{
+}
+
+[Order(10)]
+[SystemManagement]
+[Display(Name = "å¯„å”®åº“å‡ºåº“æ€»æˆæ›¿æ¢å…³ç³»")]
+public class Class4 : BaseEntity
+{
+}
+
+[Order(11)]
+[SystemManagement]
+[Display(Name = "期间设置")]
+public class Class5 : BaseEntity
+{
+}
+
+[Order(12)]
+[SystemManagement]
+[Display(Name = "é”€å”®ä»·æ ¼å•")]
+public class Class6 : BaseEntity
+{
+}
+
+[Order(2)]
+[Display(Name = "EDI业务")]
+public class EdiAttribute : GroupAttribute
+{
+}
+
+[Order(1)]
+[Edi]
+[Display(Name = "EDIå’ŒHBPOæ ¸å¯¹")]
+public class Class7 : BaseEntity
+{
+}
+
+[Order(2)]
+[Edi]
+[Display(Name = "EDIå’ŒBBACæ ¸å¯¹")]
+public class Class8 : BaseEntity
+{
+}
+
+[Order(2)]
+[Display(Name = "JIS业务")]
+public class JISModule : BaseModule
+{
+}
+
+[Order(1)]
+[Module]
+[Display(Name = "æ•°æ®è¾“å…¥")]
+public class JISDataInputAttribute : GroupAttribute
+{
+}
+
+[Order(2)]
+[Module]
+[Display(Name = "æ•°æ®è¾“出")]
+public class JISDataOutputAttribute : GroupAttribute
+{
+}
+
+[Order(1)]
+[JISDataInput]
+[Display(Name = "HBPO结算导入")]
+public class Class9 : BaseEntity
+{
+}
+
+[Order(2)]
+[JISDataInput]
+[Display(Name = "BBAC结算导入")]
+public class Class10 : BaseEntity
+{
+}
+
+[Order(3)]
+[JISDataInput]
+[Display(Name = "HBPOå‘è¿æ•°æ®")]
+public class Class11 : BaseEntity
+{
+}
+
+[Order(4)]
+[JISDataInput]
+[Display(Name = "BBACå‘è¿æ•°æ®")]
+public class Class12 : BaseEntity
+{
+}
+
+[Order(1)]
+[JISDataOutput]
+[Display(Name = "HBPOç»“ç®—æ ¸å¯¹æ˜Žç»†è¾“å‡º")]
+public class Class13 : BaseEntity
+{
+}
+
+[Order(2)]
+[JISDataOutput]
+[Display(Name = "BBACç»“ç®—æ ¸å¯¹æ˜Žç»†è¾“å‡º")]
+public class Class14 : BaseEntity
+{
+}
+
+[Order(3)]
+[JISDataOutput]
+[Display(Name = "HBPOæ— æ³•å‡ºåº“æ˜Žç»†ä¸Žæ±‡æ€»è¾“å‡º")]
+public class Class15 : BaseEntity
+{
+}
+
+[Order(4)]
+[JISDataOutput]
+[Display(Name = "BBACæ— æ³•å‡ºåº“æ˜Žç»†ä¸Žæ±‡æ€»è¾“å‡º")]
+public class Class16 : BaseEntity
+{
+}
+
+[Order(5)]
+[JISDataOutput]
+[Display(Name = "HBPO结算å‘货明细与汇总")]
+public class Class17 : BaseEntity
+{
+}
+
+[Order(6)]
+[JISDataOutput]
+[Display(Name = "BBAC结算å‘货明细与汇总")]
+public class Class18 : BaseEntity
+{
+}
+
+/////
+
+[Order(3)]
+[Display(Name = "JIT业务")]
+public class JITModule : BaseModule
+{
+}
+
+[Order(1)]
+[Module]
+[Display(Name = "æ•°æ®è¾“å…¥")]
+public class JITDataInputAttribute : GroupAttribute
+{
+}
+
+[Order(2)]
+[Module]
+[Display(Name = "æ•°æ®è¾“出")]
+public class JITDataOutputAttribute : GroupAttribute
+{
+}
+
+[Order(1)]
+[JITDataInput]
+[Display(Name = "JIT件结算导入")]
+public class Class19 : BaseEntity
+{
+}
+
+[Order(2)]
+[JITDataInput]
+[Display(Name = "JITå‘è¿æ•°æ®æŸ¥è¯¢")]
+public class Class20 : BaseEntity
+{
+}
+
+[Order(1)]
+[JITDataOutput]
+[Display(Name = "JITä»¶ç»“ç®—æ ¸å¯¹æ˜Žç»†è¾“å‡º")]
+public class Class21 : BaseEntity
+{
+}
+
+[Order(2)]
+[JITDataOutput]
+[Display(Name = "JIT件寄售库ä¸èƒ½å‡ºåº“明细与汇总")]
+public class Class22 : BaseEntity
+{
+}
+
+[Order(3)]
+[JITDataOutput]
+[Display(Name = "JIT件结算å‘货明细与汇总")]
+public class Class23 : BaseEntity
+{
+}
+
+/////
+
+[Order(4)]
+[Display(Name = "备件业务")]
+public class BeiJianModule : BaseModule
+{
+}
+
+[Order(1)]
+[Module]
+[Display(Name = "æ•°æ®è¾“å…¥")]
+public class BeiJianDataInputAttribute : GroupAttribute
+{
+}
+
+[Order(2)]
+[Module]
+[Display(Name = "æ•°æ®è¾“出")]
+public class BeiJianDataOutputAttribute : GroupAttribute
+{
+}
+
+[Order(1)]
+[BeiJianDataInput]
+[Display(Name = "备件结算导入")]
+public class Class24 : BaseEntity
+{
+}
+
+[Order(2)]
+[BeiJianDataInput]
+[Display(Name = "备件å‘è¿æ•°æ®æŸ¥è¯¢")]
+public class Class25 : BaseEntity
+{
+}
+
+[Order(1)]
+[BeiJianDataOutput]
+[Display(Name = "å¤‡ä»¶ç»“ç®—æ ¸å¯¹æ˜Žç»†è¾“å‡º")]
+public class Class26 : BaseEntity
+{
+}
+
+[Order(2)]
+[BeiJianDataOutput]
+[Display(Name = "备件寄售库ä¸èƒ½å‡ºåº“明细与汇总输出")]
+public class Class27 : BaseEntity
+{
+}
+
+[Order(3)]
+[BeiJianDataOutput]
+[Display(Name = "备件有结算有å‘货明细与汇总输出")]
+public class Class28 : BaseEntity
+{
+}
+
+[Order(4)]
+[BeiJianDataOutput]
+[Display(Name = "å¤‡ä»¶æœ‰ç»“ç®—æ— å‘货明细与汇总输出")]
+public class Class29 : BaseEntity
+{
+}
+
+/////
+
+[Order(5)]
+[Display(Name = "备件业务")]
+public class MaiDanJianModule : BaseModule
+{
+}
+
+[Order(1)]
+[Module]
+[Display(Name = "æ•°æ®è¾“å…¥")]
+public class MaiDanJianDataInputAttribute : GroupAttribute
+{
+}
+
+[Order(2)]
+[Module]
+[Display(Name = "æ•°æ®è¾“出")]
+public class MaiDanJianDataOutputAttribute : GroupAttribute
+{
+}
+
+[Order(1)]
+[MaiDanJianDataInput]
+[Display(Name = "å°åº¦ä»¶ç»“算导入")]
+public class Class30 : BaseEntity
+{
+}
+
+[Order(2)]
+[MaiDanJianDataInput]
+[Display(Name = "å°åº¦ä»¶å‘è¿æ•°æ®æŸ¥è¯¢")]
+public class Class31 : BaseEntity
+{
+}
+
+[Order(1)]
+[MaiDanJianDataOutput]
+[Display(Name = "å°åº¦ä»¶ç»“ç®—æ ¸å¯¹æ˜Žç»†è¾“å‡º")]
+public class Class32 : BaseEntity
+{
+}
+
+[Order(2)]
+[MaiDanJianDataOutput]
+[Display(Name = "å°åº¦ä»¶å¯„售库ä¸èƒ½å‡ºåº“明细与汇总输出")]
+public class Class33 : BaseEntity
+{
+}
+
+[Order(3)]
+[MaiDanJianDataOutput]
+[Display(Name = "å°åº¦ä»¶æœ‰ç»“算有å‘货明细与汇总输出")]
+public class Class34 : BaseEntity
+{
+}
+
+[Order(4)]
+[MaiDanJianDataOutput]
+[Display(Name = "å°åº¦ä»¶æœ‰ç»“ç®—æ— å‘货明细与汇总输出")]
+public class Class35 : BaseEntity
+{
+}
+
+//////
+[Order(6)]
+[Display(Name = "出库å•")]
+public class ChuKuDanGroup : GroupAttribute
+{
+}
+
+[Order(1)]
+[ChuKuDanGroup]
+[Display(Name = "HBPO-JIS出库å•")]
+public class Class36 : BaseEntity
+{
+}
+
+[Order(2)]
+[ChuKuDanGroup]
+[Display(Name = "BBAC-JIS出库å•")]
+public class Class37 : BaseEntity
+{
+}
+
+[Order(3)]
+[ChuKuDanGroup]
+[Display(Name = "JIT件件出库å•")]
+public class Class38 : BaseEntity
+{
+}
+
+[Order(4)]
+[ChuKuDanGroup]
+[Display(Name = "备件出库å•")]
+public class Class39 : BaseEntity
+{
+}
+
+[Order(5)]
+[ChuKuDanGroup]
+[Display(Name = "å°åº¦ä»¶å‡ºåº“å•")]
+public class Class40 : BaseEntity
+{
+}
+
+[Order(6)]
+[ChuKuDanGroup]
+[Display(Name = "ä¸èƒ½å‡ºåº“记录出库业务")]
+public class Class41 : BaseEntity
+{
+}
+
+//////
+[Order(7)]
+[Display(Name = "å•†åŠ¡å®¡æ ¸")]
+public class ShangWuShenHeGroup : GroupAttribute
+{
+}
+
+[Order(1)]
+[ShangWuShenHeGroup]
+[Display(Name = "HBPO-JIS 商务待开票")]
+public class Class42 : BaseEntity
+{
+}
+
+[Order(2)]
+[ShangWuShenHeGroup]
+[Display(Name = "BBAC-JIS商务待开票")]
+public class Class43 : BaseEntity
+{
+}
+
+[Order(3)]
+[ShangWuShenHeGroup]
+[Display(Name = "JIT件商务å‘票待开票")]
+public class Class44 : BaseEntity
+{
+}
+
+[Order(4)]
+[ShangWuShenHeGroup]
+[Display(Name = "备件商务å‘票待开票")]
+public class Class45 : BaseEntity
+{
+}
+
+[Order(5)]
+[ShangWuShenHeGroup]
+[Display(Name = "å°åº¦ä»¶å•†åŠ¡å‘票待开票")]
+public class Class46 : BaseEntity
+{
+}
+
+//////
+[Order(7)]
+[Display(Name = "è´¢åŠ¡å®¡æ ¸")]
+public class CaiWuShenHeGroup : GroupAttribute
+{
+}
+
+[Order(1)]
+[CaiWuShenHeGroup]
+[Display(Name = " BBAC-JIS财务管ç†å®¡æ ¸")]
+public class Class47 : BaseEntity
+{
+}
+
+public class BaseDataDbConfig : IDbConfig,
+ IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration,
+IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+
+ public void Configure(EntityTypeBuilder builder)
+ { }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Department.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Department.cs
new file mode 100644
index 00000000..fe4b2ed6
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Department.cs
@@ -0,0 +1,12 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Hidden]
+[Order(4)]
+[SystemManagement]
+public class Department : BaseTreeEntity
+{
+ public List Users { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/DictionaryItem.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/DictionaryItem.cs
new file mode 100644
index 00000000..d926a0bc
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/DictionaryItem.cs
@@ -0,0 +1,10 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Order(6)]
+[SystemManagement]
+public class DictionaryItem : BaseTreeEntity
+{
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Permission.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Permission.cs
new file mode 100644
index 00000000..64a5c933
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Permission.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Order(3)]
+[SystemManagement]
+public class Permission : BaseTreeEntity
+{
+ [Required]
+ public PermissionType? Type { get; set; }
+
+ [Required]
+ public bool? IsHidden { get; set; } = false;
+
+ [Required]
+ public bool? IsExternal { get; set; } = false;
+
+ public string? Path { get; set; }
+ public string? Method { get; set; }
+ public string? Component { get; set; }
+ public string? Redirect { get; set; }
+ public string? Icon { get; set; }
+ public string? HtmlClass { get; set; }
+
+ [Required]
+ public bool? IsTop { get; set; } = false;
+
+ public Dictionary Columns { get; set; } = new Dictionary();
+ public List RolePermissions { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/PermissionType.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/PermissionType.cs
new file mode 100644
index 00000000..1eebdcbe
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/PermissionType.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+public enum PermissionType
+{
+ [Display(Name = "模å—")]
+ Module = 10,
+
+ [Display(Name = "分组")]
+ Group = 20,
+
+ [Display(Name = "资æº")]
+ Resource = 30,
+
+ [Display(Name = "æ“作")]
+ Operation = 40
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Post.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Post.cs
new file mode 100644
index 00000000..9f196856
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Post.cs
@@ -0,0 +1,14 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Hidden]
+[Order(5)]
+[SystemManagement]
+public class Post : BaseEntity
+{
+ public string Name { get; set; } = null!;
+ public string Number { get; set; } = null!;
+ public List Users { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Role.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Role.cs
new file mode 100644
index 00000000..c13eb638
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Role.cs
@@ -0,0 +1,14 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Order(2)]
+[SystemManagement]
+public class Role : BaseEntity
+{
+ public string Name { get; set; } = null!;
+ public string Number { get; set; } = null!;
+ public List UserRoles { get; set; } = new List();
+ public List RolePermissions { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/RolePermission.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/RolePermission.cs
new file mode 100644
index 00000000..ddb9a915
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/RolePermission.cs
@@ -0,0 +1,20 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Hidden]
+[Display(Name = "角色æƒé™")]
+[SystemManagement]
+public class RolePermission : BaseEntity
+{
+ public Guid RoleId { get; set; }
+ public Guid PermissionId { get; set; }
+ public Role Role { get; set; } = null!;
+ public Permission Permission { get; set; } = null!;
+ public bool EnableColumnLimit { get; internal set; }
+ public List Columns { get; set; } = new List();
+ public bool EnableRowLimit { get; set; }
+ public List Rows { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Token.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Token.cs
new file mode 100644
index 00000000..a76340fb
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/Token.cs
@@ -0,0 +1,9 @@
+using WTA.Shared.Application;
+using WTA.Shared.Attributes;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[SystemManagement, Hidden]
+public class Token : IResource
+{
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/User.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/User.cs
new file mode 100644
index 00000000..ccfea3e4
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/User.cs
@@ -0,0 +1,36 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Order(1)]
+[SystemManagement]
+public class User : BaseEntity
+{
+ public string UserName { get; set; } = null!;
+
+ [ScaffoldColumn(false)]
+ public string NormalizedUserName { get; set; } = null!;
+
+ public string Name { get; set; } = null!;
+
+ [ScaffoldColumn(false)]
+ public string SecurityStamp { get; set; } = null!;
+
+ [ScaffoldColumn(false)]
+ public string PasswordHash { get; set; } = null!;
+
+ public int AccessFailedCount { get; set; }
+ public DateTime? LockoutEnd { get; set; }
+
+ [Navigation]
+ public Guid? DepartmentId { get; set; }
+
+ public Guid? PostId { get; set; }
+
+ public Department? Department { get; set; }
+ public Post? Post { get; set; }
+
+ public List UserRoles { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/UserRole.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/UserRole.cs
new file mode 100644
index 00000000..ca41dd6c
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagement/UserRole.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.SystemManagement;
+
+[Hidden]
+[Display(Name = "用户角色")]
+[SystemManagement]
+public class UserRole : BaseEntity
+{
+ public Guid UserId { get; set; }
+ public Guid RoleId { get; set; }
+ public User User { get; set; } = null!;
+ public Role Role { get; set; } = null!;
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/SystemManagementAttribute.cs b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagementAttribute.cs
new file mode 100644
index 00000000..9710a9de
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/SystemManagementAttribute.cs
@@ -0,0 +1,8 @@
+using WTA.Shared.Attributes;
+
+namespace WTA.Application.Identity.Entities;
+
+[Order(1)]
+public class SystemManagementAttribute : GroupAttribute
+{
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/Tenants/ConnectionString.cs b/docs/demo/src/WTA.Application/Identity/Entities/Tenants/ConnectionString.cs
new file mode 100644
index 00000000..13aaeb39
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/Tenants/ConnectionString.cs
@@ -0,0 +1,17 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.Tenants;
+
+[Hidden]
+[Tenants]
+public class ConnectionString : BaseEntity
+{
+ public string Name { get; set; } = null!;
+ public string Value { get; set; } = null!;
+
+ [Navigation]
+ public Guid? ParentId { get; set; }
+
+ public Tenant? Parent { get; set; }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/Tenants/Tenant.cs b/docs/demo/src/WTA.Application/Identity/Entities/Tenants/Tenant.cs
new file mode 100644
index 00000000..2bdfadd9
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/Tenants/Tenant.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Identity.Entities.Tenants;
+
+[Hidden]
+[Tenants]
+public class Tenant : BaseEntity
+{
+ public string Name { get; set; } = null!;
+ public string Number { get; set; } = null!;
+
+ [Required]
+ public bool? DataBaseCreated { get; set; }
+
+ public List ConnectionStrings { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Entities/TenantsAttribute.cs b/docs/demo/src/WTA.Application/Identity/Entities/TenantsAttribute.cs
new file mode 100644
index 00000000..ab9bf2fb
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Entities/TenantsAttribute.cs
@@ -0,0 +1,8 @@
+using WTA.Shared.Attributes;
+
+namespace WTA.Application.Identity.Entities;
+
+//[Module]
+public class TenantsAttribute : GroupAttribute
+{
+}
diff --git a/docs/demo/src/WTA.Application/Identity/IdentityModule.cs b/docs/demo/src/WTA.Application/Identity/IdentityModule.cs
new file mode 100644
index 00000000..531c4f39
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/IdentityModule.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Builder;
+using WTA.Application.Monitor.Entities;
+using WTA.Shared;
+using WTA.Shared.Attributes;
+using WTA.Shared.Module;
+
+namespace WTA.Application.Identity;
+
+[Order(1)]
+public class IdentityModule : BaseModule
+{
+ public override void Configure(WebApplication app)
+ {
+ WebApp.Current.UseScheduler(app);
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Models/LoginRequestModel.cs b/docs/demo/src/WTA.Application/Identity/Models/LoginRequestModel.cs
new file mode 100644
index 00000000..240a24f3
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Models/LoginRequestModel.cs
@@ -0,0 +1,40 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace WTA.Application.Identity.Models;
+
+public class LoginRequestModel// : IValidatableObject
+{
+ [ScaffoldColumn(false)]
+ [UIHint("select")]
+ public Guid? TenantId { get; set; } = null!;
+
+ [MaxLength(64)]
+ public string UserName { get; set; } = null!;
+
+ [MaxLength(64)]
+ [DataType(DataType.Password)]
+ public string Password { get; set; } = null!;
+
+ //[ScaffoldColumn(false)]
+ //public string CaptchaKey { get; set; } = null!;
+
+ //[UIHint("captcha")]
+ //public string Captcha { get; set; } = null!;
+
+ public bool RememberMe { get; set; }
+
+ //public IEnumerable Validate(ValidationContext validationContext)
+ //{
+ // using var scope = WebApp.Current.Services.CreateScope();
+ // var cache = scope.ServiceProvider.GetRequiredService();
+ // var code = cache.GetString(this.CaptchaKey);
+ // if (code == null)
+ // {
+ // yield return new ValidationResult("CaptchaExpired", new string[] { "Captcha" });
+ // }
+ // else if (code != this.Captcha)
+ // {
+ // yield return new ValidationResult("CaptchaError", new string[] { "Captcha" });
+ // }
+ //}
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Models/LoginResponseModel.cs b/docs/demo/src/WTA.Application/Identity/Models/LoginResponseModel.cs
new file mode 100644
index 00000000..cb00d5b4
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Models/LoginResponseModel.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace WTA.Application.Identity.Models;
+
+public class LoginResponseModel
+{
+ [JsonPropertyName("token_type")]
+ public string TokenType = "Bearer";
+
+ [JsonPropertyName("access_token")]
+ public string? AccessToken { get; set; }
+
+ [JsonPropertyName("refresh_token")]
+ public string? RefreshToken { get; set; }
+
+ [JsonPropertyName("expires_in")]
+ public long? ExpiresIn { get; set; }
+}
diff --git a/docs/demo/src/WTA.Application/Identity/Models/UserInfoModel.cs b/docs/demo/src/WTA.Application/Identity/Models/UserInfoModel.cs
new file mode 100644
index 00000000..2e737a7b
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/Models/UserInfoModel.cs
@@ -0,0 +1,9 @@
+using WTA.Application.Identity.Entities.SystemManagement;
+
+namespace WTA.Application.Identity.Models;
+
+public class UserInfoModel
+{
+ public User User { get; set; } = null!;
+ public List Permissions { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Application/Identity/TenantService.cs b/docs/demo/src/WTA.Application/Identity/TenantService.cs
new file mode 100644
index 00000000..2ad475bd
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Identity/TenantService.cs
@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using WTA.Application.Identity.Entities.Tenants;
+using WTA.Shared.Attributes;
+using WTA.Shared.Data;
+using WTA.Shared.Tenants;
+
+namespace WTA.Application.Identity;
+
+[Implement]
+public class TenantService : ITenantService
+{
+ private readonly IServiceProvider _serviceProvider;
+
+ public string? TenantId { get; set; }
+
+ public TenantService(IHttpContextAccessor httpContextAccessor, IServiceProvider serviceProvider)
+ {
+ this._serviceProvider = serviceProvider;
+ this.TenantId = httpContextAccessor.HttpContext?.User.Claims.FirstOrDefault(o => o.Type == "TenantId")?.Value;
+ }
+
+ public string? GetConnectionString(string connectionStringName)
+ {
+ using var scope = this._serviceProvider.CreateScope();
+ var repository = scope.ServiceProvider.GetRequiredService>();
+ repository.DisableTenantFilter();
+ return repository
+ .AsNoTracking()
+ .Where(o => o.Number == this.TenantId)
+ .SelectMany(o => o.ConnectionStrings)
+ .FirstOrDefault(o => o.Name == connectionStringName)
+ ?.Value;
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Localization/LocalizationController.cs b/docs/demo/src/WTA.Application/Localization/LocalizationController.cs
new file mode 100644
index 00000000..c524412c
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Localization/LocalizationController.cs
@@ -0,0 +1,46 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Localization;
+using Microsoft.Extensions.Options;
+using WTA.Shared.Controllers;
+
+namespace WTA.Application.Localization;
+
+[Route("api/[controller]")]
+public class LocalizationController : BaseController
+{
+ private readonly IStringLocalizer _localizer;
+ private readonly RequestLocalizationOptions _options;
+
+ public LocalizationController(IOptions options, IStringLocalizer localizer)
+ {
+ this._options = options.Value;
+ this._localizer = localizer;
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public IActionResult Index(string? culture)
+ {
+ if (culture != null)
+ {
+ Thread.CurrentThread.CurrentCulture = this._options.SupportedCultures!.First(o => o.Name == culture);
+ }
+ var result = new
+ {
+ Options = this._options.SupportedUICultures?
+ .Select(o => new { Value = o.Name, Label = o.NativeName })
+ .ToList(),
+ Locale = Thread.CurrentThread.CurrentCulture.Name,
+ Messages = new Dictionary(),
+ };
+ foreach (var item in this._options.SupportedUICultures!)
+ {
+ Thread.CurrentThread.CurrentCulture = item;
+ result.Messages.Add(item.Name, this._localizer.GetAllStrings().ToDictionary(o => o.Name, o => o.Value));
+ }
+ return Json(result);
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/Controllers/Monitor.cs b/docs/demo/src/WTA.Application/Monitor/Controllers/Monitor.cs
new file mode 100644
index 00000000..b717405d
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/Controllers/Monitor.cs
@@ -0,0 +1,12 @@
+using WTA.Shared.Application;
+using WTA.Shared.Attributes;
+
+namespace WTA.Application.Monitor.Controllers;
+
+[Hidden]
+[Order(3)]
+[SystemMonitor]
+[Component("monitor")]
+public class Monitor : IResource
+{
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/Controllers/MonitorController.cs b/docs/demo/src/WTA.Application/Monitor/Controllers/MonitorController.cs
new file mode 100644
index 00000000..de027a60
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/Controllers/MonitorController.cs
@@ -0,0 +1,30 @@
+using Microsoft.AspNetCore.Mvc;
+using WTA.Shared.Application;
+using WTA.Shared.Extensions;
+using WTA.Shared.Monitor;
+
+namespace WTA.Application.Monitor.Controllers;
+
+[ApiExplorerSettings(GroupName = nameof(MonitorModule))]
+[Route("api/{culture}/system-monitor/[controller]/[action]")]
+public class MonitorController : Controller, IResourceService
+{
+ private readonly IMonitorService _monitorService;
+
+ public MonitorController(IMonitorService monitorService)
+ {
+ this._monitorService = monitorService;
+ }
+
+ [HttpGet]
+ public IActionResult Index()
+ {
+ return Json(typeof(MonitorModel).GetMetadataForType());
+ }
+
+ [HttpPost]
+ public IActionResult Index(MonitorModel model)
+ {
+ return Json(this._monitorService.GetStatus());
+ }
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/Controllers/SystemMonitorAttribute.cs b/docs/demo/src/WTA.Application/Monitor/Controllers/SystemMonitorAttribute.cs
new file mode 100644
index 00000000..f2cd76df
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/Controllers/SystemMonitorAttribute.cs
@@ -0,0 +1,8 @@
+using WTA.Shared.Attributes;
+
+namespace WTA.Application.Monitor.Controllers;
+
+[Order(2)]
+public class SystemMonitorAttribute : GroupAttribute
+{
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/Entities/JobItem.cs b/docs/demo/src/WTA.Application/Monitor/Entities/JobItem.cs
new file mode 100644
index 00000000..f8ae42d8
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/Entities/JobItem.cs
@@ -0,0 +1,15 @@
+using WTA.Application.Monitor.Controllers;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Monitor.Entities;
+
+[Hidden]
+[Order(2)]
+[SystemMonitor]
+public class JobItem : BaseEntity
+{
+ public string Name { get; set; } = null!;
+ public string Cron { get; set; } = null!;
+ public string Service { get; set; } = null!;
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/Entities/UserLogin.cs b/docs/demo/src/WTA.Application/Monitor/Entities/UserLogin.cs
new file mode 100644
index 00000000..a69e9dc9
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/Entities/UserLogin.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+using WTA.Application.Monitor.Controllers;
+using WTA.Shared.Attributes;
+using WTA.Shared.Domain;
+
+namespace WTA.Application.Monitor.Entities;
+
+[Hidden]
+[Order(1)]
+[SystemMonitor]
+public class UserLogin : BaseEntity
+{
+ public string ConnectionId { get; set; } = null!;
+ public string UserName { get; set; } = null!;
+
+ [Required]
+ public DateTime? Login { get; set; }
+
+ public DateTime? Logout { get; set; }
+
+ [Required]
+ public bool? IsOnline { get; set; }
+
+ public DateTime? Heartbeat { get; set; }
+ public string? UserAgent { get; set; }
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/MonitorModule.cs b/docs/demo/src/WTA.Application/Monitor/MonitorModule.cs
new file mode 100644
index 00000000..7998a82e
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/MonitorModule.cs
@@ -0,0 +1,9 @@
+using WTA.Shared.Attributes;
+using WTA.Shared.Module;
+
+namespace WTA.Application.Monitor;
+
+[Order(100)]
+public class MonitorModule : BaseModule
+{
+}
diff --git a/docs/demo/src/WTA.Application/Monitor/UserLoginSrevice.cs b/docs/demo/src/WTA.Application/Monitor/UserLoginSrevice.cs
new file mode 100644
index 00000000..f8127246
--- /dev/null
+++ b/docs/demo/src/WTA.Application/Monitor/UserLoginSrevice.cs
@@ -0,0 +1,60 @@
+using WTA.Application.Monitor.Entities;
+using WTA.Shared.Data;
+using WTA.Shared.EventBus;
+using WTA.Shared.Job;
+using WTA.Shared.Mappers;
+using WTA.Shared.SignalR;
+
+namespace WTA.Application.Monitor;
+
+public class UserLoginSrevice : IEventHander,
+ IEventHander,
+ IEventHander,
+ IEventHander,
+ IJobService
+{
+ private readonly IRepository _repository;
+
+ public UserLoginSrevice(IRepository repository)
+ {
+ this._repository = repository;
+ }
+
+ public Task Handle(SignalRConnectedEvent data)
+ {
+ var entity = new UserLogin().FromModel(data);
+ entity.IsOnline = true;
+ this._repository.Insert(entity);
+ this._repository.SaveChanges();
+ return Task.CompletedTask;
+ }
+
+ public Task Handle(SignalRDisconnectedEvent data)
+ {
+ var entity = this._repository.Queryable().FirstOrDefault(o => o.ConnectionId == data.ConnectionId);
+ if (entity != null)
+ {
+ entity.FromObject(data);
+ entity.IsOnline = false;
+ this._repository.SaveChanges();
+ }
+ return Task.CompletedTask;
+ }
+
+ public Task Handle(SignalRHeartbeatEvent data)
+ {
+ this._repository.Update(o => o.SetProperty(c => c.Heartbeat, DateTime.UtcNow), o => o.ConnectionId == data.ConnectionId);
+ return Task.CompletedTask;
+ }
+
+ public Task Handle(SignalCommandREvent data)
+ {
+ return Task.CompletedTask;
+ }
+
+ public void Invoke()
+ {
+ var time = DateTime.UtcNow.AddMinutes(-1);
+ this._repository.Update(o => o.SetProperty(c => c.IsOnline, false).SetProperty(c => c.Logout, DateTime.UtcNow), o => o.Heartbeat == null || o.Heartbeat < time);
+ }
+}
diff --git a/docs/demo/src/WTA.Application/WTA.Application.csproj b/docs/demo/src/WTA.Application/WTA.Application.csproj
new file mode 100644
index 00000000..bd1bfde4
--- /dev/null
+++ b/docs/demo/src/WTA.Application/WTA.Application.csproj
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/docs/demo/src/WTA.Infrastructure/Resources/en.json b/docs/demo/src/WTA.Infrastructure/Resources/en.json
new file mode 100644
index 00000000..1ab9c343
--- /dev/null
+++ b/docs/demo/src/WTA.Infrastructure/Resources/en.json
@@ -0,0 +1,16 @@
+{
+ "Application": "WTA Framework",
+ "Copyright": "all rights reserved © copyright",
+ "Test": "test",
+ "Login": "Login",
+ "Logout": "Logout",
+ "ConfirmLogout": "Confirm Logout?",
+ "Register": "Register",
+ "Tip": "Tip",
+ "Cancel": "Cancel",
+ "UserName": "User Name",
+ "Password": "Password",
+ "RememberMe": "Remember Me",
+ "ResetPassword": "Reset Password",
+ "UserCenter": "User Center"
+}
diff --git a/docs/demo/src/WTA.Infrastructure/Resources/zh.json b/docs/demo/src/WTA.Infrastructure/Resources/zh.json
new file mode 100644
index 00000000..38e894dc
--- /dev/null
+++ b/docs/demo/src/WTA.Infrastructure/Resources/zh.json
@@ -0,0 +1,130 @@
+{
+ "Application": "WTA开呿¡†æž¶",
+ "Copyright": "ç‰ˆæƒæ‰€æœ‰ © copyright ",
+ "Test": "测试",
+ "CompareAttribute": "{0}â€å’Œ{1}ä¸åŒ¹é…",
+ "FileExtensionsAttribute": "{0}åªæŽ¥å—一下扩展å的文件: {1}",
+ "MaxLengthAttribute": "{0}的最大长度为 {1}",
+ "MinLengthAttribute": "{0}的最å°é•¿åº¦ä¸º {1}",
+ "RangeAttribute": "{0}必需在 {1} 和 {2} 之间",
+ "RegularExpressionAttribute": "{0}â€å¿…需匹é…{1}",
+ "RequiredAttribute": "{0}ä¸èƒ½ä¸ºç©º",
+ "StringLengthAttribute": "{0}的最大长度为 {1}",
+ "StringLengthAttributeIncludingMinimum": "{0}的长度在 {2} 和 {1} 之间",
+ "DataTypeAttribute_CreditCard": "{0}䏿˜¯æœ‰æ•ˆçš„信用å¡å·ç ",
+ "DataTypeAttribute_EmailAddress": "{0}䏿˜¯æœ‰æ•ˆçš„ Email 地å€",
+ "DataTypeAttribute_PhoneNumber": "{0}䏿˜¯æœ‰æ•ˆçš„æ‰‹æœºå·ç ",
+ "DataTypeAttribute_Url": "{0}䏿˜¯æœ‰æ•ˆçš„ Url",
+ "DataTypeAttribute_Upload": "{0}的扩展å必须为:{1}",
+ "DataTypeAttribute_DateTime": "{0}䏿˜¯æœ‰æ•ˆçš„æ—¥æœŸæ ¼å¼",
+ "CustomValidationAttribute": "{0}验è¯å¤±è´¥",
+ "ValidationAttribute": "{0}验è¯å¤±è´¥",
+ "True": "是",
+ "False": "å¦",
+ "Select": "选择",
+ "Confirm": "确定",
+ "Reset": "é‡ç½®",
+ "RowIndex": "行å·",
+ "Name": "åç§°",
+ "Number": "ç¼–å·",
+ "Value": "值",
+ "Order": "åºå·",
+ "IsDisabled": "ç¦ç”¨",
+ "Properties": "属性",
+ "ParentId": "上级",
+ "LockoutEnabled": "å¯ç”¨é”定",
+ "LockoutEnd": "é”定截æ¢",
+ "AccessFailedCount": "登录失败次数",
+ "IsSystem": "系统内置",
+ "IsReadonly": "åªè¯»",
+ "Audit": "审计",
+ "SelectAll": "全选",
+ "SelectInverse": "å选",
+ "Filter": "过滤",
+ "CreatedOn": "创建时间",
+ "CreatedBy": "创建人",
+ "UpdatedOn": "修改时间",
+ "UpdatedBy": "修改人",
+ "DeletedOn": "åˆ é™¤æ—¶é—´",
+ "DeletedBy": "åˆ é™¤äºº",
+ "ConcurrencyStamp": "并呿ˆ³",
+ "Operations": "æ“作",
+ "Disabled": "å·²ç¦ç”¨",
+ "DisplayOrder": "åºå·",
+ "IsDeleted": "å·²åˆ é™¤",
+ "Path": "路径",
+ "Method": "方法",
+ "IsTop": "顶部",
+ "HTMLClass": "class",
+ "InternalPath": "内部路径",
+ "Component": "组件",
+ "ServerTime": "æœåŠ¡å™¨æ—¶é—´",
+ "OSArchitecture": "系统架构",
+ "OSDescription": "æ“作系统",
+ "ProcessArchitecture": "进程架构",
+ "Tip": "æç¤º",
+ "Cancel": "æ“ä½œå–æ¶ˆ",
+ "Index": "查询",
+ "Details": "详情",
+ "Create": "新建",
+ "Update": "æ›´æ–°",
+ "Import": "导入",
+ "Export": "导出",
+ "Remove": "移除",
+ "Restore": "还原",
+ "Delete": "åˆ é™¤",
+ "Authenticate": "验è¯",
+ "LoginModel": "登录",
+ "Login": "登录",
+ "Logout": "注销",
+ "ConfirmLogout": "确认退出?",
+ "Register": "注册",
+ "UserName": "用户å",
+ "Password": "密ç ",
+ "Email": "邮箱",
+ "EmailConfirmed": "邮箱已确认",
+ "RememberMe": "è®°ä½æˆ‘",
+ "ResetPassword": "é‡ç½®å¯†ç ",
+ "UserCenter": "用户ä¸å¿ƒ",
+ "Avatar": "头åƒ",
+ "Tenant": "租户",
+ "ConnectionString": "连接å—符串",
+ "TenantId": "租户",
+ "Tenants": "租户管ç†",
+ "Identity": "认è¯ä¸å¿ƒ",
+ "SystemManagement": "基础数æ®",
+ "RoleId": "角色",
+ "PermissionId": "æƒé™",
+ "UserRoles": "用户角色",
+ "EnableColumnLimit": "列æƒé™",
+ "EnableRowLimit": "行æƒé™",
+ "RolePermissions": "角色æƒé™",
+ "DepartmentId": "部门",
+ "Cron": "定时器",
+ "Icon": "å›¾æ ‡",
+ "Type": "类型",
+ "IsExternal": "外链",
+ "IsHidden": "éšè—",
+ "Redirect": "跳转",
+ "Columns": "列",
+ "IdentityModule": "系统管ç†",
+ "User": "用户",
+ "Role": "角色",
+ "Permission": "æƒé™",
+ "Department": "部门",
+ "Post": "å²—ä½",
+ "Dict": "å—å…¸",
+ "SystemMonitor": "系统监控",
+ "Monitor": "æœåŠ¡ç›‘æŽ§",
+ "MonitorModule": "系统监控",
+ "JobItem": "定时任务",
+ "Captcha": "验è¯ç ",
+ "CaptchaExpired": "验è¯ç 已过期",
+ "CaptchaError": "验è¯ç 错误",
+ "DictionaryItem": "æ•°æ®å—å…¸",
+ "UserLogin": "登录历å²",
+ "ConnectionId": "连接Id",
+ "IsOnline": "在线",
+ "Heartbeat": "心跳",
+ "UserAgent": "用户代ç†"
+}
diff --git a/docs/demo/src/WTA.Infrastructure/WTA.Infrastructure.csproj b/docs/demo/src/WTA.Infrastructure/WTA.Infrastructure.csproj
new file mode 100644
index 00000000..f18c156c
--- /dev/null
+++ b/docs/demo/src/WTA.Infrastructure/WTA.Infrastructure.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/demo/src/WTA.Shared/Application/IExportModel.cs b/docs/demo/src/WTA.Shared/Application/IExportModel.cs
new file mode 100644
index 00000000..00de67a7
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Application/IExportModel.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Application;
+
+public interface IExportModel where TEntity : class
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Application/IImportModel.cs b/docs/demo/src/WTA.Shared/Application/IImportModel.cs
new file mode 100644
index 00000000..b2d5d242
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Application/IImportModel.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Application;
+
+public interface IImportModel where TEntity : class
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Application/IResource.cs b/docs/demo/src/WTA.Shared/Application/IResource.cs
new file mode 100644
index 00000000..49b32bdb
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Application/IResource.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Application;
+
+public interface IResource
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Application/IResourceService.cs b/docs/demo/src/WTA.Shared/Application/IResourceService.cs
new file mode 100644
index 00000000..e6515a0c
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Application/IResourceService.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Application;
+
+public interface IResourceService where TResource : IResource
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Application/PaginationModel.cs b/docs/demo/src/WTA.Shared/Application/PaginationModel.cs
new file mode 100644
index 00000000..6a4a0565
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Application/PaginationModel.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel;
+using WTA.Shared.Domain;
+
+namespace WTA.Shared.Application;
+
+public class PaginationModel
+{
+ public PaginationModel()
+ {
+ }
+
+ [DefaultValue(1)]
+ public int PageIndex { get; set; } = 1;
+
+ [DefaultValue(20)]
+ public int PageSize { get; set; } = 20;
+
+ public string? OrderBy { get; set; } = $"{nameof(BaseEntity.Order)},{nameof(BaseEntity.CreatedOn)}";
+ public int TotalCount { get; set; }
+ public List Items { get; set; } = new List();
+ public TSearchModel Query { get; set; } = Activator.CreateInstance();
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/AddOnlyAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/AddOnlyAttribute.cs
new file mode 100644
index 00000000..38e02f4a
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/AddOnlyAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property)]
+public class AddOnlyAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/ComponentAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/ComponentAttribute.cs
new file mode 100644
index 00000000..3f35ae81
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/ComponentAttribute.cs
@@ -0,0 +1,12 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class ComponentAttribute : Attribute
+{
+ public ComponentAttribute(string? component = null)
+ {
+ this.Component = component;
+ }
+
+ public string? Component { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/DbContextAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/DbContextAttribute.cs
new file mode 100644
index 00000000..263cb6dd
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/DbContextAttribute.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Attributes;
+
+public class DbContextAttribute : GenericAttribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/DisplayOnlyAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/DisplayOnlyAttribute.cs
new file mode 100644
index 00000000..b6135d73
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/DisplayOnlyAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property)]
+public class DisplayOnlyAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/ExpressionAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/ExpressionAttribute.cs
new file mode 100644
index 00000000..f1c43ef0
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/ExpressionAttribute.cs
@@ -0,0 +1,12 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Field)]
+public class ExpressionAttribute : Attribute
+{
+ public ExpressionAttribute(string expression)
+ {
+ this.Expression = expression;
+ }
+
+ public string Expression { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/GenericAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/GenericAttribute.cs
new file mode 100644
index 00000000..b094122f
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/GenericAttribute.cs
@@ -0,0 +1,12 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class GenericAttribute : Attribute, ITypeAttribute
+{
+ public Type Type => typeof(T);
+}
+
+public interface ITypeAttribute
+{
+ Type Type { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/GroupAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/GroupAttribute.cs
new file mode 100644
index 00000000..d6e16fcd
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/GroupAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class GroupAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/HiddenAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/HiddenAttribute.cs
new file mode 100644
index 00000000..8abe2cc7
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/HiddenAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+public class HiddenAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/HtmlClassAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/HtmlClassAttribute.cs
new file mode 100644
index 00000000..15566cbb
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/HtmlClassAttribute.cs
@@ -0,0 +1,13 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Method)]
+public class HtmlClassAttribute : Attribute
+{
+ public HtmlClassAttribute(string @class)
+ {
+ this.Class = @class;
+ }
+
+ public static string Default { get; } = "el-button--primary";
+ public string? Class { get; } = Default;
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/IconAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/IconAttribute.cs
new file mode 100644
index 00000000..d59dae0c
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/IconAttribute.cs
@@ -0,0 +1,14 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class IconAttribute : Attribute
+{
+ public IconAttribute(string icon)
+ {
+ this.Icon = icon;
+ }
+
+ public static string File { get; } = "file";
+ public static string Folder { get; } = "folder";
+ public string? Icon { get; } = File;
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/IgnoreMultiTenancyAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/IgnoreMultiTenancyAttribute.cs
new file mode 100644
index 00000000..162e8eef
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/IgnoreMultiTenancyAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class IgnoreMultiTenancyAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/IgnoreUpdateAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/IgnoreUpdateAttribute.cs
new file mode 100644
index 00000000..57be59d7
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/IgnoreUpdateAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property)]
+public class IgnoreUpdateAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/ImplementAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/ImplementAttribute.cs
new file mode 100644
index 00000000..45adf5f7
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/ImplementAttribute.cs
@@ -0,0 +1,26 @@
+using Microsoft.Extensions.DependencyInjection;
+using WTA.Shared.DependencyInjection;
+
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+public class ImplementAttribute : Attribute, IImplementAttribute
+{
+ public ImplementAttribute(ServiceLifetime lifetime = ServiceLifetime.Transient, PlatformType platformType = PlatformType.All)
+ {
+ this.ServiceType = typeof(T);
+ this.Lifetime = lifetime;
+ this.PlatformType = platformType;
+ }
+
+ public ServiceLifetime Lifetime { get; set; }
+ public PlatformType PlatformType { get; set; }
+ public Type ServiceType { get; }
+}
+
+public interface IImplementAttribute
+{
+ ServiceLifetime Lifetime { get; }
+ PlatformType PlatformType { get; }
+ Type ServiceType { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/ImporterHeaderAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/ImporterHeaderAttribute.cs
new file mode 100644
index 00000000..ba72fb38
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/ImporterHeaderAttribute.cs
@@ -0,0 +1,11 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property)]
+public class ImporterHeaderAttribute : Attribute
+{
+ public string Name { get; set; } = null!;
+ public bool IsIgnore { get; set; }
+ public bool IsAllowRepeat { get; set; }
+ public string ShowInputMessage { get; set; } = null!;
+ public string Format { get; set; } = null!;
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/ModuleAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/ModuleAttribute.cs
new file mode 100644
index 00000000..bf8259c2
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/ModuleAttribute.cs
@@ -0,0 +1,5 @@
+namespace WTA.Shared.Attributes;
+
+public class ModuleAttribute : GenericAttribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/MultipleAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/MultipleAttribute.cs
new file mode 100644
index 00000000..75e6da2c
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/MultipleAttribute.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Method)]
+public class MultipleAttribute : Attribute
+{
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/NavigationAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/NavigationAttribute.cs
new file mode 100644
index 00000000..5ebae6b0
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/NavigationAttribute.cs
@@ -0,0 +1,12 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property)]
+public class NavigationAttribute : Attribute
+{
+ public NavigationAttribute(string? path = null)
+ {
+ this.Path = path;
+ }
+
+ public string? Path { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/OperatorTypeAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/OperatorTypeAttribute.cs
new file mode 100644
index 00000000..308dc596
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/OperatorTypeAttribute.cs
@@ -0,0 +1,16 @@
+using WTA.Shared.Data;
+
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
+public class OperatorTypeAttribute : Attribute
+{
+ public OperatorTypeAttribute(OperatorType operatorType, string? propertyName = null)
+ {
+ this.OperatorType = operatorType;
+ this.PropertyName = propertyName;
+ }
+
+ public OperatorType OperatorType { get; }
+ public string? PropertyName { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/OptionsAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/OptionsAttribute.cs
new file mode 100644
index 00000000..af5307b2
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/OptionsAttribute.cs
@@ -0,0 +1,12 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class OptionsAttribute : Attribute
+{
+ public OptionsAttribute(string? section = null)
+ {
+ this.Section = section;
+ }
+
+ public string? Section { get; }
+}
diff --git a/docs/demo/src/WTA.Shared/Attributes/OrderAttribute.cs b/docs/demo/src/WTA.Shared/Attributes/OrderAttribute.cs
new file mode 100644
index 00000000..cca7c194
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Attributes/OrderAttribute.cs
@@ -0,0 +1,13 @@
+namespace WTA.Shared.Attributes;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+public class OrderAttribute : Attribute
+{
+ public OrderAttribute(int order)
+ {
+ this.Order = order;
+ }
+
+ public static int Default { get; }
+ public int? Order { get; } = Default;
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/AuthenticateResult.cs b/docs/demo/src/WTA.Shared/Authentication/AuthenticateResult.cs
new file mode 100644
index 00000000..0d1831dc
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/AuthenticateResult.cs
@@ -0,0 +1,11 @@
+namespace WTA.Shared.Authentication;
+
+public class AuthenticateResult
+{
+ public bool Succeeded { get; set; }
+ public bool Failed { get; set; }
+ public bool EnableColumnLimit { get; set; }
+ public bool EnableRowLimit { get; set; }
+ public List Columns { get; set; } = new List();
+ public List Rows { get; set; } = new List();
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/CustomClaimsPrincipal.cs b/docs/demo/src/WTA.Shared/Authentication/CustomClaimsPrincipal.cs
new file mode 100644
index 00000000..b88dab76
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/CustomClaimsPrincipal.cs
@@ -0,0 +1,44 @@
+using System.Security.Claims;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using WTA.Shared.Extensions;
+
+namespace WTA.Shared.Authentication;
+
+public class CustomClaimsPrincipal : ClaimsPrincipal
+{
+ private readonly IServiceProvider _serviceProvider;
+
+ public CustomClaimsPrincipal(IServiceProvider serviceProvider, ClaimsPrincipal claimsPrincipal) : base(claimsPrincipal)
+ {
+ this._serviceProvider = serviceProvider;
+ }
+
+ public AuthenticateResult? Result { get; private set; }
+
+ public override bool IsInRole(string role)
+ {
+ var permissionService = this._serviceProvider.GetService();
+ if (permissionService != null)
+ {
+ // 优先使用本地验è¯
+ this.Result = permissionService.Authenticate(this.Identity?.Name!, role);
+ }
+ else
+ {
+ var configuration = this._serviceProvider.GetRequiredService();
+ var authServer = configuration.GetValue("AuthServer") ?? throw new ArgumentException($"AuthServer 未é…ç½®");
+ var url = $"{authServer.TrimEnd('/')}/user/is-in-role";
+ var httpClientFactory = this._serviceProvider.GetRequiredService();
+ var client = httpClientFactory.CreateClient();
+ var data = new Dictionary
+ {
+ { "name", this.Identity?.Name! },
+ { "role", role },
+ };
+ var response = client.PostAsync(url, new FormUrlEncodedContent(data)).Result;
+ this.Result = response.Content.ReadAsStringAsync().Result.FromJson()!;
+ }
+ return this.Result.Succeeded;
+ }
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/CustomJwtBearerPostConfigureOptions.cs b/docs/demo/src/WTA.Shared/Authentication/CustomJwtBearerPostConfigureOptions.cs
new file mode 100644
index 00000000..d389ec18
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/CustomJwtBearerPostConfigureOptions.cs
@@ -0,0 +1,21 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.Extensions.Options;
+
+namespace WTA.Shared.Authentication;
+
+public class CustomJwtBearerPostConfigureOptions : JwtBearerPostConfigureOptions, IPostConfigureOptions
+{
+ private readonly CustomJwtSecurityTokenHandler _customJwtSecurityTokenHandler;
+
+ public CustomJwtBearerPostConfigureOptions(CustomJwtSecurityTokenHandler customJwtSecurityTokenHandler)
+ {
+ this._customJwtSecurityTokenHandler = customJwtSecurityTokenHandler;
+ }
+
+ public new void PostConfigure(string? name, JwtBearerOptions options)
+ {
+ options.SecurityTokenValidators.Clear();
+ options.SecurityTokenValidators.Add(this._customJwtSecurityTokenHandler);
+ base.PostConfigure(name, options);
+ }
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/CustomJwtSecurityTokenHandler.cs b/docs/demo/src/WTA.Shared/Authentication/CustomJwtSecurityTokenHandler.cs
new file mode 100644
index 00000000..1dfcbd9a
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/CustomJwtSecurityTokenHandler.cs
@@ -0,0 +1,20 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using Microsoft.IdentityModel.Tokens;
+
+namespace WTA.Shared.Authentication;
+
+public class CustomJwtSecurityTokenHandler : JwtSecurityTokenHandler
+{
+ private readonly IServiceProvider _serviceProvider;
+
+ public CustomJwtSecurityTokenHandler(IServiceProvider serviceProvider)
+ {
+ this._serviceProvider = serviceProvider;
+ }
+
+ public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
+ {
+ return new CustomClaimsPrincipal(this._serviceProvider, base.ValidateToken(token, validationParameters, out validatedToken));
+ }
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/IAuthenticationService.cs b/docs/demo/src/WTA.Shared/Authentication/IAuthenticationService.cs
new file mode 100644
index 00000000..d1f5e061
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/IAuthenticationService.cs
@@ -0,0 +1,6 @@
+namespace WTA.Shared.Authentication;
+
+public interface IAuthenticationService
+{
+ AuthenticateResult Authenticate(string name, string operation);
+}
diff --git a/docs/demo/src/WTA.Shared/Authentication/IdentityOptions.cs b/docs/demo/src/WTA.Shared/Authentication/IdentityOptions.cs
new file mode 100644
index 00000000..817574ba
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Authentication/IdentityOptions.cs
@@ -0,0 +1,14 @@
+namespace WTA.Shared.Authentication;
+
+public class IdentityOptions
+{
+ public const string Position = "Identity";
+ public string Issuer { get; set; } = "value";
+ public string Audience { get; set; } = "value";
+ public string Key { get; set; } = "0123456789abcdef0123456789abcdef";
+ public TimeSpan AccessTokenExpires { get; set; } = TimeSpan.FromMinutes(10);
+ public TimeSpan RefreshTokenExpires { get; set; } = TimeSpan.FromDays(14);
+ public bool SupportsUserLockout { get; set; } = true;
+ public int MaxFailedAccessAttempts { get; set; } = 5;
+ public TimeSpan DefaultLockoutTimeSpan { get; set; } = TimeSpan.FromMinutes(10);
+}
diff --git a/docs/demo/src/WTA.Shared/Captcha/CaptchaService.cs b/docs/demo/src/WTA.Shared/Captcha/CaptchaService.cs
new file mode 100644
index 00000000..2b4dfac4
--- /dev/null
+++ b/docs/demo/src/WTA.Shared/Captcha/CaptchaService.cs
@@ -0,0 +1,20 @@
+using SkiaSharp;
+using WTA.Shared.Attributes;
+
+namespace WTA.Shared.Captcha;
+
+[Implement