Compare commits
69 Commits
Author | SHA1 | Date |
---|---|---|
p53209761 | 351a86ba4b | |
p53209761 | 81b7a18773 | |
Argo-Lenovo | 760c83457a | |
Argo-Lenovo | c4eeda3ae8 | |
Argo-Lenovo | 544441a5fc | |
Argo-Lenovo | 4686a75744 | |
Argo-Lenovo | 9be53cf009 | |
Argo-Lenovo | 312f771313 | |
Argo-Lenovo | 234063b3bd | |
Argo-Lenovo | 43cb329757 | |
Argo-Lenovo | c0d21fcbb6 | |
Argo-Lenovo | 994f439d40 | |
Argo-Lenovo | 8bf3f20fa5 | |
Argo-Lenovo | c8329d5b84 | |
Argo-Lenovo | ea461e433e | |
Argo-Lenovo | 213e9155a5 | |
Argo-Lenovo | e3b67c9427 | |
Argo-Lenovo | 35cc0f5174 | |
OneNewPerson | 9343a9522e | |
Argo-Lenovo | 026b1bb990 | |
Argo-Lenovo | f030cb4be9 | |
zhangpeihang | 3f6834de5f | |
Argo-Lenovo | 08df8d8da0 | |
zhangpeihang | e9c5bd2c08 | |
Argo-Lenovo | 2ef69da9e1 | |
Argo-Lenovo | ed5790ff72 | |
Argo-Lenovo | 5d4de2c766 | |
zhangpeihang | 9a02d45e27 | |
zhangpeihang | ab6e260b6b | |
Argo-Lenovo | 0e58b81d19 | |
Argo-Lenovo | 34e376d712 | |
Argo-Lenovo | b96aab631f | |
Argo-Lenovo | 09bf567698 | |
Argo-Lenovo | 2481a4a577 | |
Argo-Lenovo | f7b2c059ef | |
Argo-Lenovo | 7a95ddc039 | |
Argo-Lenovo | 9dfd95ce41 | |
Argo-Lenovo | 371d188d76 | |
Argo-Lenovo | 134d0ee8a8 | |
Argo-Lenovo | 4995899c4c | |
Argo-Lenovo | 6ccbadd1ea | |
Argo-Lenovo | 8c3999c265 | |
Nine | c78fbcf87c | |
Argo | 89b9bf7e3a | |
Argo-Tianyi | c516a0064d | |
Argo-Tianyi | 13e5b282e9 | |
Argo-Tianyi | 3f9555273b | |
Argo-Tianyi | 83524b4acc | |
Argo-Tianyi | eb6abb32fe | |
Argo-Tianyi | 013c05c740 | |
Argo-Tianyi | 5a1b8602dd | |
Argo-Tianyi | 399fb4a700 | |
Argo-Tianyi | 05cc1f549c | |
zhangpeihang | 6fa2a7e2f1 | |
Argo-Tianyi | 65d9d4563a | |
Argo-Tianyi | 4a468f9186 | |
Argo-Lenovo | e4b2f70ae3 | |
Argo-Lenovo | 41b0dce852 | |
Argo-Lenovo | 188470bc1d | |
Argo-Lenovo | 92e3aa4c35 | |
Argo-Tianyi | 5e136d1815 | |
Argo-Tianyi | 7506665052 | |
Argo-Tianyi | fc2f0e84b2 | |
Argo-Tianyi | 6ba2ef3a96 | |
Argo-Tianyi | 2674c6278d | |
Argo-Tianyi | 6e881fbff4 | |
Argo-Tianyi | 135f0615f5 | |
Argo-Tianyi | a53c0cd791 | |
Argo-Tianyi | 71d5ff0a24 |
|
@ -11,10 +11,7 @@
|
|||
"src\\blazor\\client\\BootstrapClient.Shared\\BootstrapClient.Web.Shared.csproj",
|
||||
"src\\blazor\\client\\BootstrapClient.Web.Core\\BootstrapClient.Web.Core.csproj",
|
||||
"src\\blazor\\client\\BootstrapClient.Web.Models\\BootstrapClient.DataAccess.Models.csproj",
|
||||
"src\\blazor\\client\\BootstrapClient.Web\\BootstrapClient.Web.csproj",
|
||||
"src\\mvc\\admin\\Bootstrap.Admin\\Bootstrap.Admin.csproj",
|
||||
"src\\mvc\\admin\\Bootstrap.DataAccess\\Bootstrap.DataAccess.csproj",
|
||||
"test\\UnitTest\\UnitTest.csproj"
|
||||
"src\\blazor\\client\\BootstrapClient.Web\\BootstrapClient.Web.csproj"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -157,7 +157,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.Web", "src\
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootStarpAdmin.DataAccess.FreeSql", "src\blazor\admin\BootStarpAdmin.DataAccess.FreeSql\BootStarpAdmin.DataAccess.FreeSql.csproj", "{11122D97-B349-4A3E-B7DD-73B8B363C47C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootStarpAdmin.DataAccess.SqlSugar", "src\blazor\admin\BootStarpAdmin.DataAccess.SqlSugar\BootStarpAdmin.DataAccess.SqlSugar.csproj", "{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootStarpAdmin.DataAccess.SqlSugar", "src\blazor\admin\BootStarpAdmin.DataAccess.SqlSugar\BootStarpAdmin.DataAccess.SqlSugar.csproj", "{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.Web.Core", "src\blazor\client\BootstrapClient.Web.Core\BootstrapClient.Web.Core.csproj", "{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}"
|
||||
EndProject
|
||||
|
|
184
README.md
184
README.md
|
@ -1,178 +1,8 @@
|
|||
# BootstrapAdmin
|
||||
# 第一点
|
||||
## 部署手册
|
||||
|
||||
<span>English</span> | <a href="README.zh-CN.md">中文</a>
|
||||
|
||||
---
|
||||
|
||||
##### Version & Coverage
|
||||
[![Release](https://img.shields.io/endpoint.svg?logo=Groupon&logoColor=red&color=green&label=release&url=https://admin.blazor.zone/api/Gitee/Releases?userName=LongbowEnterprise)](https://gitee.com/LongbowEnterprise/BootstrapAdmin/releases)
|
||||
[![Coveralls](https://img.shields.io/coveralls/github/ArgoZhang/BootstrapAdmin/master.svg?logo=ReverbNation&logoColor=green&label=coveralls)](https://coveralls.io/github/ArgoZhang/BootstrapAdmin)
|
||||
[![Codecov](https://img.shields.io/codecov/c/gh/argozhang/bootstrapadmin/master.svg?logo=codecov&label=codecov)](https://codecov.io/gh/argozhang/bootstrapadmin/branch/master)
|
||||
|
||||
##### Gitee
|
||||
[![Appveyor build](https://img.shields.io/endpoint.svg?logo=appveyor&label=build&color=blueviolet&url=https://admin.blazor.zone/api/Gitee/Builds?projName=bootstrapadmin-9m1jm)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin-9m1jm)
|
||||
[![Build Status](https://img.shields.io/appveyor/ci/ArgoZhang/bootstrapadmin-9m1jm/master.svg?logo=appveyor&label=master)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin-9m1jm/branch/master)
|
||||
[![Test](https://img.shields.io/appveyor/tests/ArgoZhang/bootstrapadmin-9m1jm/master.svg?logo=appveyor&)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin-9m1jm/branch/master/tests)
|
||||
[![Issue Status](https://img.shields.io/endpoint.svg?logo=Groupon&logoColor=critical&label=issues&url=https://admin.blazor.zone/api/Gitee/Issues?userName=LongbowEnterprise)](https://gitee.com/LongbowEnterprise/BootstrapAdmin/issues)
|
||||
[![Pull Status](https://img.shields.io/endpoint.svg?logo=Groupon&logoColor=green&color=success&label=pulls&url=https://admin.blazor.zone/api/Gitee/Pulls?userName=LongbowEnterprise)](https://gitee.com/LongbowEnterprise/BootstrapAdmin/pulls)
|
||||
|
||||
##### GitHub
|
||||
[![Appveyor build](https://img.shields.io/endpoint.svg?logo=appveyor&label=build&color=blueviolet&url=https://admin.blazor.zone/api/Gitee/Builds?projName=bootstrapadmin)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin)
|
||||
[![master status](https://img.shields.io/appveyor/ci/ArgoZhang/bootstrapadmin/master.svg?logo=appveyor&label=master)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin/branch/master)
|
||||
[![Test](https://img.shields.io/appveyor/tests/argozhang/bootstrapadmin/master.svg?logo=appveyor&)](https://ci.appveyor.com/project/ArgoZhang/bootstrapadmin/branch/master/tests)
|
||||
[![Github build](https://img.shields.io/github/workflow/status/ArgoZhang/BootstrapAdmin/Auto%20Build%20CI/master?label=master&logoColor=green&logo=github)](https://github.com/ArgoZhang/BootstrapAdmin/actions?query=workflow%3A%22Auto+Build+CI%22+branch%3Amaster)
|
||||
[![Repo Size](https://img.shields.io/github/repo-size/ArgoZhang/BootstrapAdmin.svg?logo=github&logoColor=green&label=repo)](https://github.com/ArgoZhang/BootstrapAdmin)
|
||||
[![Commit Date](https://img.shields.io/github/last-commit/ArgoZhang/BootstrapAdmin/master.svg?logo=github&logoColor=green&label=commit)](https://github.com/ArgoZhang/BootstrapAdmin)
|
||||
|
||||
## Introduce
|
||||
Because the dependent on Bootstrap v4, so it is called **Bootstrap Admin**. This system can be integrated with asp.net and asp.net core applications. The database supports multiple databases at the same time. The detailed list is shown in the following **database** detailed list. Switching the data source only needs to change the configuration file without restarting the application. The configuration is simple and flexible. The UI front-end uses the popular Bootstrap framework layout, which is very compatible with mobile devices and adapts to almost all terminal devices in the current market. The system also has the feature of single background supporting multi-front desk, and provides the ability of **single sign-on (SSO)**.
|
||||
|
||||
### Notes
|
||||
Bootstrap Admin does not require secondary development, but only integration with the front-end system. The front-end system model project is **Bootstrap. Client**
|
||||
The original starting point of the project is to separate the privilege system from the business system. The project development focuses on functions. For detailed configuration instructions, please click on [View Documents](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/%E7%B3%BB%E7%BB%9F%E9%89B%86%E6%88%90).
|
||||
|
||||
### Features
|
||||
1. Integration with Front-end Website through Configuration
|
||||
2. Constructing Hierarchical Menu of Front-end System
|
||||
3. Provide a single background to support multiple front-end application configurations
|
||||
4. Provide single sign-on(SSO)
|
||||
5. Integrated System Authentication and Authorization Module
|
||||
6. Provide role, department, user, menu, foreground application authorization
|
||||
Role Authorization to Users
|
||||
Role-to-Menu Authorization
|
||||
Role Authorization to Departments
|
||||
Role-to-application authorization (multiple front-end applications share a back-end privilege management system)
|
||||
Departments Authorize Users
|
||||
7. Provide dictionary tables for personalized configuration of front-end websites
|
||||
8. Fully responsive layout (supporting all mainstream devices such as computers, tablets, mobile phones, etc.)
|
||||
9. Built-in multi-data source support, simple configuration and immediate effect without restart
|
||||
10. Built-in data memory caching mechanism, page fast response
|
||||
11. Built-in Data **Operation Log** and User **Log on**
|
||||
|
||||
[Update log](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/更新日志)
|
||||
|
||||
### Advantage
|
||||
1. The front-end system does not need to write login, authorization and authentication modules; it is only responsible for writing business modules.
|
||||
2. Background system can be used directly without any secondary development.
|
||||
3. Front-end and back-end systems are separated, which are different systems (domain name can be independent)
|
||||
4. Extensible to multi-tenant applications
|
||||
|
||||
For more information, please click [wiki](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D)
|
||||
|
||||
### Database
|
||||
**MSSQL/Oracle/SQLite/MySql/MariaDB/Firebird/MongoDB**
|
||||
|
||||
For more information, please click [wiki](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/数据库连接配置?sort_id=1333482)
|
||||
|
||||
### Browser
|
||||
![chrome](https://img.shields.io/badge/chrome->%3D4.5-success.svg?logo=google%20chrome&logoColor=red)
|
||||
![firefox](https://img.shields.io/badge/firefox->38-success.svg?logo=mozilla%20firefox&logoColor=red)
|
||||
![edge](https://img.shields.io/badge/edge->%3D12-success.svg?logo=microsoft%20edge&logoColor=blue)
|
||||
![ie](https://img.shields.io/badge/ie->%3D11-success.svg?logo=internet%20explorer&logoColor=blue)
|
||||
![Safari](https://img.shields.io/badge/safari->%3D9-success.svg?logo=safari&logoColor=blue)
|
||||
![Andriod](https://img.shields.io/badge/andriod->%3D4.4-success.svg?logo=android)
|
||||
![oper](https://img.shields.io/badge/opera->%3D3.0-success.svg?logo=opera&logoColor=red)
|
||||
|
||||
```json
|
||||
"browserslist": [
|
||||
"Chrome >= 45",
|
||||
"Firefox >= 38",
|
||||
"Edge >= 12",
|
||||
"Explorer >= 11",
|
||||
"iOS >= 9",
|
||||
"Safari >= 9",
|
||||
"Android >= 4.4",
|
||||
"Opera >= 30"
|
||||
]
|
||||
```
|
||||
|
||||
### Mobile
|
||||
![ios](https://img.shields.io/badge/ios-supported-success.svg?logo=apple&logoColor=white)
|
||||
![Andriod](https://img.shields.io/badge/andriod-suported-success.svg?logo=android)
|
||||
![windows](https://img.shields.io/badge/windows-suported-success.svg?logo=windows&logoColor=blue)
|
||||
|
||||
| | **Chrome** | **Firefox** | **Safari** | **Android Browser & WebView** | **Microsoft Edge** |
|
||||
| ------- | --------- | --------- | ------ | ------------------------- | -------------- |
|
||||
| **iOS** | Supported | Supported | Supported | N/A | Supported |
|
||||
| **Android** | Supported | Supported | N/A | Android v5.0+ supported | Supported |
|
||||
| **Windows 10 Mobile** | N/A | N/A | N/A | N/A | Supported |
|
||||
|
||||
### Desktop
|
||||
![macOS](https://img.shields.io/badge/macOS-supported-success.svg?logo=apple&logoColor=white)
|
||||
![linux](https://img.shields.io/badge/linux-suported-success.svg?logo=linux&logoColor=white)
|
||||
![windows](https://img.shields.io/badge/windows-suported-success.svg?logo=windows)
|
||||
|
||||
| | Chrome | Firefox | Internet Explorer | Microsoft Edge | Opera | Safari |
|
||||
| ------- | --------- | --------- | ----------------- | -------------- | --------- | ------------- |
|
||||
| Mac | Supported | Supported | N/A | N/A | Supported | Supported |
|
||||
| Linux | Supported | Supported | N/A | N/A | N/A | N/A |
|
||||
| Windows | Supported | Supported | Supported, IE10+ | Supported | Supported | Not supported |
|
||||
|
||||
## QQ Group
|
||||
[![QQ](https://img.shields.io/badge/QQ-795206915-green.svg?logo=tencent%20qq&logoColor=red)](https://shang.qq.com/wpa/qunwpa?idkey=d381355e50ff91db410c3da3eadb081ba859f64c2877e86343f4709b171f28b8)
|
||||
|
||||
## Installation
|
||||
1. Install .net core sdk [Offical website](http://www.microsoft.com/net/download)
|
||||
2. Install Visual Studio 2019 lastest [Offical website](https://visualstudio.microsoft.com/vs/getting-started/)
|
||||
3. Git clone `git clone https://gitee.com/LongbowEnterprise/BootstrapAdmin.git`
|
||||
4. Login as Admin/123789
|
||||
|
||||
## Branchs
|
||||
[Details](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/分支说明)
|
||||
|
||||
## Online Demonstration
|
||||
[![website1](https://img.shields.io/badge/linux-http://ba.zylweb.cn-success.svg?logo=buzzfeed&logoColor=green)](http://ba.zylweb.cn)
|
||||
[![website2](https://img.shields.io/badge/linux-http://admin.blazor.zone-success.svg?logo=buzzfeed&logoColor=green)](http://admin.blazor.zone)
|
||||
|
||||
### Login
|
||||
Administrator: Admin/123789
|
||||
User: User/123789
|
||||
|
||||
## Docker Images
|
||||
[![Docker](https://img.shields.io/docker/cloud/automated/argozhang/ba.svg?logo=docker&logoColor=success)](https://hub.docker.com/r/argozhang/ba)
|
||||
[![Docker](https://img.shields.io/docker/cloud/build/argozhang/ba.svg?logo=docker&logoColor=success)](https://hub.docker.com/r/argozhang/ba/builds)
|
||||
[![Docker](https://img.shields.io/github/workflow/status/ArgoZhang/BootstrapAdmin/Docker%20Image%20CI/master?label=Docker%20Image%20CI&logo=github&logoColor=green)](https://github.com/ArgoZhang/BootstrapAdmin/actions?query=workflow%3A%22Docker+Image+CI%22%3Amaster)
|
||||
|
||||
### Docker Hub
|
||||
Mirror [Portal](https://hub.docker.com/r/argozhang/ba)
|
||||
```bash
|
||||
docker pull argozhang/ba
|
||||
```
|
||||
### Qiniu Cloud:
|
||||
Mirror [Portal](https://hub.qiniu.com/store/argozhang/ba)
|
||||
```bash
|
||||
docker pull reg.qiniu.com/argozhang/ba
|
||||
```
|
||||
|
||||
## Configurations
|
||||
Detailed configuration instructions please click [wikis](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis)
|
||||
|
||||
## Q&A
|
||||
Please click [wikis](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98Q&A)
|
||||
|
||||
## License
|
||||
[![Gitee license](https://img.shields.io/github/license/argozhang/bootstrapadmin.svg?logo=git&logoColor=red)](https://gitee.com/LongbowEnterprise/BootstrapAdmin/blob/master/LICENSE)
|
||||
|
||||
## GVP award
|
||||
[View](https://images.gitee.com/uploads/images/2021/0112/112021_9d570be1_554725.png "GiteeGVP.png")
|
||||
|
||||
## Screenshots
|
||||
|
||||
Home
|
||||
|
||||
![Home](https://gitee.com/LongbowEnterprise/Pictures/raw/master/BootstrapAdmin/BA02-01.png "BAHome-01.png")
|
||||
|
||||
For more screenshots, Click [wiki](https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis)
|
||||
|
||||
## Contribution
|
||||
|
||||
1. Fork
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit
|
||||
4. Create Pull Request
|
||||
|
||||
## Donate
|
||||
|
||||
If this project is helpful to you, please scan the QR code below for a cup of coffee.
|
||||
|
||||
![WeChat](https://gitee.com/LongbowEnterprise/Pictures/raw/master/WeChat/WeChat.png "WeChat")
|
||||
# 第二点
|
||||
## 环境要求
|
||||
|
||||
# 第三点
|
||||
## 软件要求
|
|
@ -143,16 +143,6 @@ CREATE TABLE Tasks(
|
|||
AssignTime DATE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE RejectUsers(
|
||||
ID SERIAL PRIMARY KEY,
|
||||
UserName VARCHAR (50) NOT NULL,
|
||||
DisplayName VARCHAR (50) NOT NULL,
|
||||
RegisterTime DATE NOT NULL,
|
||||
RejectedBy VARCHAR (50) NOT NULL,
|
||||
RejectedTime DATE NOT NULL,
|
||||
RejectedReason VARCHAR (50) NULL
|
||||
);
|
||||
|
||||
CREATE TABLE RejectUsers(
|
||||
ID SERIAL PRIMARY KEY,
|
||||
UserName VARCHAR (50) NOT NULL,
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.7" />
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.0.100" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.8.13" />
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.665" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -24,6 +24,10 @@ static class FreeSqlExtensions
|
|||
i.Property(n => n.Period).IsIgnore(true);
|
||||
i.Property(n => n.IsReset).IsIgnore(true);
|
||||
});
|
||||
freeSql.CodeFirst.ConfigEntity<Trace>(i =>
|
||||
{
|
||||
i.Name("Traces");
|
||||
});
|
||||
freeSql.CodeFirst.ConfigEntity<Group>(i =>
|
||||
{
|
||||
i.Name("Groups");
|
||||
|
|
|
@ -24,6 +24,9 @@ public static class ServiceCollectionExtensions
|
|||
/// <returns></returns>
|
||||
public static IServiceCollection AddFreeSql(this IServiceCollection services, Action<IServiceProvider, FreeSqlBuilder> freeSqlBuilder)
|
||||
{
|
||||
|
||||
// 增加缓存服务
|
||||
services.AddCacheManager();
|
||||
services.TryAddSingleton<IFreeSql>(provider =>
|
||||
{
|
||||
var builder = new FreeSqlBuilder();
|
||||
|
@ -45,6 +48,7 @@ public static class ServiceCollectionExtensions
|
|||
services.AddSingleton<INavigation, NavigationService>();
|
||||
services.AddSingleton<IRole, RoleService>();
|
||||
services.AddSingleton<IUser, UserService>();
|
||||
services.AddSingleton<ITrace, TraceService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using BootstrapAdmin.DataAccess.Models;
|
|||
using BootstrapAdmin.Web.Core;
|
||||
using Longbow.Security.Cryptography;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Data;
|
||||
|
||||
namespace BootStarpAdmin.DataAccess.FreeSql.Service;
|
||||
|
||||
|
@ -175,23 +176,284 @@ class DictService : IDict
|
|||
return url;
|
||||
}
|
||||
|
||||
public bool SavDefaultApp(bool enabled)
|
||||
public bool SavDefaultApp(bool enabled) => SaveDict(new Dict
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
Category = "网站设置",
|
||||
Name = "默认应用程序",
|
||||
Code = enabled ? "1" : "0",
|
||||
Define = EnumDictDefine.System
|
||||
});
|
||||
|
||||
public bool GetEnableDefaultApp()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var dicts = GetAll();
|
||||
var code = dicts.FirstOrDefault(d => d.Category == "网站设置" && d.Name == "默认应用程序")?.Code ?? "0";
|
||||
return code == "1";
|
||||
}
|
||||
|
||||
public string GetIconFolderPath()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(d => d.Name == "头像路径" && d.Category == "头像地址" && d.Define == EnumDictDefine.System)?.Code ?? "/images/uploder/";
|
||||
}
|
||||
|
||||
public string GetDefaultIcon()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(d => d.Name == "头像文件" && d.Category == "头像地址" && d.Define == EnumDictDefine.System)?.Code ?? "default.jpg";
|
||||
}
|
||||
|
||||
public string? GetIpLocatorName()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "IP地理位置接口" && s.Define == EnumDictDefine.System)?.Code;
|
||||
}
|
||||
|
||||
public string? GetIpLocatorUrl(string? name)
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return string.IsNullOrWhiteSpace(name) ? null : dicts.FirstOrDefault(s => s.Category == "地理位置" && s.Name == name && s.Define == EnumDictDefine.System)?.Code;
|
||||
}
|
||||
|
||||
public bool GetAppSiderbar()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "侧边栏状态" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppSiderbar(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "侧边栏状态", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAppTitle()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "卡片标题状态" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppTitle(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "卡片标题状态", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAppFixHeader()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "固定表头" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppFixHeader(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "固定表头", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAppHealthCheck()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "健康检查" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppHealthCheck(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "健康检查", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAppMobileLogin()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "短信验证码登录" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppMobileLogin(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "短信验证码登录", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAppOAuthLogin()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "OAuth 认证登录" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAppOAuthLogin(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "OAuth 认证登录", Code = value ? "1" : "0" });
|
||||
|
||||
public bool GetAutoLockScreen()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "自动锁屏" && s.Define == EnumDictDefine.System)?.Code == "1";
|
||||
}
|
||||
|
||||
public bool SaveAutoLockScreen(bool value) => SaveDict(new Dict { Category = "网站设置", Name = "自动锁屏", Code = value ? "1" : "0" });
|
||||
|
||||
public int GetAutoLockScreenInterval()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "自动锁屏时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveAutoLockScreenInterval(int value) => SaveDict(new Dict { Category = "网站设置", Name = "自动锁屏时长", Code = value.ToString() });
|
||||
|
||||
public Dictionary<string, string> GetIpLocators()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.Where(d => d.Category == "地理位置服务").Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).OrderBy(i => i.Value).ToDictionary(i => i.Key, i => i.Value);
|
||||
}
|
||||
|
||||
public string? GetIpLocator()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "IP地理位置接口" && s.Define == EnumDictDefine.System)?.Code;
|
||||
}
|
||||
|
||||
public bool SaveCurrentIp(string value) => SaveDict(new Dict { Category = "网站设置", Name = "IP地理位置接口", Code = value });
|
||||
|
||||
public int GetCookieExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "Cookie保留时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveCookieExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "Cookie保留时长", Code = value.ToString() });
|
||||
|
||||
public int GetExceptionExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "程序异常保留时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveExceptionExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "程序异常保留时长", Code = value.ToString() });
|
||||
|
||||
public int GetOperateExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "操作日志保留时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveOperateExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "操作日志保留时长", Code = value.ToString() });
|
||||
|
||||
public int GetLoginExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "登录日志保留时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveLoginExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "登录日志保留时长", Code = value.ToString() });
|
||||
|
||||
public int GetAccessExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "访问日志保留时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveAccessExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "访问日志保留时长", Code = value.ToString() });
|
||||
|
||||
public int GetIPCacheExpired()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
var value = dicts.FirstOrDefault(s => s.Category == "网站设置" && s.Name == "IP请求缓存时长" && s.Define == EnumDictDefine.System)?.Code ?? "0";
|
||||
_ = int.TryParse(value, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool SaveIPCacheExpired(int value) => SaveDict(new Dict { Category = "网站设置", Name = "IP请求缓存时长", Code = value.ToString() });
|
||||
|
||||
public Dictionary<string, string>? GetClients()
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.Where(s => s.Category == "应用程序" && s.Code != "BA").ToDictionary(s => s.Name, s => s.Code);
|
||||
}
|
||||
|
||||
public string GetClientUrl(string name)
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.Where(s => s.Category == "应用首页" && s.Name == name).FirstOrDefault()?.Code ?? "";
|
||||
}
|
||||
|
||||
public bool ExistsAppId(string appId)
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return dicts.Exists(s => s.Category == "应用程序" && s.Code == appId);
|
||||
}
|
||||
|
||||
public bool SaveClient(ClientApp client)
|
||||
{
|
||||
var ret = false;
|
||||
if (!string.IsNullOrEmpty(client.AppId))
|
||||
{
|
||||
DeleteClient(client.AppId);
|
||||
try
|
||||
{
|
||||
var items = new List<Dict>()
|
||||
{
|
||||
new Dict { Category = "应用程序", Name = client.AppName, Code = client.AppId, Define = EnumDictDefine.System },
|
||||
new Dict { Category = "应用首页", Name = client.AppId, Code = client.HomeUrl, Define = EnumDictDefine.System },
|
||||
new Dict { Category = client.AppId, Name = "网站页脚", Code = client.Footer, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "网站标题", Code = client.Title, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "favicon", Code = client.Favicon, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "网站图标", Code = client.Icon, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "个人中心地址", Code = client.ProfileUrl, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "系统设置地址", Code = client.SettingsUrl, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "系统通知地址", Code = client.NotificationUrl, Define = EnumDictDefine.Customer }
|
||||
};
|
||||
|
||||
ret = FreeSql.Insert(items).ExecuteAffrows() > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ClientApp GetClient(string appId)
|
||||
{
|
||||
var dicts = GetAll();
|
||||
return new ClientApp()
|
||||
{
|
||||
AppId = appId,
|
||||
AppName = dicts.FirstOrDefault(s => s.Category == "应用程序" && s.Code == appId)?.Name,
|
||||
HomeUrl = dicts.FirstOrDefault(s => s.Category == "应用首页" && s.Name == appId)?.Code,
|
||||
ProfileUrl = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "个人中心地址")?.Code,
|
||||
SettingsUrl = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "系统设置地址")?.Code,
|
||||
NotificationUrl = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "系统通知地址")?.Code,
|
||||
Title = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "网站标题")?.Code,
|
||||
Footer = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "网站页脚")?.Code,
|
||||
Icon = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "网站图标")?.Code,
|
||||
Favicon = dicts.FirstOrDefault(s => s.Category == appId && s.Name == "favicon")?.Code,
|
||||
};
|
||||
}
|
||||
|
||||
public bool DeleteClient(string appId)
|
||||
{
|
||||
bool ret;
|
||||
try
|
||||
{
|
||||
FreeSql.Transaction(() =>
|
||||
{
|
||||
FreeSql.Ado.ExecuteNonQuery("delete Dicts where Category=@Category and Name=@Name and Define=@Define", new { Category = "应用首页", Name = appId, Define = EnumDictDefine.System });
|
||||
FreeSql.Ado.ExecuteNonQuery("delete Dicts where Category=@Category and Code=@Code and Define=@Define", new { Category = "应用程序", Code = appId, Define = EnumDictDefine.System });
|
||||
FreeSql.Ado.ExecuteNonQuery("delete Dicts where Category=@Category and Name in (@Names)", new
|
||||
{
|
||||
Category = appId,
|
||||
Names = new List<string>
|
||||
{
|
||||
"网站标题",
|
||||
"网站页脚",
|
||||
"favicon",
|
||||
"网站图标",
|
||||
"个人中心地址",
|
||||
"系统设置地址",
|
||||
"系统通知地址"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,31 @@
|
|||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
|
||||
namespace BootStarpAdmin.DataAccess.FreeSql.Service;
|
||||
|
||||
class LoginService : ILogin
|
||||
{
|
||||
public Task<bool> Log(string userName, bool result)
|
||||
private IFreeSql FreeSql { get; }
|
||||
|
||||
public LoginService(IFreeSql freeSql) => FreeSql = freeSql;
|
||||
|
||||
public bool Log(string userName, string? IP, string? OS, string? browser, string? address, string? userAgent, bool result)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
var loginUser = new LoginLog()
|
||||
{
|
||||
UserName = userName,
|
||||
LoginTime = DateTime.Now,
|
||||
Ip = IP,
|
||||
City = address,
|
||||
OS = OS,
|
||||
Browser = browser,
|
||||
UserAgent = userAgent,
|
||||
Result = result ? "登录成功" : "登录失败"
|
||||
};
|
||||
FreeSql.Insert(loginUser).ExecuteAffrows();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BootStarpAdmin.DataAccess.FreeSql.Service;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class TraceService : ITrace
|
||||
{
|
||||
private IFreeSql FreeSql { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="freeSql"></param>
|
||||
public TraceService(IFreeSql freeSql) => FreeSql = freeSql;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageItems"></param>
|
||||
/// <param name="sortList"></param>
|
||||
/// <returns></returns>
|
||||
public (IEnumerable<Trace> Items, int ItemsCount) GetAll(string? searchText, TraceFilter filter, int pageIndex, int pageItems, List<string> sortList)
|
||||
{
|
||||
var items = FreeSql.Select<Trace>();
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
items.Where("UserName Like @searchText or Ip Like @searchText or RequestUrl Like @searchText", new { searchText });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.UserName))
|
||||
{
|
||||
items.Where("UserName Like @UserName", new { filter.UserName });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.Ip))
|
||||
{
|
||||
items.Where("Ip Like @Ip", new { filter.Ip });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filter.RequestUrl))
|
||||
{
|
||||
items.Where("ErrorPage Like @RequestUrl", new { filter.RequestUrl });
|
||||
}
|
||||
|
||||
items.Where("LogTime >= @0 and LogTime <= @1", new { filter.Star, filter.End });
|
||||
|
||||
if (sortList.Any())
|
||||
{
|
||||
items.OrderBy(string.Join(", ", sortList));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.OrderBy("Logtime desc");
|
||||
}
|
||||
|
||||
var traces = items.Count(out var count).Page(pageIndex, pageItems).ToList();
|
||||
|
||||
return (traces, Convert.ToInt32(count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="trace"></param>
|
||||
public void Log(Trace trace)
|
||||
{
|
||||
FreeSql.Insert(trace).ExecuteAffrows();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.7" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.0.5.2" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.8.13" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.0.9.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -71,9 +71,9 @@ class DefaultCacheManager : ICacheManager
|
|||
{
|
||||
Cache.Remove(key);
|
||||
}
|
||||
else
|
||||
else if (Cache is MemoryCache c)
|
||||
{
|
||||
//Cache.Compact(100);
|
||||
c.Compact(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.9-beta06" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.8.13" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -306,6 +306,7 @@ public class UserService : IUser
|
|||
Password = pwd
|
||||
};
|
||||
dbcontext.Add(user);
|
||||
ret = dbcontext.SaveChanges() > 0;
|
||||
// 授权 Default 角色
|
||||
dbcontext.Database.ExecuteSqlRaw("insert into UserRole (UserID, RoleID) select ID, (select ID from Roles where RoleName = 'Default') RoleId from Users where UserName = {0}", userName);
|
||||
ret = dbcontext.SaveChanges() > 0;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.9-beta06" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.8.13" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.7" />
|
||||
<PackageReference Include="PetaPoco.Extensions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ using BootstrapAdmin.DataAccess.PetaPoco;
|
|||
using BootstrapAdmin.DataAccess.PetaPoco.Services;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapBlazor.Components;
|
||||
using BootstrapBlazor.DataAcces.PetaPoco.Services;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
@ -27,43 +26,10 @@ public static class ServiceCollectionExtensions
|
|||
///
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddPetaPocoDataAccessServices(this IServiceCollection services, Action<IServiceProvider, IDatabaseBuildConfiguration> builder)
|
||||
public static IServiceCollection AddPetaPocoDataAccessServices(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IDatabase>(provider =>
|
||||
{
|
||||
var option = DatabaseConfiguration.Build();
|
||||
builder(provider, option);
|
||||
option.UsingDefaultMapper<BootstrapAdminConventionMapper>();
|
||||
var db = new Database(option);
|
||||
|
||||
var logger = provider.GetRequiredService<ILogger<Database>>();
|
||||
db.ExceptionThrown += (sender, e) =>
|
||||
{
|
||||
var message = e.Exception.Format(new NameValueCollection()
|
||||
{
|
||||
[nameof(db.LastCommand)] = db.LastCommand,
|
||||
[nameof(db.LastArgs)] = string.Join(",", db.LastArgs)
|
||||
});
|
||||
logger.LogError(new EventId(1001, "GlobalException"), e.Exception, message);
|
||||
};
|
||||
var env = provider.GetRequiredService<IWebHostEnvironment>();
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
db.CommandExecuted += (sender, args) =>
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
foreach (DbParameter p in args.Command.Parameters)
|
||||
{
|
||||
parameters.AppendFormat("{0}: {1} ", p.ParameterName, p.Value);
|
||||
}
|
||||
logger.LogInformation(args.Command.CommandText);
|
||||
logger.LogInformation(parameters.ToString());
|
||||
};
|
||||
};
|
||||
return db;
|
||||
});
|
||||
services.TryAddSingleton<IDBManager, DBManagerService>();
|
||||
|
||||
// 增加数据服务
|
||||
services.AddSingleton(typeof(IDataService<>), typeof(DefaultDataService<>));
|
||||
|
|
|
@ -12,29 +12,34 @@ class AppService : IApp
|
|||
{
|
||||
private const string AppServiceGetAppsByRoleIdCacheKey = "AppService-GetAppsByRoleId";
|
||||
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
public AppService(IDatabase db)
|
||||
public AppService(IDBManager db)
|
||||
{
|
||||
Database = db;
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
public List<string> GetAppsByRoleId(string? roleId) => CacheManager.GetOrAdd($"{AppServiceGetAppsByRoleIdCacheKey}-{roleId}", entry => Database.Fetch<string>("select AppID from RoleApp where RoleID = @0", roleId));
|
||||
public List<string> GetAppsByRoleId(string? roleId) => CacheManager.GetOrAdd($"{AppServiceGetAppsByRoleIdCacheKey}-{roleId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select AppID from RoleApp where RoleID = @0", roleId);
|
||||
});
|
||||
|
||||
public bool SaveAppsByRoleId(string? roleId, IEnumerable<string> appIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from RoleApp where RoleID = @0", roleId);
|
||||
Database.InsertBatch("RoleApp", appIds.Select(g => new { AppID = g, RoleID = roleId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from RoleApp where RoleID = @0", roleId);
|
||||
db.InsertBatch("RoleApp", appIds.Select(g => new { AppID = g, RoleID = roleId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PetaPoco;
|
||||
using PetaPoco.Providers;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
||||
|
||||
internal class DBManagerService : IDBManager
|
||||
{
|
||||
private IConfiguration Configuration { get; set; }
|
||||
|
||||
private ILogger<DBManagerService> Logger { get; set; }
|
||||
|
||||
private IWebHostEnvironment WebHost { get; set; }
|
||||
|
||||
public DBManagerService(IConfiguration configuration, ILogger<DBManagerService> logger, IWebHostEnvironment host)
|
||||
{
|
||||
Configuration = configuration;
|
||||
Logger = logger;
|
||||
WebHost = host;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建 IDatabase 实例方法
|
||||
/// </summary>
|
||||
/// <param name="connectionName">连接字符串键值</param>
|
||||
/// <param name="keepAlive"></param>
|
||||
/// <returns></returns>
|
||||
public IDatabase Create(string? connectionName = "ba", bool keepAlive = false)
|
||||
{
|
||||
var conn = Configuration.GetConnectionString(connectionName) ?? throw new ArgumentNullException(nameof(connectionName));
|
||||
|
||||
var option = DatabaseConfiguration.Build();
|
||||
option.UsingDefaultMapper<BootstrapAdminConventionMapper>();
|
||||
|
||||
// connectionstring
|
||||
option.UsingConnectionString(conn);
|
||||
|
||||
// provider
|
||||
option.UsingProvider<SQLiteDatabaseProvider>();
|
||||
|
||||
var db = new Database(option) { KeepConnectionAlive = keepAlive };
|
||||
|
||||
db.ExceptionThrown += (sender, e) =>
|
||||
{
|
||||
var message = e.Exception.Format(new NameValueCollection()
|
||||
{
|
||||
[nameof(db.LastCommand)] = db.LastCommand,
|
||||
[nameof(db.LastArgs)] = string.Join(",", db.LastArgs)
|
||||
});
|
||||
Logger.LogError(new EventId(1001, "GlobalException"), e.Exception, message);
|
||||
};
|
||||
if (WebHost.IsDevelopment())
|
||||
{
|
||||
db.CommandExecuted += (sender, args) =>
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
foreach (DbParameter p in args.Command.Parameters)
|
||||
{
|
||||
parameters.AppendFormat("{0}: {1} ", p.ParameterName, p.Value);
|
||||
}
|
||||
Logger.LogInformation(args.Command.CommandText);
|
||||
Logger.LogInformation(parameters.ToString());
|
||||
};
|
||||
};
|
||||
return db;
|
||||
}
|
||||
}
|
|
@ -9,21 +9,21 @@ using BootstrapBlazor.Components;
|
|||
using PetaPoco;
|
||||
using PetaPoco.Extensions;
|
||||
|
||||
namespace BootstrapBlazor.DataAcces.PetaPoco.Services;
|
||||
namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
||||
|
||||
/// <summary>
|
||||
/// PetaPoco ORM 的 IDataService 接口实现
|
||||
/// </summary>
|
||||
class DefaultDataService<TModel> : DataServiceBase<TModel> where TModel : class, new()
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
private IUser UserService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public DefaultDataService(IDatabase db, IUser userService) => (Database, UserService) = (db, userService);
|
||||
public DefaultDataService(IDBManager db, IUser userService) => (DBManager, UserService) = (db, userService);
|
||||
|
||||
/// <summary>
|
||||
/// 删除方法
|
||||
|
@ -34,7 +34,8 @@ class DefaultDataService<TModel> : DataServiceBase<TModel> where TModel : class,
|
|||
{
|
||||
// 通过模型获取主键列数据
|
||||
// 支持批量删除
|
||||
Database.DeleteBatch(models);
|
||||
using var db = DBManager.Create();
|
||||
db.DeleteBatch(models);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
|
@ -52,13 +53,14 @@ class DefaultDataService<TModel> : DataServiceBase<TModel> where TModel : class,
|
|||
}
|
||||
else
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
if (changedType == ItemChangedType.Add)
|
||||
{
|
||||
await Database.InsertAsync(model);
|
||||
await db.InsertAsync(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Database.UpdateAsync(model);
|
||||
await db.UpdateAsync(model);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -79,16 +81,17 @@ class DefaultDataService<TModel> : DataServiceBase<TModel> where TModel : class,
|
|||
IsAdvanceSearch = option.AdvanceSearchs.Any() || option.CustomerSearchs.Any()
|
||||
};
|
||||
|
||||
using var db = DBManager.Create();
|
||||
if (option.IsPage)
|
||||
{
|
||||
var items = await Database.PageAsync<TModel>(option);
|
||||
var items = await db.PageAsync<TModel>(option);
|
||||
|
||||
ret.TotalCount = Convert.ToInt32(items.TotalItems);
|
||||
ret.Items = items.Items;
|
||||
}
|
||||
else
|
||||
{
|
||||
var items = await Database.FetchAsync<TModel>(option);
|
||||
var items = await db.FetchAsync<TModel>(option);
|
||||
ret.TotalCount = items.Count;
|
||||
ret.Items = items;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class DictService : IDict
|
|||
{
|
||||
private const string DictServiceCacheKey = "DictService-GetAll";
|
||||
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
private string AppId { get; set; }
|
||||
|
||||
|
@ -26,13 +26,17 @@ class DictService : IDict
|
|||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public DictService(IDatabase db, IConfiguration configuration)
|
||||
public DictService(IDBManager db, IConfiguration configuration)
|
||||
{
|
||||
Database = db;
|
||||
DBManager = db;
|
||||
AppId = configuration.GetValue("AppId", "BA");
|
||||
}
|
||||
|
||||
public List<Dict> GetAll() => CacheManager.GetOrAdd(DictServiceCacheKey, entry => Database.Fetch<Dict>());
|
||||
public List<Dict> GetAll() => CacheManager.GetOrAdd(DictServiceCacheKey, entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<Dict>();
|
||||
});
|
||||
|
||||
public Dictionary<string, string> GetApps()
|
||||
{
|
||||
|
@ -178,7 +182,8 @@ class DictService : IDict
|
|||
|
||||
private bool SaveDict(Dict dict)
|
||||
{
|
||||
var ret = Database.Update<Dict>("set Code = @Code where Category = @Category and Name = @Name", dict) == 1;
|
||||
using var db = DBManager.Create();
|
||||
var ret = db.Update<Dict>("set Code = @Code where Category = @Category and Name = @Name", dict) == 1;
|
||||
if (ret)
|
||||
{
|
||||
// 更新缓存
|
||||
|
@ -417,9 +422,10 @@ class DictService : IDict
|
|||
if (!string.IsNullOrEmpty(client.AppId))
|
||||
{
|
||||
DeleteClient(client.AppId);
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
db.BeginTransaction();
|
||||
var items = new List<Dict>()
|
||||
{
|
||||
new Dict { Category = "应用程序", Name = client.AppName, Code = client.AppId, Define = EnumDictDefine.System },
|
||||
|
@ -432,13 +438,13 @@ class DictService : IDict
|
|||
new Dict { Category = client.AppId, Name = "系统设置地址", Code = client.SettingsUrl, Define = EnumDictDefine.Customer },
|
||||
new Dict { Category = client.AppId, Name = "系统通知地址", Code = client.NotificationUrl, Define = EnumDictDefine.Customer }
|
||||
};
|
||||
Database.InsertBatch(items);
|
||||
Database.CompleteTransaction();
|
||||
db.InsertBatch(items);
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (DbException)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -466,12 +472,13 @@ class DictService : IDict
|
|||
public bool DeleteClient(string appId)
|
||||
{
|
||||
bool ret;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete Dicts where Category=@0 and Name=@1 and Define=@2", "应用首页", appId, EnumDictDefine.System);
|
||||
Database.Execute("delete Dicts where Category=@0 and Code=@1 and Define=@2", "应用程序", appId, EnumDictDefine.System);
|
||||
Database.Execute("delete Dicts where Category=@Category and Name in (@Names)", new
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete Dicts where Category=@0 and Name=@1 and Define=@2", "应用首页", appId, EnumDictDefine.System);
|
||||
db.Execute("delete Dicts where Category=@0 and Code=@1 and Define=@2", "应用程序", appId, EnumDictDefine.System);
|
||||
db.Execute("delete Dicts where Category=@Category and Name in (@Names)", new
|
||||
{
|
||||
Category = appId,
|
||||
Names = new List<string>
|
||||
|
@ -485,12 +492,12 @@ class DictService : IDict
|
|||
"系统通知地址"
|
||||
}
|
||||
});
|
||||
Database.CompleteTransaction();
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
@ -10,15 +10,16 @@ namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
|||
|
||||
class ExceptionService : IException
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
public ExceptionService(IDatabase db) => Database = db;
|
||||
public ExceptionService(IDBManager db) => DBManager = db;
|
||||
|
||||
public bool Log(Error exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
Database.Insert(exception);
|
||||
using var db = DBManager.Create();
|
||||
db.Insert(exception);
|
||||
}
|
||||
catch { }
|
||||
return true;
|
||||
|
@ -59,7 +60,8 @@ class ExceptionService : IException
|
|||
sql.OrderBy("Logtime desc", "ErrorPage", "UserId");
|
||||
}
|
||||
|
||||
var data = Database.Page<Error>(pageIndex, pageItems, sql);
|
||||
using var db = DBManager.Create();
|
||||
var data = db.Page<Error>(pageIndex, pageItems, sql);
|
||||
return (data.Items, Convert.ToInt32(data.TotalItems));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,26 +17,34 @@ class GroupService : IGroup
|
|||
|
||||
private const string GroupServiceGetGroupsByRoleIdCacheKey = "GroupService-GetGroupsByRoleId";
|
||||
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public GroupService(IDatabase db) => Database = db;
|
||||
public GroupService(IDBManager db) => DBManager = db;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<Group> GetAll() => CacheManager.GetOrAdd(GroupServiceGetAllCacheKey, entry => Database.Fetch<Group>());
|
||||
public List<Group> GetAll() => CacheManager.GetOrAdd(GroupServiceGetAllCacheKey, entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<Group>();
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetGroupsByUserId(string? userId) => CacheManager.GetOrAdd($"{GroupServiceGetGroupsByUserIdCacheKey}-{userId}", entry => Database.Fetch<string>("select GroupID from UserGroup where UserID = @0", userId));
|
||||
public List<string> GetGroupsByUserId(string? userId) => CacheManager.GetOrAdd($"{GroupServiceGetGroupsByUserIdCacheKey}-{userId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select GroupID from UserGroup where UserID = @0", userId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -47,17 +55,18 @@ class GroupService : IGroup
|
|||
public bool SaveGroupsByUserId(string? userId, IEnumerable<string> groupIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from UserGroup where UserID = @0", userId);
|
||||
Database.InsertBatch("UserGroup", groupIds.Select(g => new { GroupID = g, UserID = userId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from UserGroup where UserID = @0", userId);
|
||||
db.InsertBatch("UserGroup", groupIds.Select(g => new { GroupID = g, UserID = userId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -72,7 +81,11 @@ class GroupService : IGroup
|
|||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetGroupsByRoleId(string? roleId) => CacheManager.GetOrAdd($"{GroupServiceGetGroupsByRoleIdCacheKey}-{roleId}", entry => Database.Fetch<string>("select GroupID from RoleGroup where RoleID = @0", roleId));
|
||||
public List<string> GetGroupsByRoleId(string? roleId) => CacheManager.GetOrAdd($"{GroupServiceGetGroupsByRoleIdCacheKey}-{roleId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select GroupID from RoleGroup where RoleID = @0", roleId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -83,17 +96,18 @@ class GroupService : IGroup
|
|||
public bool SaveGroupsByRoleId(string? roleId, IEnumerable<string> groupIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from RoleGroup where RoleID = @0", roleId);
|
||||
Database.InsertBatch("RoleGroup", groupIds.Select(g => new { GroupID = g, RoleID = roleId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from RoleGroup where RoleID = @0", roleId);
|
||||
db.InsertBatch("RoleGroup", groupIds.Select(g => new { GroupID = g, RoleID = roleId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IDBManager
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDatabase Create(string? connectionName = "ba", bool keepAlive = false);
|
||||
}
|
|
@ -4,15 +4,14 @@
|
|||
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
||||
|
||||
class LoginService : ILogin
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
public LoginService(IDatabase database) => Database = database;
|
||||
public LoginService(IDBManager database) => DBManager = database;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -38,7 +37,8 @@ class LoginService : ILogin
|
|||
UserAgent = userAgent,
|
||||
Result = result ? "登录成功" : "登录失败"
|
||||
};
|
||||
Database.Insert(loginUser);
|
||||
using var db = DBManager.Create();
|
||||
db.Insert(loginUser);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,16 @@ class NavigationService : INavigation
|
|||
|
||||
private const string NavigationServiceGetMenusByRoleIdCacheKey = "NavigationService-GetMenusByRoleId";
|
||||
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public NavigationService(IDatabase db) => Database = db;
|
||||
public NavigationService(IDBManager db)
|
||||
{
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定用户名可访问的所有菜单集合
|
||||
|
@ -33,9 +36,10 @@ class NavigationService : INavigation
|
|||
/// <returns>未层次化的菜单集合</returns>
|
||||
public List<Navigation> GetAllMenus(string userName) => CacheManager.GetOrAdd($"{NavigationServiceGetAllCacheKey}-{userName}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
// 缓存所有菜单数据移除 SQL 语句降低复杂度
|
||||
var order = Database.Provider.EscapeSqlIdentifier("Order");
|
||||
return Database.Fetch<Models.Navigation>($"select n.ID, n.ParentId, n.Name, n.{order}, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application from Navigations n inner join (select nr.NavigationID from Users u inner join UserRole ur on ur.UserID = u.ID inner join NavigationRole nr on nr.RoleID = ur.RoleID where u.UserName = @UserName union select nr.NavigationID from Users u inner join UserGroup ug on u.ID = ug.UserID inner join RoleGroup rg on rg.GroupID = ug.GroupID inner join NavigationRole nr on nr.RoleID = rg.RoleID where u.UserName = @UserName union select n.ID from Navigations n where EXISTS (select UserName from Users u inner join UserRole ur on u.ID = ur.UserID inner join Roles r on ur.RoleID = r.ID where u.UserName = @UserName and r.RoleName = @RoleName)) nav on n.ID = nav.NavigationID ORDER BY n.Application, n.{order}", new { UserName = userName, RoleName = "Administrators" });
|
||||
var order = db.Provider.EscapeSqlIdentifier("Order");
|
||||
return db.Fetch<Models.Navigation>($"select n.ID, n.ParentId, n.Name, n.{order}, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application from Navigations n inner join (select nr.NavigationID from Users u inner join UserRole ur on ur.UserID = u.ID inner join NavigationRole nr on nr.RoleID = ur.RoleID where u.UserName = @UserName union select nr.NavigationID from Users u inner join UserGroup ug on u.ID = ug.UserID inner join RoleGroup rg on rg.GroupID = ug.GroupID inner join NavigationRole nr on nr.RoleID = rg.RoleID where u.UserName = @UserName union select n.ID from Navigations n where EXISTS (select UserName from Users u inner join UserRole ur on u.ID = ur.UserID inner join Roles r on ur.RoleID = r.ID where u.UserName = @UserName and r.RoleName = @RoleName)) nav on n.ID = nav.NavigationID ORDER BY n.Application, n.{order}", new { UserName = userName, RoleName = "Administrators" });
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
|
@ -43,7 +47,11 @@ class NavigationService : INavigation
|
|||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetMenusByRoleId(string? roleId) => CacheManager.GetOrAdd($"{NavigationServiceGetMenusByRoleIdCacheKey}-{roleId}", entry => Database.Fetch<string>("select NavigationID from NavigationRole where RoleID = @0", roleId));
|
||||
public List<string> GetMenusByRoleId(string? roleId) => CacheManager.GetOrAdd($"{NavigationServiceGetMenusByRoleIdCacheKey}-{roleId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select NavigationID from NavigationRole where RoleID = @0", roleId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -54,17 +62,18 @@ class NavigationService : INavigation
|
|||
public bool SaveMenusByRoleId(string? roleId, List<string> menuIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from NavigationRole where RoleID = @0", roleId);
|
||||
Database.InsertBatch("NavigationRole", menuIds.Select(g => new { NavigationID = g, RoleID = roleId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from NavigationRole where RoleID = @0", roleId);
|
||||
db.InsertBatch("NavigationRole", menuIds.Select(g => new { NavigationID = g, RoleID = roleId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
|
|
@ -19,25 +19,44 @@ class RoleService : IRole
|
|||
|
||||
private const string RoleServiceGetRolesByMenuIdCacheKey = "RoleService-GetRolesByMenusId";
|
||||
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public RoleService(IDatabase db) => Database = db;
|
||||
public RoleService(IDBManager db)
|
||||
{
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<Role> GetAll() => CacheManager.GetOrAdd(RoleServiceGetAllCacheKey, entry => CacheManager.GetOrAdd(RoleServiceGetAllCacheKey, entry => Database.Fetch<Role>()));
|
||||
public List<Role> GetAll() => CacheManager.GetOrAdd(RoleServiceGetAllCacheKey, entry => CacheManager.GetOrAdd(RoleServiceGetAllCacheKey, entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<Role>();
|
||||
}));
|
||||
|
||||
public List<string> GetRolesByGroupId(string? groupId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByGroupIdCacheKey}-{groupId}", entry => Database.Fetch<string>("select RoleID from RoleGroup where GroupID = @0", groupId));
|
||||
public List<string> GetRolesByGroupId(string? groupId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByGroupIdCacheKey}-{groupId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select RoleID from RoleGroup where GroupID = @0", groupId);
|
||||
});
|
||||
|
||||
public List<string> GetRolesByUserId(string? userId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByUserIdCacheKey}-{userId}", entry => Database.Fetch<string>("select RoleID from UserRole where UserID = @0", userId));
|
||||
public List<string> GetRolesByUserId(string? userId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByUserIdCacheKey}-{userId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select RoleID from UserRole where UserID = @0", userId);
|
||||
});
|
||||
|
||||
public List<string> GetRolesByMenuId(string? menuId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByMenuIdCacheKey}-{menuId}", entry => Database.Fetch<string>("select RoleID from NavigationRole where NavigationID = @0", menuId));
|
||||
public List<string> GetRolesByMenuId(string? menuId) => CacheManager.GetOrAdd($"{RoleServiceGetRolesByMenuIdCacheKey}-{menuId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select RoleID from NavigationRole where NavigationID = @0", menuId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -48,17 +67,18 @@ class RoleService : IRole
|
|||
public bool SaveRolesByGroupId(string? groupId, IEnumerable<string> roleIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from RoleGroup where GroupID = @0", groupId);
|
||||
Database.InsertBatch("RoleGroup", roleIds.Select(g => new { RoleID = g, GroupID = groupId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from RoleGroup where GroupID = @0", groupId);
|
||||
db.InsertBatch("RoleGroup", roleIds.Select(g => new { RoleID = g, GroupID = groupId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -77,17 +97,18 @@ class RoleService : IRole
|
|||
public bool SaveRolesByUserId(string? userId, IEnumerable<string> roleIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from UserRole where UserID = @0", userId);
|
||||
Database.InsertBatch("UserRole", roleIds.Select(g => new { RoleID = g, UserID = userId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from UserRole where UserID = @0", userId);
|
||||
db.InsertBatch("UserRole", roleIds.Select(g => new { RoleID = g, UserID = userId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -100,17 +121,18 @@ class RoleService : IRole
|
|||
public bool SaveRolesByMenuId(string? menuId, IEnumerable<string> roleIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from NavigationRole where NavigationID = @0", menuId);
|
||||
Database.InsertBatch("NavigationRole", roleIds.Select(g => new { RoleID = g, NavigationID = menuId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from NavigationRole where NavigationID = @0", menuId);
|
||||
db.InsertBatch("NavigationRole", roleIds.Select(g => new { RoleID = g, NavigationID = menuId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
|
|
@ -10,13 +10,12 @@ namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
|||
|
||||
class TraceService : ITrace
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public TraceService(IDatabase db) => Database = db;
|
||||
public TraceService(IDBManager db)
|
||||
{
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -24,7 +23,8 @@ class TraceService : ITrace
|
|||
/// <param name="trace"></param>
|
||||
public void Log(Trace trace)
|
||||
{
|
||||
Database.Insert(trace);
|
||||
using var db = DBManager.Create();
|
||||
db.Insert(trace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -39,7 +39,6 @@ class TraceService : ITrace
|
|||
public (IEnumerable<Trace> Items, int ItemsCount) GetAll(string? searchText, TraceFilter filter, int pageIndex, int pageItems, List<string> sortList)
|
||||
{
|
||||
var sql = new Sql();
|
||||
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
sql.Where("UserName Like @0 or Ip Like @0 or RequestUrl Like @0", $"%{searchText}%");
|
||||
|
@ -71,7 +70,8 @@ class TraceService : ITrace
|
|||
sql.OrderBy("Logtime desc");
|
||||
}
|
||||
|
||||
var data = Database.Page<Trace>(pageIndex, pageItems, sql);
|
||||
using var db = DBManager.Create();
|
||||
var data = db.Page<Trace>(pageIndex, pageItems, sql);
|
||||
return (data.Items, Convert.ToInt32(data.TotalItems));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,19 +12,22 @@ namespace BootstrapAdmin.DataAccess.PetaPoco.Services;
|
|||
|
||||
class UserService : IUser
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public UserService(IDatabase db) => Database = db;
|
||||
public UserService(IDBManager db)
|
||||
{
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<User> GetAll() => Database.Fetch<User>();
|
||||
public List<User> GetAll()
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<User>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -35,7 +38,8 @@ class UserService : IUser
|
|||
/// <exception cref="NotImplementedException"></exception>
|
||||
public bool Authenticate(string userName, string password)
|
||||
{
|
||||
var user = Database.SingleOrDefault<User>("select DisplayName, Password, PassSalt from Users where ApprovedTime is not null and UserName = @0", userName);
|
||||
using var db = DBManager.Create();
|
||||
var user = db.SingleOrDefault<User>("select DisplayName, Password, PassSalt from Users where ApprovedTime is not null and UserName = @0", userName);
|
||||
|
||||
var isAuth = false;
|
||||
if (user != null && !string.IsNullOrEmpty(user.PassSalt))
|
||||
|
@ -47,11 +51,19 @@ class UserService : IUser
|
|||
|
||||
private const string UserServiceGetUserByUserNameCacheKey = "UserService-GetUserByUserName";
|
||||
|
||||
public User? GetUserByUserName(string? userName) => CacheManager.GetOrAdd($"{UserServiceGetUserByUserNameCacheKey}-{userName}", entry => string.IsNullOrEmpty(userName) ? null : Database.FirstOrDefault<User>("Where UserName = @0", userName));
|
||||
public User? GetUserByUserName(string? userName) => CacheManager.GetOrAdd($"{UserServiceGetUserByUserNameCacheKey}-{userName}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return string.IsNullOrEmpty(userName) ? null : db.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
});
|
||||
|
||||
private const string UserServiceGetAppsByUserNameCacheKey = "UserService-GetAppsByUserName";
|
||||
|
||||
public List<string> GetApps(string userName) => CacheManager.GetOrAdd($"{UserServiceGetAppsByUserNameCacheKey}-{userName}", entry => Database.Fetch<string>($"select d.Code from Dicts d inner join RoleApp ra on d.Code = ra.AppId inner join (select r.Id from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 union select r.Id from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0) r on ra.RoleId = r.ID union select Code from Dicts where Category = @1 and exists(select r.ID from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 and r.RoleName = @2 union select r.ID from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0 and r.RoleName = @2)", userName, "应用程序", "Administrators"));
|
||||
public List<string> GetApps(string userName) => CacheManager.GetOrAdd($"{UserServiceGetAppsByUserNameCacheKey}-{userName}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>($"select d.Code from Dicts d inner join RoleApp ra on d.Code = ra.AppId inner join (select r.Id from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 union select r.Id from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0) r on ra.RoleId = r.ID union select Code from Dicts where Category = @1 and exists(select r.ID from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 and r.RoleName = @2 union select r.ID from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0 and r.RoleName = @2)", userName, "应用程序", "Administrators");
|
||||
});
|
||||
|
||||
private const string UserServiceGetAppIdByUserNameCacheKey = "UserService-GetAppIdByUserName";
|
||||
|
||||
|
@ -60,7 +72,11 @@ class UserService : IUser
|
|||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public string? GetAppIdByUserName(string userName) => CacheManager.GetOrAdd($"{UserServiceGetAppIdByUserNameCacheKey}-{userName}", entry => Database.FirstOrDefault<User>("Where UserName = @0", userName)?.App);
|
||||
public string? GetAppIdByUserName(string userName) => CacheManager.GetOrAdd($"{UserServiceGetAppIdByUserNameCacheKey}-{userName}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.FirstOrDefault<User>("Where UserName = @0", userName)?.App;
|
||||
});
|
||||
|
||||
private const string UserServiceGetRolesByUserNameCacheKey = "UserService-GetRolesByUserName";
|
||||
|
||||
|
@ -70,7 +86,11 @@ class UserService : IUser
|
|||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public List<string> GetRoles(string userName) => CacheManager.GetOrAdd($"{UserServiceGetRolesByUserNameCacheKey}-{userName}", entry => Database.Fetch<string>($"select r.RoleName from Roles r inner join UserRole ur on r.ID=ur.RoleID inner join Users u on ur.UserID = u.ID and u.UserName = @0 union select r.RoleName from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID and u.UserName = @0", userName));
|
||||
public List<string> GetRoles(string userName) => CacheManager.GetOrAdd($"{UserServiceGetRolesByUserNameCacheKey}-{userName}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>($"select r.RoleName from Roles r inner join UserRole ur on r.ID=ur.RoleID inner join Users u on ur.UserID = u.ID and u.UserName = @0 union select r.RoleName from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID and u.UserName = @0", userName);
|
||||
});
|
||||
|
||||
private const string UserServiceGetUsersByGroupIdCacheKey = "UserService-GetUsersByGroupId";
|
||||
|
||||
|
@ -78,7 +98,11 @@ class UserService : IUser
|
|||
///
|
||||
/// </summary>
|
||||
/// <param name="groupId"></param>
|
||||
public List<string> GetUsersByGroupId(string? groupId) => CacheManager.GetOrAdd($"{UserServiceGetUsersByGroupIdCacheKey}-{groupId}", entry => Database.Fetch<string>("select UserID from UserGroup where GroupID = @0", groupId));
|
||||
public List<string> GetUsersByGroupId(string? groupId) => CacheManager.GetOrAdd($"{UserServiceGetUsersByGroupIdCacheKey}-{groupId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select UserID from UserGroup where GroupID = @0", groupId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -90,17 +114,18 @@ class UserService : IUser
|
|||
public bool SaveUsersByGroupId(string? id, IEnumerable<string> userIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from UserGroup where GroupId = @0", id);
|
||||
Database.InsertBatch("UserGroup", userIds.Select(g => new { UserID = g, GroupID = id }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from UserGroup where GroupId = @0", id);
|
||||
db.InsertBatch("UserGroup", userIds.Select(g => new { UserID = g, GroupID = id }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -117,7 +142,11 @@ class UserService : IUser
|
|||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetUsersByRoleId(string? roleId) => CacheManager.GetOrAdd($"{UserServiceGetUsersByRoleIdCacheKey}-{roleId}", entry => Database.Fetch<string>("select UserID from UserRole where RoleID = @0", roleId));
|
||||
public List<string> GetUsersByRoleId(string? roleId) => CacheManager.GetOrAdd($"{UserServiceGetUsersByRoleIdCacheKey}-{roleId}", entry =>
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>("select UserID from UserRole where RoleID = @0", roleId);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -128,17 +157,18 @@ class UserService : IUser
|
|||
public bool SaveUsersByRoleId(string? roleId, IEnumerable<string> userIds)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from UserRole where RoleID = @0", roleId);
|
||||
Database.InsertBatch("UserRole", userIds.Select(g => new { UserID = g, RoleID = roleId }));
|
||||
Database.CompleteTransaction();
|
||||
db.BeginTransaction();
|
||||
db.Execute("delete from UserRole where RoleID = @0", roleId);
|
||||
db.InsertBatch("UserRole", userIds.Select(g => new { UserID = g, RoleID = roleId }));
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -157,12 +187,13 @@ class UserService : IUser
|
|||
public bool ChangePassword(string userName, string password, string newPassword)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
if (Authenticate(userName, password))
|
||||
{
|
||||
var passSalt = LgbCryptography.GenerateSalt();
|
||||
password = LgbCryptography.ComputeHash(newPassword, passSalt);
|
||||
string sql = "set Password = @0, PassSalt = @1 where UserName = @2";
|
||||
ret = Database.Update<User>(sql, password, passSalt, userName) == 1;
|
||||
ret = db.Update<User>(sql, password, passSalt, userName) == 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -172,7 +203,8 @@ class UserService : IUser
|
|||
/// </summary>
|
||||
public bool SaveDisplayName(string userName, string displayName)
|
||||
{
|
||||
var ret = Database.Update<User>("set DisplayName = @1 where UserName = @0", userName, displayName) == 1;
|
||||
using var db = DBManager.Create();
|
||||
var ret = db.Update<User>("set DisplayName = @1 where UserName = @0", userName, displayName) == 1;
|
||||
if (ret)
|
||||
{
|
||||
CacheManager.Clear();
|
||||
|
@ -185,7 +217,8 @@ class UserService : IUser
|
|||
/// </summary>
|
||||
public bool SaveTheme(string userName, string theme)
|
||||
{
|
||||
var ret = Database.Update<User>("set Css = @1 where UserName = @0", userName, theme) == 1;
|
||||
using var db = DBManager.Create();
|
||||
var ret = db.Update<User>("set Css = @1 where UserName = @0", userName, theme) == 1;
|
||||
if (ret)
|
||||
{
|
||||
CacheManager.Clear();
|
||||
|
@ -198,7 +231,8 @@ class UserService : IUser
|
|||
/// </summary>
|
||||
public bool SaveLogo(string userName, string? logo)
|
||||
{
|
||||
var ret = Database.Update<User>("set Icon = @1 where UserName = @0", userName, logo) == 1;
|
||||
using var db = DBManager.Create();
|
||||
var ret = db.Update<User>("set Icon = @1 where UserName = @0", userName, logo) == 1;
|
||||
if (ret)
|
||||
{
|
||||
CacheManager.Clear();
|
||||
|
@ -217,14 +251,15 @@ class UserService : IUser
|
|||
public bool TryCreateUserByPhone(string phone, string code, string appId, ICollection<string> roles)
|
||||
{
|
||||
var ret = false;
|
||||
using var db = DBManager.Create();
|
||||
try
|
||||
{
|
||||
var salt = LgbCryptography.GenerateSalt();
|
||||
var pwd = LgbCryptography.ComputeHash(code, salt);
|
||||
var user = Database.FirstOrDefault<User>("Where UserName = @0", phone);
|
||||
var user = db.FirstOrDefault<User>("Where UserName = @0", phone);
|
||||
if (user == null)
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
db.BeginTransaction();
|
||||
// 插入用户
|
||||
user = new User()
|
||||
{
|
||||
|
@ -238,23 +273,23 @@ class UserService : IUser
|
|||
Password = LgbCryptography.ComputeHash(code, salt),
|
||||
App = appId
|
||||
};
|
||||
Database.Save(user);
|
||||
db.Save(user);
|
||||
// Authorization
|
||||
var roleIds = Database.Fetch<string>("select ID from Roles where RoleName in (@roles)", new { roles });
|
||||
Database.InsertBatch("UserRole", roleIds.Select(g => new { RoleID = g, UserID = user.Id }));
|
||||
Database.CompleteTransaction();
|
||||
var roleIds = db.Fetch<string>("select ID from Roles where RoleName in (@roles)", new { roles });
|
||||
db.InsertBatch("UserRole", roleIds.Select(g => new { RoleID = g, UserID = user.Id }));
|
||||
db.CompleteTransaction();
|
||||
}
|
||||
else
|
||||
{
|
||||
user.PassSalt = salt;
|
||||
user.Password = pwd;
|
||||
Database.Update(user);
|
||||
db.Update(user);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -268,14 +303,15 @@ class UserService : IUser
|
|||
{
|
||||
var salt = LgbCryptography.GenerateSalt();
|
||||
var pwd = LgbCryptography.ComputeHash(password, salt);
|
||||
var user = Database.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
using var db = DBManager.Create();
|
||||
var user = db.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
bool ret;
|
||||
if (user == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 开始事务
|
||||
Database.BeginTransaction();
|
||||
db.BeginTransaction();
|
||||
user = new User()
|
||||
{
|
||||
ApprovedBy = "System",
|
||||
|
@ -287,16 +323,16 @@ class UserService : IUser
|
|||
PassSalt = salt,
|
||||
Password = pwd
|
||||
};
|
||||
Database.Save(user);
|
||||
db.Save(user);
|
||||
// 授权 Default 角色
|
||||
Database.Execute("insert into UserRole (UserID, RoleID) select ID, (select ID from Roles where RoleName = 'Default') RoleId from Users where UserName = @0", userName);
|
||||
db.Execute("insert into UserRole (UserID, RoleID) select ID, (select ID from Roles where RoleName = 'Default') RoleId from Users where UserName = @0", userName);
|
||||
// 结束事务
|
||||
Database.CompleteTransaction();
|
||||
db.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
db.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -305,7 +341,7 @@ class UserService : IUser
|
|||
user.DisplayName = displayName;
|
||||
user.PassSalt = salt;
|
||||
user.Password = pwd;
|
||||
Database.Update(user);
|
||||
db.Update(user);
|
||||
ret = true;
|
||||
}
|
||||
if (ret)
|
||||
|
@ -317,7 +353,8 @@ class UserService : IUser
|
|||
|
||||
public bool SaveApp(string userName, string app)
|
||||
{
|
||||
var ret = Database.Update<User>("Set App = @1 Where UserName = @0", userName, app) == 1;
|
||||
using var db = DBManager.Create();
|
||||
var ret = db.Update<User>("Set App = @1 Where UserName = @0", userName, app) == 1;
|
||||
if (ret)
|
||||
{
|
||||
CacheManager.Clear();
|
||||
|
|
Binary file not shown.
|
@ -1,35 +1,39 @@
|
|||
<form method="post" class="form-signin" action="@PostUrl" @ref="LoginForm">
|
||||
<h2 class="form-signin-heading">@Title</h2>
|
||||
<div class="@ClassString">
|
||||
@if (AllowMobile)
|
||||
{
|
||||
<div class="login-sms">
|
||||
<SMSLogin />
|
||||
<div class="wrap white">
|
||||
<div class="container">
|
||||
<form method="post" class="form-signin" action="@PostUrl" @ref="LoginForm">
|
||||
<h2 class="form-signin-heading">@Title</h2>
|
||||
<div class="@ClassString">
|
||||
@if (AllowMobile)
|
||||
{
|
||||
<div class="login-sms">
|
||||
<SMSLogin />
|
||||
</div>
|
||||
}
|
||||
<div class="login-up">
|
||||
<UserLogin />
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-3">
|
||||
<Checkbox @bind-Value="RememberPassword" Color="Color.Primary" ShowAfterLabel="true" DisplayText="记住密码自动登录" OnValueChanged="OnRememberPassword" />
|
||||
<Block Condition="AllowMobile">
|
||||
<SwitchButton @bind-ToggleState="UseMobileLogin" OnClick="OnClickSwitchButton" OffText="短信验证登录" OnText="用户密码登录" />
|
||||
</Block>
|
||||
</div>
|
||||
<button class="btn-login btn-lg btn-block mt-3" data-bs-toggle="tooltip" title="不填写密码默认使用 Gitee 认证">登 录</button>
|
||||
<div class="d-flex justify-content-between mt-3">
|
||||
<LinkButton Text="申请账号" OnClick="OnSignUp" />
|
||||
<LinkButton Text="忘记密码" OnClick="OnForgotPassword" />
|
||||
</div>
|
||||
<Block Condition="AllowOAuth">
|
||||
<Divider Text="其他方式登录" />
|
||||
<div class="login-list">
|
||||
<LinkButton Url="Account/Gitee" Title="使用 Gitee 帐号登录" ImageUrl="images/gitee.svg" />
|
||||
<LinkButton Url="Account/Gitee" Title="使用 GitHub 帐号登录" ImageUrl="images/git.svg" />
|
||||
<LinkButton Url="#" Title="微信-暂未实现" ImageUrl="images/weixin-2.svg" />
|
||||
<LinkButton Url="Account/Tencent" Title="使用 QQ 账号登录" ImageUrl="images/qq.svg" />
|
||||
<LinkButton Url="Account/Alipay" Title="使用支付宝账号登录" ImageUrl="images/zhifubao.svg" />
|
||||
</div>
|
||||
</Block>
|
||||
</div>
|
||||
}
|
||||
<div class="login-up">
|
||||
<UserLogin />
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-3">
|
||||
<Checkbox @bind-Value="RememberPassword" Color="Color.Primary" ShowAfterLabel="true" DisplayText="记住密码自动登录" OnValueChanged="OnRememberPassword" />
|
||||
<Block Condition="AllowMobile">
|
||||
<SwitchButton @bind-ToggleState="UseMobileLogin" OnClick="OnClickSwitchButton" OffText="短信验证登录" OnText="用户密码登录" />
|
||||
</Block>
|
||||
</div>
|
||||
<button class="btn-login btn-lg btn-block mt-3" data-bs-toggle="tooltip" title="不填写密码默认使用 Gitee 认证">登 录</button>
|
||||
<div class="d-flex justify-content-between mt-3">
|
||||
<LinkButton Text="申请账号" OnClick="OnSignUp" />
|
||||
<LinkButton Text="忘记密码" OnClick="OnForgotPassword" />
|
||||
</div>
|
||||
<Block Condition="AllowOAuth">
|
||||
<Divider Text="其他方式登录" />
|
||||
<div class="login-list">
|
||||
<LinkButton Url="Account/Gitee" Title="使用 Gitee 帐号登录" ImageUrl="images/gitee.svg" />
|
||||
<LinkButton Url="Account/Gitee" Title="使用 GitHub 帐号登录" ImageUrl="images/git.svg" />
|
||||
<LinkButton Url="#" Title="微信-暂未实现" ImageUrl="images/weixin-2.svg" />
|
||||
<LinkButton Url="Account/Tencent" Title="使用 QQ 账号登录" ImageUrl="images/qq.svg" />
|
||||
<LinkButton Url="Account/Alipay" Title="使用支付宝账号登录" ImageUrl="images/zhifubao.svg" />
|
||||
</div>
|
||||
</Block>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Utils;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components;
|
||||
|
@ -12,19 +13,40 @@ namespace BootstrapAdmin.Web.Components;
|
|||
/// </summary>
|
||||
public partial class AdminLogin : IDisposable
|
||||
{
|
||||
private string? Title { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string? Title { get; set; }
|
||||
|
||||
private bool AllowMobile { get; set; } = true;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected bool AllowMobile { get; set; } = true;
|
||||
|
||||
private bool UseMobileLogin { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected bool UseMobileLogin { get; set; }
|
||||
|
||||
private bool AllowOAuth { get; set; } = true;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected bool AllowOAuth { get; set; } = true;
|
||||
|
||||
private bool RememberPassword { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected bool RememberPassword { get; set; }
|
||||
|
||||
private ElementReference LoginForm { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected ElementReference LoginForm { get; set; }
|
||||
|
||||
private string? PostUrl { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string? PostUrl { get; set; }
|
||||
|
||||
private JSInterop<AdminLogin>? Interop { get; set; }
|
||||
|
||||
|
@ -40,13 +62,19 @@ public partial class AdminLogin : IDisposable
|
|||
[Parameter]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictsService { get; set; }
|
||||
protected IDict? DictsService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ILogin? LoginService { get; set; }
|
||||
protected ILogin? LoginService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
|
@ -57,7 +85,7 @@ public partial class AdminLogin : IDisposable
|
|||
/// </summary>
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private WebClientService? WebClientService { get; set; }
|
||||
protected WebClientService? WebClientService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -66,7 +94,10 @@ public partial class AdminLogin : IDisposable
|
|||
[NotNull]
|
||||
private IIPLocatorProvider? IPLocatorProvider { get; set; }
|
||||
|
||||
private string? ClassString => CssBuilder.Default("login-wrap")
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected string? ClassString => CssBuilder.Default("login-wrap")
|
||||
.AddClass("is-mobile", UseMobileLogin)
|
||||
.Build();
|
||||
|
||||
|
@ -78,17 +109,20 @@ public partial class AdminLogin : IDisposable
|
|||
base.OnInitialized();
|
||||
|
||||
Title = DictsService.GetWebTitle();
|
||||
PostUrl = QueryHelper.AddQueryString("/Account/Login", new Dictionary<string, string?>
|
||||
PostUrl = QueryHelper.AddQueryString("Account/Login", new Dictionary<string, string?>
|
||||
{
|
||||
["ReturnUrl"] = ReturnUrl,
|
||||
["AppId"] = AppId
|
||||
});
|
||||
}
|
||||
|
||||
void OnClickSwitchButton()
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected void OnClickSwitchButton()
|
||||
{
|
||||
var rem = RememberPassword ? "true" : "false";
|
||||
PostUrl = QueryHelper.AddQueryString(UseMobileLogin ? "/Account/Mobile" : "/Account/Login", new Dictionary<string, string?>()
|
||||
PostUrl = QueryHelper.AddQueryString(UseMobileLogin ? "Account/Mobile" : "Account/Login", new Dictionary<string, string?>()
|
||||
{
|
||||
[nameof(ReturnUrl)] = ReturnUrl,
|
||||
["AppId"] = AppId,
|
||||
|
@ -113,18 +147,29 @@ public partial class AdminLogin : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
Task OnRememberPassword(bool remember)
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="remember"></param>
|
||||
/// <returns></returns>
|
||||
protected Task OnRememberPassword(bool remember)
|
||||
{
|
||||
OnClickSwitchButton();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
void OnSignUp()
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected void OnSignUp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnForgotPassword()
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected void OnForgotPassword()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,29 @@
|
|||
.form-signin-heading {
|
||||
.wrap {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.wrap {
|
||||
background-color: #5bc0de;
|
||||
background: url('../images/bg2.jpg') fixed no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: url('../images/bg3.png') no-repeat;
|
||||
background-size: contain;
|
||||
width: 704px;
|
||||
height: 404px;
|
||||
margin: 0 auto;
|
||||
margin-top: calc(100vh / 2 - 190px);
|
||||
}
|
||||
}
|
||||
|
||||
.form-signin-heading {
|
||||
margin: 0;
|
||||
padding: 20px 15px;
|
||||
text-align: center;
|
||||
|
@ -123,3 +148,17 @@
|
|||
color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.gitee.wrap {
|
||||
background-color: #f1f2f7;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.gitee .container {
|
||||
width: 704px;
|
||||
height: 404px;
|
||||
margin: 0 auto;
|
||||
margin-top: calc(100vh / 2 - 190px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<div class="login-footer">
|
||||
<ul class="login-footer-body">
|
||||
<li><a href="https://www.gitee.com/LongbowEnterprise" target="_blank"><i class="fa fa-copyright"></i> Bootstrap Admin</a></li>
|
||||
<li><a href="https://www.gitee.com/LongbowEnterprise/BootstrapAdmin/wikis" target="_blank">帮助文档</a></li>
|
||||
<li><a href="Account/Login?View=Login">系统默认</a></li>
|
||||
<li><a href="Account/Login?View=Login-Gitee">高仿码云</a></li>
|
||||
<li><a href="Account/Login?View=Login-Blue">蓝色简约</a></li>
|
||||
<li><a href="Account/Login?View=Login-Tec">科技动感</a></li>
|
||||
<li><a href="Account/Login?View=Login-LTE">Admin-LTE</a></li>
|
||||
</ul>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
.login-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.login-footer-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.white + .login-footer li a {
|
||||
color: #fff;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
@inherits AdminLogin
|
||||
|
||||
<div class="wrap">
|
||||
<div class="container">
|
||||
<section class="login-sidebox">
|
||||
<div class="login-sidebox-content">
|
||||
<div class="login-sidebox-header">
|
||||
<div class="login-sidebox-logo">
|
||||
<img alt="logo" src="../favicon.png"><span>Bootstrap Admin</span>
|
||||
</div>
|
||||
<h2 class="login-sidebox-subtitle">
|
||||
通用后台权限管理系统
|
||||
</h2>
|
||||
</div>
|
||||
<div class="login-sidebox-body">
|
||||
<p>
|
||||
基于 RBAC 的 NetCore 后台管理框架,权限管理,前后台分离,支持多站点单点登录,兼容所有主流浏览器,内置微信、支付宝、QQ等多种登录方式,内置多种样式,可切换至 Blazor 多 Tabs 模式,权限控制细化到网页内任意元素(按钮、表格、文本框等等)
|
||||
</p>
|
||||
</div>
|
||||
<div class="login-sidebox-footer">
|
||||
<div>开源文档:<a href="https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis">码云托管平台 - Wiki</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="login-form">
|
||||
<div class="login-form-header">
|
||||
<h2>登录</h2>
|
||||
<span class="flex-self-end">
|
||||
没有帐号?
|
||||
<LinkButton Text="申请账号" OnClick="OnSignUp" />
|
||||
</span>
|
||||
</div>
|
||||
<form method="post" class="form-signin" action="@PostUrl" @ref="LoginForm">
|
||||
<div class="@ClassString">
|
||||
@if (AllowMobile)
|
||||
{
|
||||
<div class="login-sms">
|
||||
<SMSLogin />
|
||||
</div>
|
||||
}
|
||||
<div class="login-up">
|
||||
<UserLogin />
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<Checkbox @bind-Value="RememberPassword" Color="Color.Primary" ShowAfterLabel="true" DisplayText="记住密码自动登录" OnValueChanged="OnRememberPassword" />
|
||||
<Block Condition="AllowMobile">
|
||||
<SwitchButton @bind-ToggleState="UseMobileLogin" OnClick="OnClickSwitchButton" OffText="短信验证登录" OnText="用户密码登录" />
|
||||
</Block>
|
||||
</div>
|
||||
<button class="btn-login btn-lg btn-block mt-4" data-bs-toggle="tooltip" title="不填写密码默认使用 Gitee 认证">登 录</button>
|
||||
<div class="d-flex justify-content-center mt-3 mb-4">
|
||||
<LinkButton Text="已有账号,忘记密码?" OnClick="OnForgotPassword" />
|
||||
</div>
|
||||
<Block Condition="AllowOAuth">
|
||||
<Divider Text="其他方式登录" />
|
||||
<div class="login-list">
|
||||
<LinkButton Url="Account/Gitee" Title="使用 Gitee 帐号登录" ImageUrl="images/gitee.svg" />
|
||||
<LinkButton Url="Account/Gitee" Title="使用 GitHub 帐号登录" ImageUrl="images/git.svg" />
|
||||
<LinkButton Url="#" Title="微信-暂未实现" ImageUrl="images/weixin-2.svg" />
|
||||
<LinkButton Url="Account/Tencent" Title="使用 QQ 账号登录" ImageUrl="images/qq.svg" />
|
||||
<LinkButton Url="Account/Alipay" Title="使用支付宝账号登录" ImageUrl="images/zhifubao.svg" />
|
||||
</div>
|
||||
</Block>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,228 @@
|
|||
.wrap {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: #40485b;
|
||||
background-color: #f1f2f7;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
box-shadow: 0px 20px 80px 0px rgb(0 0 0 / 30%);
|
||||
width: 1000px;
|
||||
height: 500px;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
margin-top: calc(100vh / 2 - 275px);
|
||||
}
|
||||
|
||||
section {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.login-sidebox {
|
||||
position: relative;
|
||||
background: -webkit-gradient(linear, left bottom, left top, from(#3a485a), to(#607089));
|
||||
background: linear-gradient(0deg, #3a485a 0%, #607089 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.login-sidebox::before,
|
||||
.login-sidebox::after {
|
||||
content: '';
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.login-sidebox::before {
|
||||
background: url(../images/left-1.png) no-repeat 0 0;
|
||||
}
|
||||
|
||||
.login-sidebox::after {
|
||||
background: url(../images/left-2.png) no-repeat right bottom;
|
||||
}
|
||||
|
||||
.login-sidebox .login-sidebox-content {
|
||||
padding: 80px 80px 48px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.login-sidebox-header {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.login-sidebox-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.login-sidebox-logo img {
|
||||
width: 48px;
|
||||
height: auto;
|
||||
border-radius: 50%;
|
||||
margin-right: 14px;
|
||||
}
|
||||
|
||||
.login-sidebox-logo span {
|
||||
display: inline;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.login-sidebox-subtitle {
|
||||
font-size: 20pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.login-sidebox-footer {
|
||||
margin-top: 40px;
|
||||
border-top: solid 1px #ddd;
|
||||
padding-top: 28px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.login-sidebox-footer a {
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
padding: 64px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.login-form-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-form-header h2 {
|
||||
margin-bottom: 0;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.login-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.login-list .item {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.forget-password {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.form-signin-heading {
|
||||
margin: 0;
|
||||
padding: 20px 15px;
|
||||
text-align: center;
|
||||
background-color: #41cac0;
|
||||
border-radius: 5px 5px 0 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.login-sms,
|
||||
.is-mobile .login-up {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.is-mobile .login-sms {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::deep .btn-login {
|
||||
color: #fff;
|
||||
background: #fe7300;
|
||||
border-color: transparent;
|
||||
text-transform: uppercase;
|
||||
font-weight: 300;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
::deep .btn-login:hover {
|
||||
background: #fe7300;
|
||||
}
|
||||
|
||||
::deep .divider-wrap {
|
||||
background-color: #7c86bb;
|
||||
}
|
||||
|
||||
::deep .divider-text {
|
||||
background-color: #f1f2f7;
|
||||
}
|
||||
|
||||
.login-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.login-list ::deep img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
::deep .btn-sms {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.form-signin {
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
max-width: 320px;
|
||||
border: solid 1px #ddd;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.form-signin-heading {
|
||||
padding: 28px 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.slidercaptcha {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.slidercaptcha, .slidercaptcha.oauth {
|
||||
height: 280px;
|
||||
}
|
||||
|
||||
.slidercaptcha.card .card-body {
|
||||
padding: 15px 15px 0 15px;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.login-footer .login-footer-body li a {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
::deep .divider {
|
||||
margin: 1.5rem 0;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<Table TItem="TItem" IsBordered="true" IsStriped="true" IsMultipleSelect="IsMultipleSelect" @ref="Instance"
|
||||
IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader"
|
||||
IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeIcon="fa-chevron-circle-right"
|
||||
IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-chevron-circle-right"
|
||||
ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch"
|
||||
ShowEmpty="ShowEmpty" EmptyText="暂无数据" EmptyImage="images/empty.svg" SortString="@SortString"
|
||||
OnQueryAsync="OnQueryAsync!" OnDeleteAsync="OnDeleteAsync!" OnSaveAsync="OnSaveAsync!"
|
||||
|
@ -10,7 +10,7 @@
|
|||
ShowToolbar="ShowToolbar" ShowExtendButtons="ShowExtendButtons" ShowAddButton="@AuthorizeButton("add")"
|
||||
ShowDeleteButton="@AuthorizeButton("del")" ShowEditButton="@AuthorizeButton("edit")"
|
||||
ShowCardView="true" ShowColumnList="true" ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
|
||||
CustomerSearchModel="CustomerSearchModel" SelectedRows="SelectedRows"
|
||||
CustomerSearchModel="CustomerSearchModel" SelectedRows="SelectedRows" ModelEqualityComparer="ModelEqualityComparer!"
|
||||
ShowEditButtonCallback="ShowEditButtonCallback!" ShowDeleteButtonCallback="ShowDeleteButtonCallback!"
|
||||
TableToolbarTemplate="TableToolbarTemplate" TableColumns="TableColumns" EditTemplate="EditTemplate!"
|
||||
CustomerSearchTemplate="CustomerSearchTemplate!" RowButtonTemplate="RowButtonTemplate!">
|
||||
|
|
|
@ -145,7 +145,13 @@ namespace BootstrapAdmin.Web.Components
|
|||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, Task<IEnumerable<TItem>>>? OnTreeExpand { get; set; }
|
||||
public Func<TItem, Task<IEnumerable<TableTreeNode<TItem>>>>? OnTreeExpand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<IEnumerable<TItem>, Task<IEnumerable<TableTreeNode<TItem>>>>? TreeNodeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -177,6 +183,12 @@ namespace BootstrapAdmin.Web.Components
|
|||
[Parameter]
|
||||
public Func<TItem, bool>? ShowDeleteButtonCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, TItem, bool>? ModelEqualityComparer { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private Table<TItem>? Instance { get; set; }
|
||||
|
||||
|
|
|
@ -30,11 +30,9 @@
|
|||
<div class="col-12 col-sm-12">
|
||||
<BootstrapInput @bind-Value="Value.Favicon" placeholder="不可为空,2000字以内"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12">
|
||||
<div class="table-modal-footer text-end">
|
||||
<Button ButtonType="ButtonType.Button" Text="关闭" Icon="fa fa-close" Color="Color.Secondary" OnClick="OnClickClose"></Button>
|
||||
<Button ButtonType="ButtonType.Submit" Text="保存" Icon="fa fa-save"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<Button ButtonType="ButtonType.Button" Text="关闭" Icon="fa fa-close" Color="Color.Secondary" OnClick="OnClickClose"></Button>
|
||||
<Button ButtonType="ButtonType.Submit" Text="保存" Icon="fa fa-save"></Button>
|
||||
</div>
|
||||
</ValidateForm>
|
||||
|
|
|
@ -60,13 +60,12 @@ public partial class ClientDialog
|
|||
}
|
||||
}
|
||||
|
||||
private Task OnSaveCleint(EditContext context)
|
||||
private async Task OnSaveCleint(EditContext context)
|
||||
{
|
||||
if (OnSave != null)
|
||||
{
|
||||
OnSave(Value);
|
||||
await OnSave(Value);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnClickClose()
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
{
|
||||
var value = DictService.GetClientUrl(item.Value);
|
||||
<div class="col-12 col-sm-12">
|
||||
<BootstrapInputGroup>
|
||||
<BootstrapInputGroupLabel Text="@item.Key"></BootstrapInputGroupLabel>
|
||||
<BootstrapInputGroup @key="item.Key">
|
||||
<BootstrapInputGroupLabel DisplayText="@item.Key"></BootstrapInputGroupLabel>
|
||||
<BootstrapInput Value="value" Readonly="true"></BootstrapInput>
|
||||
<PopConfirmButton Placement="Placement.Top" Color="Color.Danger" Icon="fa fa-trash-o" ConfirmIcon="fa fa-exclamation-circle text-danger" ConfirmButtonColor="Color.Danger" Text="删除" Content="确定删除当前应用吗?" OnConfirm="() => OnDeleteClient(item.Value)" />
|
||||
<Button Icon="fa fa-edit" Text="编辑" OnClickWithoutRender="() => OnEditClient(item.Value)" />
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<div class="row g-3 form-inline">
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.Name" DisplayText="菜单名称" ShowLabel="true"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<MenuTree @bind-Value="Value.ParentId" Lookup="@ParementMenus" DisplayText="父级菜单"></MenuTree>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.Order"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="Value.Icon"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<BootstrapInput @bind-Value="Value.Url"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select @bind-Value="Value.Category"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select Items="@Targets" @bind-Value="Value.Target"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select @bind-Value="Value.IsResource"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select Items="@Apps" @bind-Value="Value.Application"></Select>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class MenuEditor
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public Navigation? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public List<SelectedItem>? ParementMenus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public List<SelectedItem>? Targets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public List<SelectedItem>? Apps { get; set; }
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<div class="tree-dialog">
|
||||
<label class="form-label">@DisplayText</label>
|
||||
<BootstrapInputGroup>
|
||||
<Display Value="Value" Lookup="Lookup" ShowLabel="false"></Display>
|
||||
<Button Icon="fa fa-times" Color="Color.Secondary" OnClick="OnClearText"></Button>
|
||||
<Button Icon="fa fa-bars" OnClick="OnSelectMenu"></Button>
|
||||
</BootstrapInputGroup>
|
||||
</div>
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Services;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class MenuTree
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public List<SelectedItem>? Lookup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public string? DisplayText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public string? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public EventCallback<string> ValueChanged { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private DialogService? DialogService { get; set; }
|
||||
|
||||
private DialogOption? Option { get; set; }
|
||||
|
||||
private async Task OnSelectMenu()
|
||||
{
|
||||
Option = new DialogOption()
|
||||
{
|
||||
IsScrolling = true,
|
||||
Title = "选择菜单",
|
||||
BodyTemplate = BootstrapDynamicComponent.CreateComponent<ParentMenuTree>(new Dictionary<string, object?>
|
||||
{
|
||||
[nameof(ParentMenuTree.Value)] = Value,
|
||||
[nameof(ParentMenuTree.ValueChanged)] = EventCallback.Factory.Create<string>(this, v => OnValueChanged(v))
|
||||
}).Render(),
|
||||
FooterTemplate = BootstrapDynamicComponent.CreateComponent<Button>(new Dictionary<string, object?>
|
||||
{
|
||||
[nameof(Button.Color)] = Color.Primary,
|
||||
[nameof(Button.Text)] = "确认",
|
||||
[nameof(Button.OnClick)] = EventCallback.Factory.Create<MouseEventArgs>(this, () =>
|
||||
{
|
||||
Option?.Dialog.Close();
|
||||
}),
|
||||
}).Render()
|
||||
};
|
||||
await DialogService.Show(Option);
|
||||
}
|
||||
|
||||
private Task OnClearText() => OnValueChanged("0");
|
||||
|
||||
private async Task OnValueChanged(string v)
|
||||
{
|
||||
if (Value != v)
|
||||
{
|
||||
Value = v;
|
||||
if (ValueChanged.HasDelegate)
|
||||
{
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
.tree-dialog {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tree-dialog ::deep .input-group {
|
||||
flex-wrap: nowrap !important
|
||||
}
|
|
@ -1,8 +1,15 @@
|
|||
@inherits AssignmentBase<Navigation>
|
||||
@inherits ComponentBase
|
||||
|
||||
<Tree Items="InternalItems" ShowCheckbox="true" ShowIcon="true" OnTreeItemChecked="@OnTreeItemChecked" />
|
||||
<div class="tree-menu">
|
||||
<Tree Items="InternalItems" ShowCheckbox="true" ShowIcon="true" @ref="MenusTree" />
|
||||
|
||||
<div class="form-footer">
|
||||
<Button Color="Color.Secondary" Icon="fa fa-times" Text="关闭" OnClickWithoutRender="OnClickClose" />
|
||||
<Button Color="Color.Primary" Icon="fa fa-save" Text="保存" OnClickWithoutRender="OnClickSave" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
RenderFragment<Navigation> RenderTreeItem => item =>
|
||||
@<div class="d-flex flex-fill"><span class="flex-fill">@item.Name</span><span class="mx-3">@item.Order</span><span class="app-type">@item.IsResource.ToDescriptionString()</span><span class="app-text">@GetApp(item.Application)</span></div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Extensions;
|
||||
|
||||
|
@ -15,10 +16,45 @@ public partial class NavigationTree
|
|||
[NotNull]
|
||||
private List<TreeItem>? InternalItems { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private Tree? MenusTree { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public List<Navigation>? Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public List<string>? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭弹窗回调委托
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public Func<Task>? OnClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 保存按钮回调委托
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public Func<List<string?>, Task>? OnSave { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -29,12 +65,9 @@ public partial class NavigationTree
|
|||
InternalItems = Items.ToTreeItemList(Value, RenderTreeItem);
|
||||
}
|
||||
|
||||
private Task OnTreeItemChecked(List<TreeItem> items)
|
||||
{
|
||||
Value = items.Select(i => i.Key!.ToString()!).ToList();
|
||||
OnValueChanged(Value);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private string GetApp(string? app) => DictService.GetApps().FirstOrDefault(i => i.Key == app).Value ?? "未设置";
|
||||
|
||||
private Task OnClickClose() => OnClose();
|
||||
|
||||
private Task OnClickSave() => OnSave(MenusTree.GetCheckedItems().Select(i => i.Key?.ToString()).ToList());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
.tree-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tree-menu ::deep .tree {
|
||||
flex: 1;
|
||||
margin: -1rem;
|
||||
padding: 1rem;
|
||||
max-height: calc(100vh - 173px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<Tree Items="InternalItems" ShowRadio="true" ShowIcon="true" OnTreeItemChecked="@OnTreeItemChecked" />
|
||||
|
||||
@code {
|
||||
RenderFragment<Navigation> RenderTreeItem => item =>
|
||||
@<div class="d-flex flex-fill"><span class="flex-fill">@item.Name</span><span class="mx-3">@item.Order</span><span class="app-type">@item.IsResource.ToDescriptionString()</span><span class="app-text">@GetApp(item.Application)</span></div>;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Extensions;
|
||||
using BootstrapAdmin.Web.Services;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class ParentMenuTree
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[EditorRequired]
|
||||
[NotNull]
|
||||
public string? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<string> ValueChanged { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private List<TreeItem>? InternalItems { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private INavigation? NavigationService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private BootstrapAppContext? Context { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
var items = NavigationService.GetAllMenus(Context.UserName);
|
||||
InternalItems = items.ToTreeItemList(new List<string> { Value }, RenderTreeItem);
|
||||
}
|
||||
|
||||
private async Task OnTreeItemChecked(List<TreeItem> items)
|
||||
{
|
||||
Value = items.First().Key?.ToString();
|
||||
if (ValueChanged.HasDelegate)
|
||||
{
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetApp(string? app) => DictService.GetApps().FirstOrDefault(i => i.Key == app).Value ?? "未设置";
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<BootstrapBlazor.Components.Console Items="@Messages" Height="280" ShowAutoScroll="true" />
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Models;
|
||||
using Longbow.Tasks;
|
||||
|
||||
namespace BootstrapAdmin.Web.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class TaskInfo : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
[EditorRequired]
|
||||
public TasksModel? Model { get; set; }
|
||||
|
||||
private List<ConsoleMessageItem> Messages { get; } = new(24);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
var sche = TaskServicesManager.Get(Model.Name);
|
||||
if (sche != null)
|
||||
{
|
||||
sche.Triggers.First().PulseCallback = async t => await DispatchMessage(t);
|
||||
await DispatchMessage(sche.Triggers.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DispatchMessage(ITrigger trigger)
|
||||
{
|
||||
var message = $"Trigger({trigger.GetType().Name}) LastRuntime: {trigger.LastRuntime} Run({trigger.LastResult}) NextRuntime: {trigger.NextRuntime} Elapsed: {trigger.LastRunElapsedTime.TotalSeconds}";
|
||||
Messages.Add(new ConsoleMessageItem()
|
||||
{
|
||||
Message = message
|
||||
});
|
||||
if (Messages.Count > 20)
|
||||
{
|
||||
Messages.RemoveAt(0);
|
||||
}
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
var sche = TaskServicesManager.Get(Model.Name);
|
||||
if (sche != null)
|
||||
{
|
||||
sche.Triggers.First().PulseCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
|
@ -18,9 +18,48 @@ public static class DialogExtensions
|
|||
public static Task ShowAssignmentDialog(this DialogService dialogService, string title, List<SelectedItem> items, List<string> value, Func<Task<bool>> saveCallback, ToastService? toast) => dialogService.ShowDialog<Assignment, SelectedItem>(title, items, value, saveCallback, toast);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 弹出菜单分配弹窗
|
||||
/// </summary>
|
||||
public static Task ShowNavigationDialog(this DialogService dialogService, string title, List<Navigation> items, List<string> value, Func<Task<bool>> saveCallback, ToastService? toast) => dialogService.ShowDialog<NavigationTree, Navigation>(title, items, value, saveCallback, toast);
|
||||
/// <param name="dialogService"></param>
|
||||
/// <param name="title">弹窗标题</param>
|
||||
/// <param name="menus">当前用户可用所有菜单集合</param>
|
||||
/// <param name="value">已分配菜单集合</param>
|
||||
/// <param name="saveCallback"></param>
|
||||
/// <param name="toast"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task ShowNavigationDialog(this DialogService dialogService, string title, List<Navigation> menus, List<string> value, Func<List<string>, Task<bool>> saveCallback, ToastService? toast)
|
||||
{
|
||||
var option = new DialogOption
|
||||
{
|
||||
Title = title,
|
||||
ShowFooter = false,
|
||||
IsScrolling = true,
|
||||
Class = "modal-dialog-menu"
|
||||
};
|
||||
var parameters = new Dictionary<string, object?>()
|
||||
{
|
||||
[nameof(NavigationTree.Items)] = menus,
|
||||
[nameof(NavigationTree.Value)] = value,
|
||||
[nameof(NavigationTree.OnClose)] = () => option.Dialog.Close(),
|
||||
[nameof(NavigationTree.OnSave)] = new Func<List<string>, Task>(async items =>
|
||||
{
|
||||
var ret = await saveCallback(items);
|
||||
if (toast != null)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
await toast.Success("分配操作", "操作成功!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await toast.Error("分配操作", "操作失败,请联系相关管理员!");
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
option.Component = BootstrapDynamicComponent.CreateComponent<NavigationTree>(parameters);
|
||||
await dialogService.Show(option);
|
||||
}
|
||||
|
||||
private static Task ShowDialog<TBody, TItem>(this DialogService dialogService, string title, List<TItem> items, List<string> value, Func<Task<bool>> saveCallback, ToastService? toast) where TBody : AssignmentBase<TItem> => dialogService.ShowSaveDialog<TBody>(title, async () =>
|
||||
{
|
||||
|
@ -38,15 +77,15 @@ public static class DialogExtensions
|
|||
}
|
||||
return ret;
|
||||
},
|
||||
new Dictionary<string, object?>
|
||||
parameters =>
|
||||
{
|
||||
[nameof(AssignmentBase<TItem>.Items)] = items,
|
||||
[nameof(AssignmentBase<TItem>.Value)] = value,
|
||||
[nameof(AssignmentBase<TItem>.OnValueChanged)] = new Action<List<string>>(v =>
|
||||
parameters.Add(nameof(AssignmentBase<TItem>.Items), items);
|
||||
parameters.Add(nameof(AssignmentBase<TItem>.Value), value);
|
||||
parameters.Add(nameof(AssignmentBase<TItem>.OnValueChanged), new Action<List<string>>(v =>
|
||||
{
|
||||
value.Clear();
|
||||
value.AddRange(v);
|
||||
})
|
||||
}));
|
||||
},
|
||||
op =>
|
||||
{
|
||||
|
|
|
@ -67,19 +67,13 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// var connString = configuration.GetConnectionString("bb");
|
||||
// builder.UseConnectionString(FreeSql.DataType.Sqlite, connString);
|
||||
//#if DEBUG
|
||||
// //调试sql语句输出
|
||||
// 调试sql语句输出
|
||||
// builder.UseMonitorCommand(cmd => System.Console.WriteLine(cmd.CommandText));
|
||||
//#endif
|
||||
// });
|
||||
|
||||
// 增加 PetaPoco 数据服务
|
||||
services.AddPetaPocoDataAccessServices((provider, builder) =>
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
var connString = configuration.GetConnectionString("bb");
|
||||
builder.UsingProvider<SQLiteDatabaseProvider>()
|
||||
.UsingConnectionString(connString);
|
||||
});
|
||||
services.AddPetaPocoDataAccessServices();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Components;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Shared;
|
||||
using BootstrapAdmin.Web.Utils;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
|
||||
namespace BootstrapAdmin.Web.Pages.Account;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Layout(typeof(LoginLayout))]
|
||||
[Route("/Account/Login")]
|
||||
public class Login : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[SupplyParameterFromQuery]
|
||||
[Parameter]
|
||||
public string? ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[SupplyParameterFromQuery]
|
||||
[Parameter]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[SupplyParameterFromQuery]
|
||||
[Parameter]
|
||||
public string? View { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictsService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// BuildRenderTree 方法
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(View))
|
||||
{
|
||||
View = $"0-{View}";
|
||||
}
|
||||
var view = LoginHelper.GetCurrentLoginTheme(View ?? DictsService.GetCurrentLogin());
|
||||
var componentType = view switch
|
||||
{
|
||||
"gitee" => typeof(AdminLoginGitee),
|
||||
_ => typeof(AdminLogin)
|
||||
};
|
||||
builder.OpenComponent(0, componentType);
|
||||
builder.AddAttribute(1, nameof(AdminLogin.ReturnUrl), ReturnUrl);
|
||||
builder.AddAttribute(2, nameof(AdminLogin.AppId), AppId);
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<AdminLoginFooter>(3);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
@layout LoginLayout
|
||||
@page "/Account/Login"
|
||||
|
||||
<div class="wrap">
|
||||
<div class="container">
|
||||
<AdminLogin ReturnUrl="@ReturnUrl" AppId="@AppId" />
|
||||
</div>
|
||||
</div>
|
|
@ -1,24 +0,0 @@
|
|||
.wrap {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.wrap {
|
||||
background-color: #5bc0de;
|
||||
background: url('../images/bg2.jpg') fixed no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: url('../images/bg3.png') no-repeat;
|
||||
background-size: contain;
|
||||
width: 704px;
|
||||
height: 404px;
|
||||
margin: 0 auto;
|
||||
margin-top: calc(100vh / 2 - 190px);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
@page "/Admin/Menus"
|
||||
|
||||
<AdminTable TItem="DataAccess.Models.Navigation"
|
||||
IsTree="true" OnTreeExpand="OnTreeExpand" ExtendButtonColumnWidth="200"
|
||||
CustomerSearchModel="SearchModel" OnQueryAsync="OnQueryAsync">
|
||||
IsTree="true" OnTreeExpand="OnTreeExpand" TreeNodeConverter="TreeNodeConverter" ModelEqualityComparer="ModelEqualityComparer"
|
||||
ExtendButtonColumnWidth="200" CustomerSearchModel="SearchModel" OnQueryAsync="OnQueryAsync">
|
||||
<TableToolbarTemplate>
|
||||
<TableToolbarButton TItem="DataAccess.Models.Navigation" Color="Color.Info" Icon="fa fa-sitemap" Text="分配角色"
|
||||
IsEnableWhenSelectedOneRow="true" IsShow="@AuthorizeButton("assignRole")"
|
||||
|
@ -23,35 +23,7 @@
|
|||
<TableColumn @bind-Field="@context.Application" Filterable="true" Lookup="Apps"></TableColumn>
|
||||
</TableColumns>
|
||||
<EditTemplate Context="v">
|
||||
<div class="row g-3 form-inline">
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="v.Name" DisplayText="菜单名称" ShowLabel="true"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select @bind-Value="v.ParentId" Items="@ParementMenus" IsDisabled="@(v.ParentId == "0")" DisplayText="父级菜单" ShowLabel="true"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="v.Order"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<BootstrapInput @bind-Value="v.Icon"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<BootstrapInput @bind-Value="v.Url"></BootstrapInput>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select @bind-Value="v.Category"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select Items="@Targets" @bind-Value="v.Target"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select @bind-Value="v.IsResource"></Select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-6">
|
||||
<Select Items="@Apps" @bind-Value="v.Application"></Select>
|
||||
</div>
|
||||
</div>
|
||||
<MenuEditor Value="v" ParementMenus="ParementMenus" Targets="Targets" Apps="Apps" />
|
||||
</EditTemplate>
|
||||
<RowButtonTemplate>
|
||||
<TableCellButton Size="Size.ExtraSmall" IsShow="@AuthorizeButton("assignRole")" Color="Color.Info" Icon="fa fa-sitemap" Text="分配角色" OnClick="() => OnAssignmentRoles(context)" />
|
||||
|
|
|
@ -123,9 +123,30 @@ public partial class Menus
|
|||
});
|
||||
}
|
||||
|
||||
private Task<IEnumerable<Navigation>> OnTreeExpand(Navigation menu)
|
||||
private Task<IEnumerable<TableTreeNode<Navigation>>> OnTreeExpand(Navigation menu)
|
||||
{
|
||||
var navs = NavigationService.GetAllMenus(AppContext.UserName);
|
||||
return Task.FromResult(navs.Where(m => m.ParentId == menu.Id).OrderBy(m => m.Order).AsEnumerable());
|
||||
return Task.FromResult(navs.Where(m => m.ParentId == menu.Id).OrderBy(m => m.Order).AsEnumerable().Select(i => new TableTreeNode<Navigation>(i)));
|
||||
}
|
||||
|
||||
private Task<IEnumerable<TableTreeNode<Navigation>>> TreeNodeConverter(IEnumerable<Navigation> items)
|
||||
{
|
||||
var ret = BuildTreeNodes(items, "0");
|
||||
return Task.FromResult(ret);
|
||||
|
||||
IEnumerable<TableTreeNode<Navigation>> BuildTreeNodes(IEnumerable<Navigation> items, string parentId)
|
||||
{
|
||||
var navs = NavigationService.GetAllMenus(AppContext.UserName);
|
||||
var ret = new List<TableTreeNode<Navigation>>();
|
||||
ret.AddRange(items.Where(i => i.ParentId == parentId).Select((nav, index) => new TableTreeNode<Navigation>(nav)
|
||||
{
|
||||
HasChildren = navs.Any(i => i.ParentId == nav.Id),
|
||||
IsExpand = navs.Any(i => i.ParentId == nav.Id),
|
||||
Items = BuildTreeNodes(navs.Where(i => i.ParentId == nav.Id), nav.Id)
|
||||
}));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ModelEqualityComparer(Navigation x, Navigation y) => x.Id == y.Id;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ public partial class Profiles
|
|||
[NotNull]
|
||||
private string? DefaultLogoFolder { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
[NotNull]
|
||||
private Layout? Layout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
@ -109,8 +113,13 @@ public partial class Profiles
|
|||
|
||||
private async Task OnSaveDisplayName(EditContext context)
|
||||
{
|
||||
var ret = UserService.SaveDisplayName(CurrentUser.DisplayName, CurrentUser.UserName);
|
||||
var ret = UserService.SaveDisplayName(CurrentUser.UserName, CurrentUser.DisplayName);
|
||||
await ShowToast(ret, "显示名称");
|
||||
if (ret)
|
||||
{
|
||||
AppContext.DisplayName = CurrentUser.DisplayName;
|
||||
await RenderLayout("displayName");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSavePassword(EditContext context)
|
||||
|
@ -177,4 +186,12 @@ public partial class Profiles
|
|||
await ShowToast(ret, "用户头像", "删除");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private async Task RenderLayout(string key)
|
||||
{
|
||||
if (Layout.OnUpdateAsync != null)
|
||||
{
|
||||
await Layout.OnUpdateAsync(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,12 +72,12 @@ public partial class Roles
|
|||
|
||||
private async Task OnAssignmentMenus(Role role)
|
||||
{
|
||||
var apps = NavigationService.GetAllMenus(AppContext.UserName);
|
||||
var menus = NavigationService.GetAllMenus(AppContext.UserName);
|
||||
var values = NavigationService.GetMenusByRoleId(role.Id);
|
||||
|
||||
await DialogService.ShowNavigationDialog($"分配菜单 - 当前角色: {role.RoleName}", apps, values, () =>
|
||||
await DialogService.ShowNavigationDialog($"分配菜单 - 当前角色: {role.RoleName}", menus, values, items =>
|
||||
{
|
||||
var ret = NavigationService.SaveMenusByRoleId(role.Id, values);
|
||||
var ret = NavigationService.SaveMenusByRoleId(role.Id, items);
|
||||
return Task.FromResult(ret);
|
||||
}, ToastService);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public partial class Settings
|
|||
base.OnInitialized();
|
||||
|
||||
IsDemo = DictService.IsDemo();
|
||||
Logins = DictService.GetLogins().ToSelectedItemList();
|
||||
Logins = DictService.GetLogins().ToSelectedItemList().OrderBy(i => i.Value).ToList();
|
||||
Themes = DictService.GetThemes().ToSelectedItemList();
|
||||
IPLocators = DictService.GetIpLocators().ToSelectedItemList();
|
||||
IPLocators.Insert(0, new SelectedItem("", "未选择"));
|
||||
|
@ -180,9 +180,9 @@ public partial class Settings
|
|||
|
||||
private async Task RenderLayout(string key)
|
||||
{
|
||||
if (Layout.OnUpdate != null)
|
||||
if (Layout.OnUpdateAsync != null)
|
||||
{
|
||||
await Layout.OnUpdate(key);
|
||||
await Layout.OnUpdateAsync(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapAdmin.Web.Components;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapAdmin.Web.Extensions;
|
||||
using BootstrapAdmin.Web.Models;
|
||||
|
@ -32,6 +33,10 @@ public partial class Tasks
|
|||
[NotNull]
|
||||
private IDict? DictService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private DialogService? DialogService { get; set; }
|
||||
|
||||
private bool IsDemo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -157,9 +162,18 @@ public partial class Tasks
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static Task OnLog(TasksModel model)
|
||||
private async Task OnLog(TasksModel model)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
var option = new DialogOption()
|
||||
{
|
||||
Class = "modal-dialog-task",
|
||||
Title = $"{model.Name} - 日志窗口(最新 20 条)",
|
||||
Component = BootstrapDynamicComponent.CreateComponent<TaskInfo>(new Dictionary<string, object?>
|
||||
{
|
||||
[nameof(TaskInfo.Model)] = model
|
||||
})
|
||||
};
|
||||
await DialogService.Show(option);
|
||||
}
|
||||
|
||||
private static bool OnCheckTaskStatus(TasksModel model) => model.Status != SchedulerStatus.Disabled;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
}
|
||||
},
|
||||
"profiles": {
|
||||
"BootstrapAdmin.Web": {
|
||||
"Console": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
|
|
|
@ -25,24 +25,24 @@ class AdminTaskService : BackgroundService
|
|||
/// <returns></returns>
|
||||
protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(() =>
|
||||
{
|
||||
TaskServicesManager.GetOrAdd("单次任务", token => Task.Delay(1000));
|
||||
TaskServicesManager.GetOrAdd("周期任务", token => Task.Delay(1000), TriggerBuilder.Default.WithInterval(10000).Build());
|
||||
TaskServicesManager.GetOrAdd("Cron 任务", token => Task.Delay(1000), TriggerBuilder.Build(Cron.Secondly(5)));
|
||||
TaskServicesManager.GetOrAdd("超时任务", token => Task.Delay(2000), TriggerBuilder.Default.WithTimeout(1000).WithInterval(1000).WithRepeatCount(2).Build());
|
||||
TaskServicesManager.GetOrAdd("单次任务", token => Task.Delay(1000, token));
|
||||
TaskServicesManager.GetOrAdd("周期任务", token => Task.Delay(1000, token), TriggerBuilder.Default.WithInterval(10000).Build());
|
||||
TaskServicesManager.GetOrAdd("Cron 任务", token => Task.Delay(1000, token), TriggerBuilder.Build(Cron.Secondly(5)));
|
||||
TaskServicesManager.GetOrAdd("超时任务", token => Task.Delay(2000, token), TriggerBuilder.Default.WithTimeout(1000).WithInterval(1000).WithRepeatCount(2).Build());
|
||||
|
||||
// 本机调试时此处会抛出异常,配置文件中默认开启了任务持久化到物理文件,此处异常只有首次加载时会抛出
|
||||
// 此处异常是示例自定义任务内部未进行捕获异常时任务仍然能继续运行,不会导致整个进程崩溃退出
|
||||
// 此处代码可注释掉
|
||||
//TaskServicesManager.GetOrAdd("故障任务", token => throw new Exception("故障任务"));
|
||||
TaskServicesManager.GetOrAdd("取消任务", token => Task.Delay(1000)).Triggers.First().Enabled = false;
|
||||
TaskServicesManager.GetOrAdd("取消任务", token => Task.Delay(1000, token)).Triggers.First().Enabled = false;
|
||||
|
||||
// 创建任务并禁用
|
||||
TaskServicesManager.GetOrAdd("禁用任务", token => Task.Delay(1000)).Status = SchedulerStatus.Disabled;
|
||||
TaskServicesManager.GetOrAdd("禁用任务", token => Task.Delay(1000, token)).Status = SchedulerStatus.Disabled;
|
||||
|
||||
// 真实任务负责批次写入数据执行脚本到日志中
|
||||
TaskServicesManager.GetOrAdd<DBLogTask>("SQL日志", TriggerBuilder.Build(Cron.Minutely()));
|
||||
|
||||
// 真实任务负责周期性设置健康检查结果开关为开启
|
||||
TaskServicesManager.GetOrAdd("健康检查", token => Task.FromResult(DictService.SaveHealthCheck()), TriggerBuilder.Build(Cron.Minutely(10)));
|
||||
});
|
||||
}, stoppingToken);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
<Layout SideWidth="0" IsPage="true" IsFullSide="true" IsFixedHeader="true"
|
||||
ShowFooter="true" ShowGotoTop="true" ShowCollapseBar="true" Menus="@MenuItems"
|
||||
OnAuthorizing="@OnAuthorizing" OnErrorHandleAsync="OnErrorHandleAsync"
|
||||
UseTabSet="true" TabDefaultUrl="/Admin/Index" OnUpdate="OnUpdate">
|
||||
UseTabSet="true" TabDefaultUrl="/Admin/Index" OnUpdateAsync="OnUpdateAsync">
|
||||
<Header>
|
||||
<span class="ms-3 flex-fill">Bootstrap of Blazor</span>
|
||||
<Logout ImageUrl="@Icon" DisplayName="@DisplayName" UserName="@UserName">
|
||||
<Logout ImageUrl="@Icon" DisplayName="@Context.DisplayName" UserName="@UserName">
|
||||
<LinkTemplate>
|
||||
<a href="/Admin/Profiles"><i class="fa fa-suitcase"></i>个人中心</a>
|
||||
<a href="/Admin/Index"><i class="fa fa-cog"></i>设置</a>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<div class="layout-user">
|
||||
<img class="layout-avatar" src="@Icon">
|
||||
<div class="layout-title">
|
||||
<span>@DisplayName</span>
|
||||
<span>@Context.DisplayName</span>
|
||||
</div>
|
||||
<div class="layout-user-state"></div>
|
||||
</div>
|
||||
|
|
|
@ -74,8 +74,6 @@ namespace BootstrapAdmin.Web.Shared
|
|||
|
||||
private string? Footer { get; set; }
|
||||
|
||||
private string? DisplayName { get; set; }
|
||||
|
||||
private string? UserName { get; set; }
|
||||
|
||||
private bool Lock { get; set; }
|
||||
|
@ -133,9 +131,8 @@ namespace BootstrapAdmin.Web.Shared
|
|||
if (!string.IsNullOrEmpty(UserName))
|
||||
{
|
||||
var user = UsersService.GetUserByUserName(UserName);
|
||||
DisplayName = user?.DisplayName ?? "未注册账户";
|
||||
Context.UserName = UserName;
|
||||
Context.DisplayName = DisplayName;
|
||||
Context.DisplayName = user?.DisplayName ?? "未注册账户";
|
||||
Icon = string.IsNullOrEmpty(user?.Icon) ? "/images/uploader/default.jpg" : GetIcon(user.Icon);
|
||||
|
||||
MenuItems = NavigationsService.GetAllMenus(UserName).ToMenus();
|
||||
|
@ -161,7 +158,7 @@ namespace BootstrapAdmin.Web.Shared
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Task OnUpdate(string key)
|
||||
public Task OnUpdateAsync(string key)
|
||||
{
|
||||
if (key == "title")
|
||||
{
|
||||
|
|
|
@ -50,4 +50,20 @@ public static class LoginHelper
|
|||
|
||||
return returnUrl ?? "/Admin/Index";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字典表中的配置 1-Login-Gitee 转化为 gitee
|
||||
/// </summary>
|
||||
/// <param name="loginTheme"></param>
|
||||
/// <returns></returns>
|
||||
public static string? GetCurrentLoginTheme(string loginTheme)
|
||||
{
|
||||
string? ret = null;
|
||||
var segs = loginTheme.Split('-');
|
||||
if (segs.Length == 3)
|
||||
{
|
||||
ret = segs[2].ToLowerInvariant();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@
|
|||
|
||||
@using BootstrapAdmin.Web.Components
|
||||
@using BootstrapAdmin.Web.Models
|
||||
@using BootstrapAdmin.Web.Shared
|
||||
@using BootstrapAdmin.Web.Shared
|
||||
|
|
|
@ -16,59 +16,9 @@
|
|||
}
|
||||
},
|
||||
"SimulateUserName": "",
|
||||
"AutoGenerateDatabase": true,
|
||||
"BootstrapAdminAuthenticationOptions": {
|
||||
"KeyPath": "..\\..\\keys"
|
||||
},
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "SqlServer",
|
||||
"SqlFolder": "..\\..\\..\\db\\SqlServer",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=.;Initial Catalog=BootstrapAdmin;User ID=sa;Password=sa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"ProviderName": "Sqlite",
|
||||
"SqlFolder": "..\\..\\..\\db\\SQLite",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=BootstrapAdmin.db;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "MySql",
|
||||
"SqlFolder": "..\\..\\..\\db\\MySQL",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BA;Uid=argozhang;Pwd=argo@163.com;SslMode=none;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "Oracle",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=XXXXXX)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)));User Id=XX;Password=XX"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "Npgsql",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BootstrapAdmin;User ID=argozhang;Password=argo@163.com;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"Widget": "Bootstrap.DataAccess.MongoDB",
|
||||
"ProviderName": "MongoDB",
|
||||
"SqlFolder": "..\\..\\..\\db\\MongoDB",
|
||||
"ConnectionStrings": {
|
||||
"ba": "mongodb://localhost:27017/BootstrapAdmin"
|
||||
}
|
||||
}
|
||||
],
|
||||
"SwaggerPathBase": "",
|
||||
"GiteeHealthChecks": "true",
|
||||
"AllowOrigins": "http://localhost:49185",
|
||||
|
@ -157,194 +107,5 @@
|
|||
"第二层",
|
||||
"第三层",
|
||||
"第四层"
|
||||
],
|
||||
"LongbowCache": {
|
||||
"Enabled": true,
|
||||
"CorsItems": [
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "ba",
|
||||
"Url": "CacheList.axd",
|
||||
"Desc": "后台管理数据缓存接口",
|
||||
"Self": true
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "App",
|
||||
"Url": "http://localhost:49185/CacheList.axd",
|
||||
"Desc": "测试系统",
|
||||
"Self": false
|
||||
}
|
||||
],
|
||||
"CacheItems": [
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRolesByUserName",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "指定用户角色数据缓存"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRolesByUrl",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过菜单获得角色数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "AppHelper-RetrieveAppsByUserName",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "指定用户授权应用数据缓存"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "BootstrapUser-RetrieveUsersByName",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "登录用户数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "BootstrapDict-RetrieveDicts",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "所有字典数据缓存"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "BootstrapMenu-RetrieveMenus",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "用户所有菜单数据缓存"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "GroupHelper-RetrieveGroupsByUserName",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "指定用户组数据缓存"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "UserHelper-RetrieveUsers",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "所有用户数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "UserHelper-RetrieveUsersByRoleId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过角色ID获得所有用户数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "UserHelper-RetrieveUsersByGroupId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过部门ID获得所有用户数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "UserHelper-RetrieveNewUsers",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "新用户数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "MenuHelper-RetrieveMenusByRoleId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过角色ID获得所有菜单数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRoles",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "所有角色数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRolesByUserId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过用户ID获得所有角色数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRolesByMenuId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过菜单ID获得所有角色数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "RoleHelper-RetrieveRolesByGroupId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过部门ID获得所有角色数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "GroupHelper-RetrieveGroups",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "所有部门数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "GroupHelper-RetrieveGroupsByUserId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过用户ID获得所有部门数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "GroupHelper-RetrieveGroupsByRoleId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过角色ID获得所有部门数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "AppHelper-RetrieveAppsByRoleId",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "通过角色ID获得所有应用程序数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "DictHelper-RetrieveDictsCategory",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "字典分类数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "ExceptionHelper-RetrieveExceptions",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "程序异常数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "MessageHelper-RetrieveMessages",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "站内消息数据"
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"Key": "TaskHelper-RetrieveTasks",
|
||||
"Interval": 600000,
|
||||
"SlidingExpiration": true,
|
||||
"Desc": "所有任务数据"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -20,51 +20,9 @@
|
|||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=.;Initial Catalog=BootstrapAdmin;User ID=sa;Password=sa",
|
||||
"bb": "Data Source=BootstrapAdmin.db;"
|
||||
"ba": "Data Source=BootstrapAdmin.db;"
|
||||
},
|
||||
"AutoGenerateDatabase": false,
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "SqlServer",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=.;Initial Catalog=BootstrapAdmin;User ID=sa;Password=sa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"ProviderName": "Sqlite",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=BootstrapAdmin.db;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "MySql",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BA;Uid=argozhang;Pwd=argo@163.com;SslMode=none;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "Npgsql",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BootstrapAdmin;User ID=argozhang;Password=argo@163.com;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"Widget": "Bootstrap.DataAccess.MongoDB",
|
||||
"ProviderName": "MongoDB",
|
||||
"ConnectionStrings": {
|
||||
"ba": "mongodb://localhost:27017/BootstrapAdmin"
|
||||
}
|
||||
}
|
||||
],
|
||||
"AppId": "BA",
|
||||
"UseHttps": true,
|
||||
"SwaggerPathBase": "",
|
||||
"AllowOrigins": "http://localhost,http://admin.blazor.zone",
|
||||
"HealthsCloudUrl": "https://client.blazor.zone/api/Interface/Healths",
|
||||
"GiteeHealthChecks": false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.layout.is-page .layout-side {
|
||||
.layout.is-page .layout-side {
|
||||
color: #3f4254;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 28px 0 rgb(82 63 105 / 5%);
|
||||
|
@ -26,3 +26,11 @@
|
|||
background-color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-task ::-webkit-scrollbar-thumb {
|
||||
background-color: #ffffff66;
|
||||
}
|
||||
|
||||
.modal-dialog-task ::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #ffffffb3;
|
||||
}
|
||||
|
|
|
@ -122,3 +122,12 @@
|
|||
.cell-icon {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.layout-user,
|
||||
.layout-menu {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.modal-dialog-menu.modal-dialog-scrollable .modal-body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.9-beta04" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.8.13" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.7" />
|
||||
<PackageReference Include="PetaPoco.Extensions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -26,56 +26,19 @@ public static class ServiceCollectionExtensions
|
|||
///
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddPetaPocoDataAccessServices(this IServiceCollection services, Action<IServiceProvider, IDatabaseBuildConfiguration> builder)
|
||||
public static IServiceCollection AddPetaPocoDataAccessServices(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IDatabase>(provider =>
|
||||
{
|
||||
var option = DatabaseConfiguration.Build();
|
||||
builder(provider, option);
|
||||
option.UsingDefaultMapper<BootstrapAdminConventionMapper>();
|
||||
var db = new Database(option);
|
||||
// 增加多数据库支持服务
|
||||
services.TryAddSingleton<IDBManager, DBManagerService>();
|
||||
|
||||
var logger = provider.GetRequiredService<ILogger<Database>>();
|
||||
db.ExceptionThrown += (sender, e) =>
|
||||
{
|
||||
var message = e.Exception.Format(new NameValueCollection()
|
||||
{
|
||||
[nameof(db.LastCommand)] = db.LastCommand,
|
||||
[nameof(db.LastArgs)] = string.Join(",", db.LastArgs)
|
||||
});
|
||||
logger.LogError(new EventId(1001, "GlobalException"), e.Exception, message);
|
||||
};
|
||||
var env = provider.GetRequiredService<IWebHostEnvironment>();
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
db.CommandExecuted += (sender, args) =>
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
foreach (DbParameter p in args.Command.Parameters)
|
||||
{
|
||||
parameters.AppendFormat("{0}: {1} ", p.ParameterName, p.Value);
|
||||
}
|
||||
logger.LogInformation(args.Command.CommandText);
|
||||
logger.LogInformation(parameters.ToString());
|
||||
};
|
||||
};
|
||||
return db;
|
||||
});
|
||||
|
||||
//// 增加数据服务
|
||||
//services.AddSingleton(typeof(IDataService<>), typeof(DefaultDataService<>));
|
||||
|
||||
//// 增加业务服务
|
||||
//services.AddSingleton<IApp, AppService>();
|
||||
// 增加业务服务
|
||||
services.AddSingleton<IDict, DictService>();
|
||||
//services.AddSingleton<IException, ExceptionService>();
|
||||
//services.AddSingleton<IGroup, GroupService>();
|
||||
//services.AddSingleton<ILogin, LoginService>();
|
||||
services.AddSingleton<INavigation, NavigationService>();
|
||||
//services.AddSingleton<IRole, RoleService>();
|
||||
services.AddSingleton<IUser, UserService>();
|
||||
|
||||
// 增加示例数据服务
|
||||
services.AddSingleton<IDummy, DummyService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PetaPoco;
|
||||
using PetaPoco.Providers;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
||||
|
||||
internal class DBManagerService : IDBManager
|
||||
{
|
||||
private IConfiguration Configuration { get; set; }
|
||||
|
||||
private ILogger<DBManagerService> Logger { get; set; }
|
||||
|
||||
private IWebHostEnvironment WebHost { get; set; }
|
||||
|
||||
public DBManagerService(IConfiguration configuration, ILogger<DBManagerService> logger, IWebHostEnvironment host)
|
||||
{
|
||||
Configuration = configuration;
|
||||
Logger = logger;
|
||||
WebHost = host;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建 IDatabase 实例方法
|
||||
/// </summary>
|
||||
/// <param name="connectionName">连接字符串键值</param>
|
||||
/// <param name="keepAlive"></param>
|
||||
/// <returns></returns>
|
||||
public IDatabase Create(string? connectionName = "ba", bool keepAlive = false)
|
||||
{
|
||||
var conn = Configuration.GetConnectionString(connectionName) ?? throw new ArgumentNullException(nameof(connectionName));
|
||||
|
||||
var option = DatabaseConfiguration.Build();
|
||||
option.UsingDefaultMapper<BootstrapAdminConventionMapper>();
|
||||
|
||||
// connectionstring
|
||||
option.UsingConnectionString(conn);
|
||||
|
||||
// provider
|
||||
option.UsingProvider<SQLiteDatabaseProvider>();
|
||||
|
||||
var db = new Database(option) { KeepConnectionAlive = keepAlive };
|
||||
|
||||
db.ExceptionThrown += (sender, e) =>
|
||||
{
|
||||
var message = e.Exception.Format(new NameValueCollection()
|
||||
{
|
||||
[nameof(db.LastCommand)] = db.LastCommand,
|
||||
[nameof(db.LastArgs)] = string.Join(",", db.LastArgs)
|
||||
});
|
||||
Logger.LogError(new EventId(1001, "GlobalException"), e.Exception, message);
|
||||
};
|
||||
if (WebHost.IsDevelopment())
|
||||
{
|
||||
db.CommandExecuted += (sender, args) =>
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
foreach (DbParameter p in args.Command.Parameters)
|
||||
{
|
||||
parameters.AppendFormat("{0}: {1} ", p.ParameterName, p.Value);
|
||||
}
|
||||
Logger.LogInformation(args.Command.CommandText);
|
||||
Logger.LogInformation(parameters.ToString());
|
||||
};
|
||||
};
|
||||
return db;
|
||||
}
|
||||
}
|
|
@ -10,15 +10,19 @@ namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
|||
|
||||
class DictService : IDict
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public DictService(IDatabase db) => Database = db;
|
||||
public DictService(IDBManager db) => DBManager = db;
|
||||
|
||||
public List<Dict> GetAll() => Database.Fetch<Dict>();
|
||||
public List<Dict> GetAll()
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<Dict>();
|
||||
}
|
||||
|
||||
public bool IsDemo()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapClient.DataAccess.Models;
|
||||
using BootstrapClient.Web.Core;
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
||||
|
||||
internal class DummyService : IDummy
|
||||
{
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public DummyService(IDBManager db)
|
||||
{
|
||||
DBManager = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DummyEntity> GetAll()
|
||||
{
|
||||
return new List<DummyEntity>()
|
||||
{
|
||||
new() { Id= "1", Name ="Dummy1" },
|
||||
new() { Id= "2", Name ="Dummy2" }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IDBManager
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IDatabase Create(string? connectionName = "ba", bool keepAlive = false);
|
||||
}
|
|
@ -13,13 +13,13 @@ namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
|||
/// </summary>
|
||||
class NavigationService : INavigation
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public NavigationService(IDatabase db) => Database = db;
|
||||
public NavigationService(IDBManager db) => DBManager = db;
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定用户名可访问的所有菜单集合
|
||||
|
@ -28,7 +28,8 @@ class NavigationService : INavigation
|
|||
/// <returns>未层次化的菜单集合</returns>
|
||||
public List<Navigation> GetMenus(string userName)
|
||||
{
|
||||
var order = Database.Provider.EscapeSqlIdentifier("Order");
|
||||
return Database.Fetch<Navigation>($"select n.ID, n.ParentId, n.Name, n.{order}, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application from Navigations n inner join (select nr.NavigationID from Users u inner join UserRole ur on ur.UserID = u.ID inner join NavigationRole nr on nr.RoleID = ur.RoleID where u.UserName = @UserName union select nr.NavigationID from Users u inner join UserGroup ug on u.ID = ug.UserID inner join RoleGroup rg on rg.GroupID = ug.GroupID inner join NavigationRole nr on nr.RoleID = rg.RoleID where u.UserName = @UserName union select n.ID from Navigations n where EXISTS (select UserName from Users u inner join UserRole ur on u.ID = ur.UserID inner join Roles r on ur.RoleID = r.ID where u.UserName = @UserName and r.RoleName = 'Administrators')) nav on n.ID = nav.NavigationID Where n.Category = '1' ORDER BY n.Application, n.{order}", new { UserName = userName });
|
||||
using var db = DBManager.Create ();
|
||||
var order = db.Provider.EscapeSqlIdentifier("Order");
|
||||
return db.Fetch<Navigation>($"select n.ID, n.ParentId, n.Name, n.{order}, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application from Navigations n inner join (select nr.NavigationID from Users u inner join UserRole ur on ur.UserID = u.ID inner join NavigationRole nr on nr.RoleID = ur.RoleID where u.UserName = @UserName union select nr.NavigationID from Users u inner join UserGroup ug on u.ID = ug.UserID inner join RoleGroup rg on rg.GroupID = ug.GroupID inner join NavigationRole nr on nr.RoleID = rg.RoleID where u.UserName = @UserName union select n.ID from Navigations n where EXISTS (select UserName from Users u inner join UserRole ur on u.ID = ur.UserID inner join Roles r on ur.RoleID = r.ID where u.UserName = @UserName and r.RoleName = 'Administrators')) nav on n.ID = nav.NavigationID Where n.Category = '1' ORDER BY n.Application, n.{order}", new { UserName = userName });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,32 +10,49 @@ namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
|||
|
||||
class UserService : IUser
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
private IDBManager DBManager { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public UserService(IDatabase db) => Database = db;
|
||||
public UserService(IDBManager db) => DBManager = db;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public User? GetUserByUserName(string? userName) => string.IsNullOrEmpty(userName) ? null : Database.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
public User? GetUserByUserName(string? userName)
|
||||
{
|
||||
User? user = null;
|
||||
if (!string.IsNullOrEmpty(userName))
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
user = db.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetApps(string userName) => Database.Fetch<string>($"select d.Code from Dicts d inner join RoleApp ra on d.Code = ra.AppId inner join (select r.Id from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 union select r.Id from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0) r on ra.RoleId = r.ID union select Code from Dicts where Category = @1 and exists(select r.ID from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 and r.RoleName = @2 union select r.ID from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0 and r.RoleName = @2)", userName, "应用程序", "Administrators");
|
||||
public List<string> GetApps(string userName)
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>($"select d.Code from Dicts d inner join RoleApp ra on d.Code = ra.AppId inner join (select r.Id from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 union select r.Id from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0) r on ra.RoleId = r.ID union select Code from Dicts where Category = @1 and exists(select r.ID from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 and r.RoleName = @2 union select r.ID from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0 and r.RoleName = @2)", userName, "应用程序", "Administrators");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetRoles(string userName) => Database.Fetch<string>($"select r.RoleName from Roles r inner join UserRole ur on r.ID=ur.RoleID inner join Users u on ur.UserID = u.ID and u.UserName = @0 union select r.RoleName from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID and u.UserName=@0", userName);
|
||||
public List<string> GetRoles(string userName)
|
||||
{
|
||||
using var db = DBManager.Create();
|
||||
return db.Fetch<string>($"select r.RoleName from Roles r inner join UserRole ur on r.ID=ur.RoleID inner join Users u on ur.UserID = u.ID and u.UserName = @0 union select r.RoleName from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {db.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID and u.UserName=@0", userName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,17 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BootstrapClient.DataAccess\BootstrapClient.DataAccess.PetaPoco.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="BootstrapBlazor.Components" />
|
||||
<Using Include="Microsoft.AspNetCore.Components" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
@typeparam TItem
|
||||
|
||||
<Table TItem="TItem" IsBordered="true" IsStriped="true" IsMultipleSelect="IsMultipleSelect" @ref="Instance"
|
||||
IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader"
|
||||
IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-chevron-circle-right"
|
||||
ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch"
|
||||
ShowEmpty="ShowEmpty" EmptyText="暂无数据" EmptyImage="images/empty.svg" SortString="@SortString"
|
||||
OnQueryAsync="OnQueryAsync!" OnDeleteAsync="OnDeleteAsync!" OnSaveAsync="OnSaveAsync!"
|
||||
ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch"
|
||||
ShowToolbar="ShowToolbar" ShowExtendButtons="ShowExtendButtons" ShowAddButton="@AuthorizeButton("add")"
|
||||
ShowDeleteButton="@AuthorizeButton("del")" ShowEditButton="@AuthorizeButton("edit")"
|
||||
ShowCardView="true" ShowColumnList="true" ExtendButtonColumnWidth="@ExtendButtonColumnWidth"
|
||||
CustomerSearchModel="CustomerSearchModel" SelectedRows="SelectedRows"
|
||||
ShowEditButtonCallback="ShowEditButtonCallback!" ShowDeleteButtonCallback="ShowDeleteButtonCallback!"
|
||||
TableToolbarTemplate="TableToolbarTemplate" TableColumns="TableColumns" EditTemplate="EditTemplate!"
|
||||
CustomerSearchTemplate="CustomerSearchTemplate!" RowButtonTemplate="RowButtonTemplate!">
|
||||
</Table>
|
|
@ -0,0 +1,222 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using Bootstrap.Security.Blazor;
|
||||
using BootstrapClient.Web.Shared.Services;
|
||||
|
||||
namespace BootstrapClient.Web.Shared.Components
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[CascadingTypeParameter(nameof(TItem))]
|
||||
public partial class AdminTable<TItem> where TItem : class, new()
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public IEnumerable<int>? PageItemsSource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int ExtendButtonColumnWidth { get; set; } = 130;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? SortString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
[Parameter]
|
||||
public RenderFragment<TItem>? TableColumns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<TItem>? RowButtonTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<ITableSearchModel>? CustomerSearchTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public RenderFragment<TItem>? EditTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
[Parameter]
|
||||
public RenderFragment? TableToolbarTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsPagination { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsMultipleSelect { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsFixedHeader { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowToolbar { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowEmpty { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowLoading { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowSearch { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowAdvancedSearch { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowDefaultButtons { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowExtendButtons { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ITableSearchModel? CustomerSearchModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<QueryPageOptions, Task<QueryData<TItem>>>? OnQueryAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, Task<IEnumerable<TableTreeNode<TItem>>>>? OnTreeExpand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<IEnumerable<TItem>, Task<IEnumerable<TableTreeNode<TItem>>>>? TreeNodeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, ItemChangedType, Task<bool>>? OnSaveAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<IEnumerable<TItem>, Task<bool>>? OnDeleteAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public List<TItem>? SelectedRows { get; set; } = new List<TItem>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, bool>? ShowEditButtonCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<TItem, bool>? ShowDeleteButtonCallback { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private Table<TItem>? Instance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public ValueTask ToggleLoading(bool v) => Instance.ToggleLoading(v);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public Task QueryAsync() => Instance.QueryAsync();
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IBootstrapAdminService? AdminService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private NavigationManager? NavigationManager { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private BootstrapAppContext? AppContext { get; set; }
|
||||
|
||||
private bool AuthorizeButton(string operate)
|
||||
{
|
||||
var url = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
|
||||
return AdminService.AuhorizingBlock(AppContext.UserName, url, operate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
@using BootstrapClient.Web.Shared.Components
|
||||
@page "/dummy"
|
||||
|
||||
<AdminTable TItem="BootstrapClient.DataAccess.Models.DummyEntity" OnQueryAsync="OnQueryAsync">
|
||||
<TableColumns>
|
||||
<TableColumn @bind-Field="context.Id"></TableColumn>
|
||||
<TableColumn @bind-Field="context.Name"></TableColumn>
|
||||
</TableColumns>
|
||||
</AdminTable>
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapClient.DataAccess.Models;
|
||||
using BootstrapClient.Web.Core;
|
||||
|
||||
namespace BootstrapClient.Web.Shared.Pages;
|
||||
|
||||
public partial class Dummy
|
||||
{
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDummy? DummyService { get; set; }
|
||||
|
||||
private Task<QueryData<DummyEntity>> OnQueryAsync(QueryPageOptions options)
|
||||
{
|
||||
var items = DummyService.GetAll();
|
||||
var ret = new QueryData<DummyEntity>()
|
||||
{
|
||||
Items = items
|
||||
};
|
||||
return Task.FromResult(ret);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
@page "/"
|
||||
@page "/Home/Index"
|
||||
@attribute [TabItemOption(Text = "首页", Icon = "fa fa-fa")]
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
IsFullSide="@IsFullSide" IsFixedHeader="@IsFixedHeader" IsFixedFooter="@IsFixedFooter" ShowFooter="@ShowFooter"
|
||||
Menus="@MenuItems" UseTabSet="@UseTabSet"
|
||||
TabDefaultUrl="/Home/Index"
|
||||
AdditionalAssemblies="new[] { GetType().Assembly }" OnAuthorizing="@OnAuthorizing" class="@Theme">
|
||||
AdditionalAssemblies="new[] { GetType().Assembly }" OnAuthorizing="@OnAuthorizing" class="@ClassString">
|
||||
<Header>
|
||||
<span class="ml-3 flex-sm-fill d-none d-sm-block">Bootstrap of Blazor</span>
|
||||
<Widget></Widget>
|
||||
|
|
|
@ -9,6 +9,7 @@ using BootstrapClient.Web.Shared.Extensions;
|
|||
using BootstrapClient.Web.Shared.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace BootstrapClient.Web.Shared.Shared;
|
||||
|
||||
|
@ -43,6 +44,10 @@ public sealed partial class MainLayout
|
|||
|
||||
private string? Footer { get; set; }
|
||||
|
||||
private string? ClassString => CssBuilder.Default(Theme)
|
||||
.AddClass("is-fixed-tab")
|
||||
.Build();
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IBootstrapAdminService? SecurityService { get; set; }
|
||||
|
@ -71,6 +76,10 @@ public sealed partial class MainLayout
|
|||
[NotNull]
|
||||
private BootstrapAppContext? Context { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IConfiguration? Configuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
|
@ -107,6 +116,13 @@ public sealed partial class MainLayout
|
|||
MenuItems = NavigationsService.GetMenus(userName).Where(i => i.Application == Context.AppId).ToMenus();
|
||||
|
||||
Context.DisplayName = user?.DisplayName ?? "未注册账户";
|
||||
|
||||
// 增加模拟账户识别
|
||||
if (!string.IsNullOrEmpty(Configuration.GetValue("SimulateUserName", string.Empty)))
|
||||
{
|
||||
Context.DisplayName = $"{Context.DisplayName} (模拟)";
|
||||
}
|
||||
|
||||
Title = DictsService.GetWebTitle(Context.AppId);
|
||||
Footer = DictsService.GetWebFooter(Context.AppId);
|
||||
}
|
||||
|
|
|
@ -310,3 +310,17 @@
|
|||
.widget .dropdown-item:not(:nth-of-type(odd)):active {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.is-page .layout-main > .tabs {
|
||||
height: calc(100vh - 90px);
|
||||
}
|
||||
|
||||
.is-fixed-tab .tabs-body {
|
||||
height: calc(100vh - 89px - var(--bb-footer-height));
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.is-fixed-tab .tabs-body .tabs-body-content {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
|
|
@ -56,4 +56,18 @@ public class AdminService : IBootstrapAdminService
|
|||
}
|
||||
return Task.FromResult(ret);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="blockName"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public bool AuhorizingBlock(string userName, string url, string blockName)
|
||||
{
|
||||
// Client 暂时未使用
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bootstrap.Security.Blazor" Version="6.0.1-beta01" />
|
||||
<PackageReference Include="Bootstrap.Security.Blazor" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
using BootstrapClient.DataAccess.Models;
|
||||
|
||||
namespace BootstrapClient.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 数据服务示例接口
|
||||
/// </summary>
|
||||
public interface IDummy
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得 全部数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DummyEntity> GetAll();
|
||||
}
|
|
@ -2,24 +2,20 @@
|
|||
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
|
||||
// Website: https://admin.blazor.zone
|
||||
|
||||
namespace BootstrapAdmin.Web.Pages.Account;
|
||||
namespace BootstrapClient.DataAccess.Models;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 数据库实体类
|
||||
/// </summary>
|
||||
public partial class Login
|
||||
public class DummyEntity
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 Id
|
||||
/// </summary>
|
||||
[SupplyParameterFromQuery]
|
||||
[Parameter]
|
||||
public string? ReturnUrl { get; set; }
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 Name
|
||||
/// </summary>
|
||||
[SupplyParameterFromQuery]
|
||||
[Parameter]
|
||||
public string? AppId { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
|
@ -33,13 +33,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.AddScoped<BootstrapAppContext>();
|
||||
|
||||
// 增加 PetaPoco 数据服务
|
||||
services.AddPetaPocoDataAccessServices((provider, builder) =>
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
var connString = configuration.GetConnectionString("ba");
|
||||
builder.UsingProvider<SQLiteDatabaseProvider>()
|
||||
.UsingConnectionString(connString);
|
||||
});
|
||||
services.AddPetaPocoDataAccessServices();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Bootstrap.Client.Blazor": {
|
||||
"Client": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
|
|
|
@ -12,34 +12,5 @@
|
|||
"BootstrapAdminAuthenticationOptions": {
|
||||
"AuthHost": "http://localhost:5210",
|
||||
"KeyPath": "..\\..\\keys"
|
||||
},
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"ProviderName": "Sqlite",
|
||||
"ConnectionStrings": {
|
||||
"bb": "..\\..\\admin\\BootstrapAdmin.Web\\BootstrapAdmin.db;",
|
||||
"client": "Data Source=Client.db;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "MySql",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BootstrapAdmin;Uid=root;Pwd=argo@163.com;SslMode=none;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"Widget": "Bootstrap.Client.DataAccess.MongoDB",
|
||||
"ProviderName": "MongoDB",
|
||||
"ConnectionStrings": {
|
||||
"ba": "mongodb://localhost:27017/BootstrapAdmin",
|
||||
"client": "mongodb://localhost:27017/BootstrapClient"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,32 +16,7 @@
|
|||
"ba": "Data Source=..\\..\\admin\\BootstrapAdmin.Web\\BootstrapAdmin.db;",
|
||||
"client": "Data Source=Client.db;"
|
||||
},
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false
|
||||
},
|
||||
{
|
||||
"Enabled": true,
|
||||
"ProviderName": "Sqlite",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=..\\..\\admin\\BootstrapAdmin.Web\\BootstrapAdmin.db;",
|
||||
"client": "Data Source=Client.db;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"ProviderName": "MySql",
|
||||
"ConnectionStrings": {
|
||||
"ba": "Server=localhost;Database=BootstrapAdmin;Uid=argozhang;Pwd=argo@163.com;SslMode=none;"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Enabled": false,
|
||||
"Widget": "Bootstrap.Client.DataAccess.MongoDB",
|
||||
"ProviderName": "MongoDB",
|
||||
"ConnectionStrings": {
|
||||
"ba": "mongodb://localhost:27017/BootstrapAdmin"
|
||||
}
|
||||
}
|
||||
]
|
||||
"BootstrapBlazorOptions": {
|
||||
"DefaultCultureInfo": "zh-CN"
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue