Merge branch 'dev' into dev-WeChat

# Conflicts:
#	src/admin/Bootstrap.Admin/Startup.cs
#	src/admin/Bootstrap.Admin/Views/Account/Login.cshtml
This commit is contained in:
Argo Zhang 2019-09-28 13:34:15 +08:00 committed by Argo Zhang
commit 289d9561c8
No known key found for this signature in database
GPG Key ID: 152E398953DDF19F
73 changed files with 985 additions and 195 deletions

View File

@ -3,7 +3,7 @@
# (note that '\' need to be escaped).
[issuetracker "Gitee-Issue"]
regex = "#((?!.*Issue|issue|Comme|comme).{5})"
regex = "#((?!.*Issue|issue|Comme|comme)[A-Za-z0-9]+)"
url = "https://gitee.com/LongbowEnterprise/BootstrapAdmin/issues/$1?from=project-issue"
[issuetracker "Gitee-Url"]

View File

@ -5,14 +5,14 @@ VisualStudioVersion = 16.0.29215.179
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLServer", "SQLServer", "{87319AF5-7C40-4362-B67C-35F9DD737DB4}"
ProjectSection(SolutionItems) = preProject
scripts\SqlServer\InitData.sql = scripts\SqlServer\InitData.sql
scripts\SqlServer\install.ps1 = scripts\SqlServer\install.ps1
scripts\SqlServer\Install.sql = scripts\SqlServer\Install.sql
db\SqlServer\InitData.sql = db\SqlServer\InitData.sql
db\SqlServer\install.ps1 = db\SqlServer\install.ps1
db\SqlServer\Install.sql = db\SqlServer\Install.sql
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Admin", "src\admin\Bootstrap.Admin\Bootstrap.Admin.csproj", "{7B2B7043-3CB2-4C5A-BDF2-8C47F1A5471A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{586410F2-C1F0-47CD-AB28-2CF506DED2C8}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "db", "db", "{586410F2-C1F0-47CD-AB28-2CF506DED2C8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client", "src\client\Bootstrap.Client\Bootstrap.Client.csproj", "{C82A6E45-AB90-43D1-8429-5CBE953D8151}"
EndProject
@ -22,37 +22,37 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess", "src
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLite", "SQLite", "{523515EC-2AD7-4282-9AF4-9D20371183B0}"
ProjectSection(SolutionItems) = preProject
scripts\SQLite\InitData.sql = scripts\SQLite\InitData.sql
scripts\SQLite\Install.sql = scripts\SQLite\Install.sql
db\SQLite\InitData.sql = db\SQLite\InitData.sql
db\SQLite\Install.sql = db\SQLite\Install.sql
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.DataAccess.MongoDB", "src\admin\Bootstrap.DataAccess.MongoDB\Bootstrap.DataAccess.MongoDB.csproj", "{8336F096-4B4A-4710-A1FA-0F5E44CD8D26}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongoDB", "MongoDB", "{A06A0AD8-A246-4329-B024-7174AE4A3EDE}"
ProjectSection(SolutionItems) = preProject
scripts\MongoDB\Dicts.js = scripts\MongoDB\Dicts.js
scripts\MongoDB\Groups.js = scripts\MongoDB\Groups.js
scripts\MongoDB\init.js = scripts\MongoDB\init.js
scripts\MongoDB\install.sh = scripts\MongoDB\install.sh
scripts\MongoDB\Navigations.js = scripts\MongoDB\Navigations.js
scripts\MongoDB\Roles.js = scripts\MongoDB\Roles.js
scripts\MongoDB\Users.js = scripts\MongoDB\Users.js
db\MongoDB\Dicts.js = db\MongoDB\Dicts.js
db\MongoDB\Groups.js = db\MongoDB\Groups.js
db\MongoDB\init.js = db\MongoDB\init.js
db\MongoDB\install.sh = db\MongoDB\install.sh
db\MongoDB\Navigations.js = db\MongoDB\Navigations.js
db\MongoDB\Roles.js = db\MongoDB\Roles.js
db\MongoDB\Users.js = db\MongoDB\Users.js
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MySQL", "MySQL", "{084E2E94-6B7D-4D3E-9BF1-6972427FBF80}"
ProjectSection(SolutionItems) = preProject
scripts\MySQL\initData.sql = scripts\MySQL\initData.sql
scripts\MySQL\install.sh = scripts\MySQL\install.sh
scripts\MySQL\install.sql = scripts\MySQL\install.sql
scripts\MySQL\my.ini = scripts\MySQL\my.ini
db\MySQL\initData.sql = db\MySQL\initData.sql
db\MySQL\install.sh = db\MySQL\install.sh
db\MySQL\install.sql = db\MySQL\install.sql
db\MySQL\my.ini = db\MySQL\my.ini
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\UnitTest\UnitTest.csproj", "{CFE75C48-F9D5-403A-8419-D07939BBD769}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Postgresql", "Postgresql", "{6F61C2AC-84D4-48A9-8A48-680657CC8175}"
ProjectSection(SolutionItems) = preProject
scripts\Postgresql\initData.sql = scripts\Postgresql\initData.sql
scripts\Postgresql\install.sql = scripts\Postgresql\install.sql
db\Postgresql\initData.sql = db\Postgresql\initData.sql
db\Postgresql\install.sql = db\Postgresql\install.sql
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bootstrap.Client.DataAccess", "src\client\Bootstrap.Client.DataAccess\Bootstrap.Client.DataAccess.csproj", "{843811A2-FE49-410F-BF9F-9F1FB14A1DEE}"
@ -84,6 +84,31 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{85574E
src\admin\Bootstrap.Admin\Linux.Dockerfile = src\admin\Bootstrap.Admin\Linux.Dockerfile
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "srcipts", "srcipts", "{72C103DB-E1D3-449F-97C2-DF12CA111FD4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "win", "win", "{C6F2DCA0-7941-4C28-9328-2D495F5DCB00}"
ProjectSection(SolutionItems) = preProject
publish-admin.cmd = publish-admin.cmd
publish-client.cmd = publish-client.cmd
watch-run-admin.cmd = watch-run-admin.cmd
watch-run-client.cmd = watch-run-client.cmd
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "linux", "linux", "{FDCFC3E3-14CF-40B2-9FE5-5BC239AAC110}"
ProjectSection(SolutionItems) = preProject
publish-admin.sh = publish-admin.sh
publish-client.sh = publish-client.sh
watch-run-admin.sh = watch-run-admin.sh
watch-run-client.sh = watch-run-client.sh
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ci", "ci", "{5F732D4E-133B-4DA6-811B-C369CDC3FB89}"
ProjectSection(SolutionItems) = preProject
appveyor.build.ps1 = appveyor.build.ps1
appveyor.test.ps1 = appveyor.test.ps1
appveyor.yml = appveyor.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -137,6 +162,9 @@ Global
{843811A2-FE49-410F-BF9F-9F1FB14A1DEE} = {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}
{BC1C6D63-ADA9-4C3B-89F0-CEB191A86BF5} = {C7F51A14-2D89-4D1F-AD78-C42B79AB0BF0}
{E03B7391-B52F-4449-B400-5CD9DE01F085} = {41B6D37A-5E5E-42B3-85E4-D81A81E3D757}
{C6F2DCA0-7941-4C28-9328-2D495F5DCB00} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
{FDCFC3E3-14CF-40B2-9FE5-5BC239AAC110} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
{5F732D4E-133B-4DA6-811B-C369CDC3FB89} = {72C103DB-E1D3-449F-97C2-DF12CA111FD4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {221EAE38-5F75-4391-9A48-E462A9F3B8FC}

View File

@ -12,6 +12,14 @@
<MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
</PropertyGroup>
<Target Condition=" '$(TargetFramework)' == 'netcoreapp2.2' " Name="PostPublish" AfterTargets="Publish">
<Message Text="Publish -> $(PublishDir)" Importance="high" />
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\keys\Longbow.lic" SkipUnchangedFiles="true" />
<Copy Condition="'$(OS)' == 'UNIX'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src/admin/keys/Longbow.lic" SkipUnchangedFiles="true" />
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\Bootstrap.Admin\BootstrapAdmin.db" SkipUnchangedFiles="true" />
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src/admin/Bootstrap.Admin/BootstrapAdmin.db" SkipUnchangedFiles="true" />
</Target>
<Target Condition=" '$(TargetFramework)' == 'netcoreapp2.2' " Name="PostBuild" AfterTargets="PostBuildEvent">
<Message Text="Copy file -> $(TargetDir)" Importance="high" />
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(TargetDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\keys\Longbow.lic" SkipUnchangedFiles="true" />

View File

@ -4,12 +4,3 @@
}
runCmd "dotnet build src\admin\Bootstrap.Admin"
runCmd "dotnet publish src\admin\Bootstrap.Admin --configuration Release --no-restore"
$publishFolder = "$($env:appveyor_build_folder)\src\admin\Bootstrap.Admin\bin\Release\netcoreapp2.2\publish"
$licFile = "$($env:appveyor_build_folder)\src\admin\keys\Longbow.lic"
write-host "copy file $licFile" -ForegroundColor Cyan
xcopy $licFile $publishFolder /y
$dbFile = "$($env:appveyor_build_folder)\src\admin\Bootstrap.Admin\BootstrapAdmin.db"
write-host "copy file $dbFile" -ForegroundColor Cyan
xcopy $dbFile $publishFolder /y

View File

@ -1,6 +1,6 @@
function installDB() {
write-host "init sqlserver database..." -ForegroundColor Cyan
$startPath = "$($env:appveyor_build_folder)\scripts\SqlServer"
$startPath = "$($env:appveyor_build_folder)\db\SqlServer"
$sqlInstance = "(local)\SQL2014"
$outFile = join-path $startPath "output.log"
$sqlFile = join-path $startPath "Install.sql"
@ -14,7 +14,7 @@
$cmd = $mysql + ' -e "create database BootstrapAdmin;" -uroot'
cmd.exe /c $cmd
$startPath = "$($env:appveyor_build_folder)\scripts\MySQL"
$startPath = "$($env:appveyor_build_folder)\db\MySQL"
$para = ' -hlocalhost -uroot -DBootstrapAdmin < '
$sqlFile = join-path $startPath "Install.sql"
$cmd = $mysql + $para + $sqlFile
@ -25,7 +25,7 @@
cmd.exe /c $cmd
write-host "init mongodb data..." -ForegroundColor Cyan
$initFolder = "$($env:appveyor_build_folder)\scripts\MongoDB"
$initFolder = "$($env:appveyor_build_folder)\db\MongoDB"
cd $initFolder
cmd.exe /c "C:\mongodb\bin\mongo init.js"

View File

@ -27,7 +27,7 @@ install:
dotnet --version
xcopy "$($env:appveyor_build_folder)\scripts\MySQL\my.ini" "C:\Program Files\MySQL\MySQL Server 5.7" /y
xcopy "$($env:appveyor_build_folder)\db\MySQL\my.ini" "C:\Program Files\MySQL\MySQL Server 5.7" /y
build_script:
- ps: >-
.\appveyor.build.ps1

View File

@ -257,5 +257,29 @@
"Name": "卡片标题状态",
"Code": "1",
"Define": NumberInt(0)
},
{
"Category": "网站设置",
"Name": "短信验证码登录",
"Code": "1",
"Define": NumberInt(0)
},
{
"Category": "网站设置",
"Name": "OAuth 认证登录",
"Code": "1",
"Define": NumberInt(0)
},
{
"Category": "网站设置",
"Name": "自动锁屏时长",
"Code": "30",
"Define": NumberInt(0)
},
{
"Category": "网站设置",
"Name": "自动锁屏",
"Code": "0",
"Define": NumberInt(0)
}
];

View File

@ -191,6 +191,30 @@
"IsResource": NumberInt(2),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b06"),
"ParentId": "5bd7b8445fa31256f77e4b93",
"Name": "登录设置",
"Order": NumberInt(60),
"Icon": "fa fa-fa",
"Url": "loginSettings",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(2),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b07"),
"ParentId": "5bd7b8445fa31256f77e4b93",
"Name": "自动锁屏",
"Order": NumberInt(70),
"Icon": "fa fa-fa",
"Url": "lockScreen",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(2),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b94"),
"ParentId": "0",
@ -635,6 +659,18 @@
"IsResource": NumberInt(0),
"Application": "0"
},
{
"_id": ObjectId("5bd9b3d868aa001661776f60"),
"ParentId": "5bd7b8445fa31256f77e4b9c",
"Name": "SQL日志",
"Order": NumberInt(40),
"Icon": "fa fa-database",
"Url": "~/Admin/SQL",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(0),
"Application": "0"
},
{
"_id": ObjectId("5bd7b8445fa31256f77e4b89"),
"ParentId": "0",

View File

@ -33,6 +33,14 @@ INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '前台
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '侧边栏状态', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '卡片标题状态', '1', 0);
-- 登录配置
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '短信验证码登录', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', 'OAuth 认证登录', '1', 0);
-- 自动锁屏(秒)默认 30 秒
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '自动锁屏时长', '30', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '自动锁屏', '0', 0);
-- 时长单位 月
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '程序异常保留时长', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '操作日志保留时长', '12', 0);
@ -67,6 +75,8 @@ INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResourc
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 2, '保存样式', 30, 'fa fa-fa', 'saveTheme', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 3, '清理缓存', 40, 'fa fa-fa', 'clearCache', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 4, '清理全部缓存', 50, 'fa fa-fa', 'clearAllCache', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 5, '登录设置', 60, 'fa fa-fa', 'loginSettings', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 6, '自动锁屏', 70, 'fa fa-fa', 'lockScreen', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '菜单管理', 50, 'fa fa-dashboard', '~/Admin/Menus', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity, '新增', 10, 'fa fa-fa', 'add', '0', 2);
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 1, '编辑', 20, 'fa fa-fa', 'edit', '0', 2);
@ -104,6 +114,7 @@ INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity - 1, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity - 2, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity - 3, 'SQL日志', 40, 'fa fa-database', '~/Admin/SQL', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');

View File

@ -183,3 +183,10 @@ CREATE TABLE Traces(
RequestUrl VARCHAR (500) NOT NULL,
UserAgent VARCHAR (2000) NULL
);
CREATE TABLE DBLogs (
ID INTEGER PRIMARY KEY Auto_increment,
UserName VARCHAR (50) NULL,
`SQL` VARCHAR (2000) NOT NULL,
LogTime DATETIME NOT NULL
);

View File

@ -33,6 +33,14 @@ INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '前台
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '侧边栏状态', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '卡片标题状态', '1', 0);
-- 登录配置
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '短信验证码登录', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', 'OAuth 认证登录', '1', 0);
-- 自动锁屏(秒)默认 30 秒
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '自动锁屏时长', '30', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '自动锁屏', '0', 0);
-- 时长单位 月
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '程序异常保留时长', '1', 0);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '操作日志保留时长', '12', 0);
@ -67,6 +75,9 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 3, '保存样式', 30, 'fa fa-fa', 'saveTheme', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 4, '清理缓存', 40, 'fa fa-fa', 'clearCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 5, '清理全部缓存', 50, 'fa fa-fa', 'clearAllCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 6, '登录设置', 60, 'fa fa-fa', 'loginSettings', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 7, '自动锁屏', 70, 'fa fa-fa', 'lockScreen', '0', 2);
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '菜单管理', 50, 'fa fa-dashboard', '~/Admin/Menus', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 1, '新增', 10, 'fa fa-fa', 'add', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 2, '编辑', 20, 'fa fa-fa', 'edit', '0', 2);
@ -104,6 +115,7 @@ INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 1, 0, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 2, 0, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 3, 0, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 4, 0, 'SQL日志', 40, 'fa fa-database', '~/Admin/SQL', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');

View File

@ -183,3 +183,10 @@ CREATE TABLE Traces(
RequestUrl VARCHAR (500) NOT NULL,
UserAgent VARCHAR (2000) NULL
);
CREATE TABLE DBLogs (
ID SERIAL PRIMARY KEY,
UserName VARCHAR (50) NULL,
SQL VARCHAR (2000) NOT NULL,
LogTime DATE NOT NULL
);

View File

@ -33,6 +33,14 @@ INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '侧边栏状态', '1', 0);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '卡片标题状态', '1', 0);
-- 登录配置
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '短信验证码登录', '1', 0);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', 'OAuth 认证登录', '1', 0);
-- 自动锁屏(秒)默认 30 秒
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '自动锁屏时长', '30', 0);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '自动锁屏', '0', 0);
-- 时长单位 月
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', '程序异常保留时长', '1', 0);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', '操作日志保留时长', '12', 0);
@ -67,6 +75,8 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 2, '保存样式', 30, 'fa fa-fa', 'saveTheme', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 3, '清理缓存', 40, 'fa fa-fa', 'clearCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 4, '清理全部缓存', 50, 'fa fa-fa', 'clearAllCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 5, '登录设置', 60, 'fa fa-fa', 'loginSettings', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 6, '自动锁屏', 70, 'fa fa-fa', 'lockScreen', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '菜单管理', 50, 'fa fa-dashboard', '~/Admin/Menus', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid(), '新增', 10, 'fa fa-fa', 'add', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 1, '编辑', 20, 'fa fa-fa', 'edit', '0', 2);
@ -104,6 +114,7 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid(), '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid() - 1, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid() - 2, '访问日志', 30, 'fa fa-bars', '~/Admin/Traces', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid() - 3, 'SQL日志', 40, 'fa fa-database', '~/Admin/SQL', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '网站分析', 145, 'fa fa-line-chart', '~/Admin/Analyse', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');

View File

@ -183,3 +183,10 @@ CREATE TABLE Traces(
RequestUrl VARCHAR (500) NOT NULL,
UserAgent VARCHAR (2000)
);
CREATE TABLE DBLogs (
ID INTEGER PRIMARY KEY,
UserName VARCHAR (50) COLLATE NOCASE,
SQL VARCHAR NOT NULL,
LogTime DATETIME NOT NULL
);

View File

@ -36,6 +36,14 @@ INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'侧边栏状态', N'1', 0)
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'卡片标题状态', N'1', 0)
-- 登录配置
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'短信验证码登录', N'1', 0)
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'OAuth 认证登录', N'1', 0)
-- 自动锁屏(秒)默认 30 秒
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'自动锁屏时长', N'30', 0)
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'自动锁屏', N'0', 0)
-- 时长单位 月
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'程序异常保留时长', '1', 0)
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'操作日志保留时长', '12', 0)
@ -70,6 +78,8 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 2, N'保存样式', 30, 'fa fa-fa', 'saveTheme', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 3, N'清理缓存', 40, 'fa fa-fa', 'clearCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 4, N'清理全部缓存', 50, 'fa fa-fa', 'clearAllCache', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 5, N'登录设置', 60, 'fa fa-fa', 'loginSettings', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 6, N'自动锁屏', 70, 'fa fa-fa', 'lockScreen', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'菜单管理', 50, N'fa fa-dashboard', N'~/Admin/Menus', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity, N'新增', 10, 'fa fa-fa', 'add', '0', 2);
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 1, N'编辑', 20, 'fa fa-fa', 'edit', '0', 2);
@ -107,6 +117,7 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity, N'操作日志', 10, N'fa fa-edit', N'~/Admin/Logs', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity - 1, N'登录日志', 20, N'fa fa-user-circle-o', N'~/Admin/Logins', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity - 2, N'访问日志', 30, N'fa fa-bars', N'~/Admin/Traces', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity - 3, N'SQL日志', 40, N'fa fa-database', N'~/Admin/SQL', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'在线用户', 140, N'fa fa-users', N'~/Admin/Online', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'网站分析', 145, N'fa fa-line-chart', N'~/Admin/Analyse', N'0')
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'程序异常', 150, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')

View File

@ -578,3 +578,29 @@ GO
SET ANSI_PADDING OFF
GO
/****** Object: Table [dbo].[DBLogs] Script Date: 09/22/2019 22:06:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[DBLogs](
[ID] [int] IDENTITY(1,1) NOT NULL,
[UserName] [varchar](50) NULL,
[SQL] [nvarchar](max) NOT NULL,
[LogTime] [datetime] NOT NULL,
CONSTRAINT [PK_DBLogs] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO

3
publish-admin.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
dotnet publish src\admin\Bootstrap.Admin -c Release

3
publish-client.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
dotnet publish src\client\Bootstrap.Client -c Release

View File

@ -11,12 +11,11 @@
<ItemGroup>
<PackageReference Include="Bootstrap.Security.DataAccess" Version="2.2.21" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="2.2.17" />
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.0.0" />
<PackageReference Include="Longbow.Configuration" Version="2.2.7" />
<PackageReference Include="Longbow.Tasks" Version="2.2.23" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.1.6" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="Sentry.AspNetCore" Version="1.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />

View File

@ -53,6 +53,12 @@ namespace Bootstrap.Admin.Controllers
/// <returns></returns>
public ActionResult Logs() => View(new NavigatorBarModel(this));
/// <summary>
///
/// </summary>
/// <returns></returns>
public ActionResult SQL() => View(new NavigatorBarModel(this));
/// <summary>
///
/// </summary>
@ -89,7 +95,7 @@ namespace Bootstrap.Admin.Controllers
///
/// </summary>
/// <returns></returns>
public ActionResult Settings() => View(new ThemeModel(this));
public ActionResult Settings() => View(new SettingsModel(this));
/// <summary>
///

View File

@ -1,6 +1,6 @@
using Bootstrap.Admin.Query;
using Bootstrap.DataAccess;
using Bootstrap.Security;
using Bootstrap.Security.Authentication;
using Longbow.Web.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

View File

@ -0,0 +1,26 @@
using Bootstrap.Admin.Query;
using Bootstrap.DataAccess;
using Longbow.Web.Mvc;
using Microsoft.AspNetCore.Mvc;
namespace Bootstrap.Admin.Controllers.Api
{
/// <summary>
/// SQL 语句执行日志 webapi
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class SQLController : ControllerBase
{
/// <summary>
/// 获取执行日志数据
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[HttpGet]
public QueryData<DBLog> Get([FromQuery]QuerySQLOption value)
{
return value.RetrieveData();
}
}
}

View File

@ -1,4 +1,5 @@
using Bootstrap.Admin.HealthChecks;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.DependencyInjection
{
@ -17,7 +18,10 @@ namespace Microsoft.Extensions.DependencyInjection
var builder = services.AddHealthChecks();
builder.AddCheck<DBHealthCheck>("db");
builder.AddBootstrapAdminHealthChecks();
builder.AddCheck<GiteeHttpHealthCheck>("Gitee");
var config = services.BuildServiceProvider().GetRequiredService<IConfiguration>();
var checkGitee = config.GetValue("GiteeHealthChecks", false);
if (checkGitee) builder.AddCheck<GiteeHttpHealthCheck>("Gitee");
return services;
}
}

View File

@ -18,6 +18,12 @@ namespace Bootstrap.Admin.Models
IsDemo = DictHelper.RetrieveSystemModel();
ShowCardTitle = DictHelper.RetrieveCardTitleStatus() ? "" : "no-card-header";
ShowSideBar = DictHelper.RetrieveSidebarStatus() ? "" : "collapsed";
AllowMobile = DictHelper.RetrieveMobileLogin();
AllowOAuth = DictHelper.RetrieveOAuthLogin();
ShowMobile = AllowMobile ? "" : "mobile";
ShowOAuth = AllowOAuth ? "" : "oauth";
LockScreenPeriod = DictHelper.RetrieveAutoLockScreenPeriod();
EnableAutoLockScreen = DictHelper.RetrieveAutoLockScreen();
}
/// <summary>
@ -49,5 +55,35 @@ namespace Bootstrap.Admin.Models
/// 是否收缩侧边栏
/// </summary>
public string ShowSideBar { get; protected set; }
/// <summary>
/// 获得 是否允许短信验证码登录
/// </summary>
public bool AllowMobile { get; }
/// <summary>
/// 获得 是否允许第三方 OAuth 认证登录
/// </summary>
public bool AllowOAuth { get; }
/// <summary>
/// 获得 是否允许短信验证码登录
/// </summary>
public string ShowMobile { get; }
/// <summary>
/// 获得 是否允许第三方 OAuth 认证登录
/// </summary>
public string ShowOAuth { get; }
/// <summary>
/// 获得 自动锁屏时长 默认 1 分钟 字典表中配置
/// </summary>
public int LockScreenPeriod { get; }
/// <summary>
/// 获得 自动锁屏功能是否自动开启 默认关闭
/// </summary>
public bool EnableAutoLockScreen { get; }
}
}

View File

@ -8,7 +8,7 @@ namespace Bootstrap.Admin.Models
/// <summary>
///
/// </summary>
public class ProfilesModel : ThemeModel
public class ProfilesModel : SettingsModel
{
/// <summary>
/// 获得 头像文件大小

View File

@ -6,21 +6,28 @@ using System.Collections.Generic;
namespace Bootstrap.Admin.Models
{
/// <summary>
///
/// 网站设置 Model 实体类
/// </summary>
public class ThemeModel : NavigatorBarModel
public class SettingsModel : NavigatorBarModel
{
/// <summary>
///
/// </summary>
/// <param name="controller"></param>
public ThemeModel(ControllerBase controller) : base(controller)
public SettingsModel(ControllerBase controller) : base(controller)
{
Themes = DictHelper.RetrieveThemes();
AutoLockScreen = EnableAutoLockScreen ? "" : "lockScreen";
}
/// <summary>
/// 获得 系统配置的所有样式表
/// </summary>
public IEnumerable<BootstrapDict> Themes { get; }
/// <summary>
/// 获得 是否开启自动锁屏
/// </summary>
public string AutoLockScreen { get; }
}
}

View File

@ -0,0 +1,40 @@
using Bootstrap.DataAccess;
using Longbow.Web.Mvc;
using System;
namespace Bootstrap.Admin.Query
{
/// <summary>
/// SQL执行查询配置类
/// </summary>
public class QuerySQLOption : PaginationOption
{
/// <summary>
/// 获得/设置 用户登录名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 获得/设置 开始时间
/// </summary>
public DateTime? OperateTimeStart { get; set; }
/// <summary>
/// 获得/设置 结束时间
/// </summary>
public DateTime? OperateTimeEnd { get; set; }
/// <summary>
/// 查询数据方法
/// </summary>
/// <returns></returns>
public QueryData<DBLog> RetrieveData()
{
var data = LogHelper.RetrieveDBLogs(this, OperateTimeStart, OperateTimeEnd, UserName);
var ret = new QueryData<DBLog>();
ret.total = data.TotalItems;
ret.rows = data.Items;
return ret;
}
}
}

View File

@ -1,6 +1,7 @@
using Bootstrap.DataAccess;
using Longbow.Web;
using Longbow.Web.SignalR;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@ -60,7 +61,8 @@ namespace Bootstrap.Admin
services.AddSignalR().AddJsonProtocalDefault();
services.AddSignalRExceptionFilterHandler<SignalRHub>((client, ex) => client.SendMessageBody(ex).ConfigureAwait(false));
services.AddResponseCompression();
services.AddBootstrapAdminAuthentication().AddGitee(OAuthHelper.Configure).AddGitHub(OAuthHelper.Configure).AddWeChat(WeChatHelper.Configure);
// 兼容 QQ 浏览器兼容模式
services.AddBootstrapAdminAuthentication(configureCookies: ConfigureCookie).AddGitee(OAuthHelper.Configure).AddGitHub(OAuthHelper.Configure);
services.AddSwagger();
services.AddButtonAuthorization(MenuHelper.AuthorizateButtons);
services.AddBootstrapAdminBackgroundTask();
@ -109,7 +111,8 @@ namespace Bootstrap.Admin
app.UseHttpsRedirection();
app.UseResponseCompression();
app.UseStaticFiles();
app.UseBootstrapAdminAuthentication(RoleHelper.RetrievesByUserName, RoleHelper.RetrievesByUrl, AppHelper.RetrievesByUserName);
app.UseAuthentication();
app.UseBootstrapAdminAuthorization(RoleHelper.RetrievesByUserName, RoleHelper.RetrievesByUrl, AppHelper.RetrievesByUserName);
app.UseBootstrapHealthChecks();
app.UseOnlineUsers(TraceHelper.Filter, TraceHelper.Save);
app.UseCacheManager();
@ -119,12 +122,13 @@ namespace Bootstrap.Admin
routes.MapHub<TaskLogHub>("/TaskLogHub");
});
app.UseSwagger(Configuration["SwaggerPathBase"].TrimEnd('/'));
app.UseMvc(routes =>
app.UseMvcWithDefaultRoute();
}
private void ConfigureCookie(CookieAuthenticationOptions options)
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
var supportQQ = Configuration.GetValue("SupportQQBrowser", false);
if (supportQQ) options.Cookie.SameSite = SameSiteMode.None;
}
}
}

View File

@ -1,9 +1,10 @@
using Longbow.Tasks;
using Bootstrap.DataAccess;
using Longbow.Tasks;
using Microsoft.Extensions.Hosting;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.Extensions.DependencyInjection
{
@ -49,6 +50,9 @@ namespace Microsoft.Extensions.DependencyInjection
// 创建任务并禁用
TaskServicesManager.GetOrAdd("禁用任务", token => Task.Delay(1000)).Status = SchedulerStatus.Disabled;
// 真实任务负责批次写入数据执行脚本到日志中
TaskServicesManager.GetOrAdd<LogHelper.DbLogTask>("SQL日志", TriggerBuilder.Build(Cron.Minutely()));
});
}
}

View File

@ -43,7 +43,7 @@
}
<div class="container">
<input id="imgUrl" type="hidden" value="@Model.ImageLibUrl" />
<form id="login" method="post" class="form-signin" data-demo="True">
<form id="login" method="post" class="form-signin" data-demo="@Model.IsDemo">
<h2 class="form-signin-heading">@Model.Title</h2>
<div class="login-wrap" data-auth="@Model.AuthFailed" data-toggle="LgbValidate" data-valid-button="button[type='submit']">
<div class="alert alert-danger d-none" asp-condition="@Model.AuthFailed">用户名或密码错误!</div>
@ -57,16 +57,6 @@
<input type="text" name="userName" class="form-control" data-toggle="tooltip" placeholder="用户名" maxlength="16" data-required-msg="请输入用户名" value="" autofocus data-valid="true" />
</div>
</div>
<div id="loginMobile" class="form-group d-none">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user"></span>
</div>
</div>
<input type="text" id="txtPhone" class="form-control digits" data-toggle="tooltip" placeholder="手机号码" minlength="11" maxlength="11" data-required-msg="请输入手机号码" value="" data-valid="true" />
</div>
</div>
<div id="loginPwd" class="form-group">
<div class="input-group">
<div class="input-group-prepend">
@ -77,6 +67,17 @@
<input type="password" name="password" class="form-control" value="" data-toggle="tooltip" placeholder="密码" maxlength="16" data-required-msg="请输入密码" data-valid="true" />
</div>
</div>
<div asp-condition="@Model.AllowMobile">
<div id="loginMobile" class="form-group d-none">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user"></span>
</div>
</div>
<input type="text" id="txtPhone" class="form-control digits" data-toggle="tooltip" placeholder="手机号码" minlength="11" maxlength="11" data-required-msg="请输入手机号码" value="" data-valid="true" />
</div>
</div>
<div id="loginSMS" class="form-group d-none">
<div class="input-group">
<div class="input-group-prepend">
@ -90,21 +91,23 @@
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-between">
<div class="form-group rememberPwd" onselectstart="return false">
<i class="fa fa-square-o"></i>
<span>记住密码自动登录</span>
<input id="remember" name="remember" type="hidden" value="false" />
</div>
<div>
<div asp-condition="@Model.AllowMobile">
<a id="loginType" data-value="username" href="#" class="">短信验证登陆</a>
</div>
</div>
<button class="btn btn-lg btn-login btn-block" data-toggle="tooltip" title="不填写密码默认使用 Gitee 认证" type="submit">登 录</button>
<div class="login-footer">
<button class="btn btn-lg btn-login btn-block" data-oauth="@Model.AllowOAuth" data-toggle="tooltip" title="不填写密码默认使用 Gitee 认证" type="submit">登 录</button>
<div class="d-flex justify-content-between">
<a href="#" data-method="register">申请账号</a>
<a href="#" data-method="forgot">忘记密码</a>
</div>
<div asp-condition="@Model.AllowOAuth">
<div class="login-other">
<span class="text-muted">
其他方式登录
@ -122,8 +125,8 @@
</a>
</div>
<div class="item">
<a href="~/Account/WeChat" data-toggle="tooltip" title="使用微信帐号登录">
<img class="item" src="~/images/weixin.svg" />
<a href="#" data-toggle="tooltip" title="微信-暂未实现">
<img class="item" src="~/images/weixin-2.svg" />
</a>
</div>
<div class="item">
@ -137,7 +140,8 @@
</a>
</div>
</div>
<div class="slidercaptcha card">
</div>
<div class="slidercaptcha card @Model.ShowOAuth">
<div class="card-header">
<span>请完成安全验证</span>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>

View File

@ -112,7 +112,7 @@
</div>
</div>
<div class="form-group col-sm-6">
<input type="text" class="form-control d-none" id="parentId" data-default-val="0" />
<input type="hidden" class="form-control" id="parentId" data-default-val="0" />
<label class="control-label" for="parentName">父级菜单</label>
<div class="input-group flex-sm-fill">
<input type="text" class="form-control" readonly id="parentName" name="parentName" placeholder="请选择...(可为空)50字以内" maxlength="50" />

View File

@ -0,0 +1,80 @@
@model NavigatorBarModel
@{
ViewBag.Title = "SQL日志";
}
@section css {
<environment include="Development">
<link href="~/lib/datetimepicker/css//bootstrap-datetimepicker.css" rel="stylesheet" />
<link href="~/lib/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link href="~/lib/datetimepicker/css//bootstrap-datetimepicker.min.css" rel="stylesheet" />
<link href="~/lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
</environment>
}
@section javascript {
<environment include="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.js"></script>
<script src="~/lib/bootstrap-table/extensions/export/bootstrap-table-export.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
<script src="~/lib/tablexport/tableExport.js"></script>
<script src="~/lib/datetimepicker/js/bootstrap-datetimepicker.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.min.js"></script>
<script src="~/lib/bootstrap-table/extensions/export/bootstrap-table-export.min.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="~/lib/tablexport/tableExport.min.js"></script>
<script src="~/lib/datetimepicker/js/bootstrap-datetimepicker.min.js"></script>
</environment>
<script src="~/lib/datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js"></script>
<script src="~/js/sql.js" asp-append-version="true"></script>
}
<div class="card">
<div class="card-header">查询条件</div>
<div class="card-body">
<form class="form-inline">
<div class="row">
<div class="form-group col-sm-6 col-lg-auto">
<label class="control-label" for="txt_operate_start">起始时间</label>
<div class="input-group date">
<input id="txt_operate_start" class="form-control" size="16" type="text" value="@DateTime.Today.ToString("yyyy-MM-dd")" readonly>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-times"></span></div>
</div>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-calendar"></span></div>
</div>
</div>
</div>
<div class="form-group col-sm-6 col-lg-auto">
<label class="control-label" for="txt_operate_end">终止时间</label>
<div class="input-group date">
<input id="txt_operate_end" class="form-control" size="16" type="text" value="" readonly>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-times"></span></div>
</div>
<div class="input-group-append input-group-addon">
<div class="input-group-text"><span class="fa fa-calendar"></span></div>
</div>
</div>
</div>
<div class="form-group col-sm-6 col-lg-auto">
<label class="control-label" for="txt_username">登录用户</label>
<input type="text" class="form-control" id="txt_username" />
</div>
<div class="form-group col-sm-6 col-lg-auto flex-sm-fill justify-content-sm-end align-self-sm-end">
<button type="button" id="btn_query" class="btn btn-primary btn-fill"><i class="fa fa-search" aria-hidden="true"></i><span>查询</span></button>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
查询结果
</div>
<div class="card-body">
<table></table>
</div>
</div>

View File

@ -1,4 +1,4 @@
@model ThemeModel
@model SettingsModel
@{
ViewBag.Title = "网站设置";
}
@ -95,8 +95,48 @@
</div>
</div>
</div>
<div class="modal-footer">
<button id="btnSaveCss" data-method="UISettings" class="btn btn-secondary" type="button"><i class="fa fa-save"></i><span>保存</span></button>
<div class="modal-footer text-right">
<button data-method="UISettings" class="btn btn-secondary" type="button"><i class="fa fa-save"></i><span>保存</span></button>
</div>
</div>
</div>
<div class="card" asp-auth="loginSettings">
<div class="card-header">登录设置</div>
<div class="card-body">
<div class="form-inline">
<div class="row">
<div class="form-group col-6">
<label class="control-label" for="mobile">手机登录</label>
<input id="mobile" hidden type="checkbox" data-default-val="@Model.ShowMobile" data-toggle="toggle" data-width="120" data-onstyle="success" data-on="允许" data-off="关闭" />
</div>
<div class="form-group col-6">
<label class="control-label" for="cardTitle">OAuth 认证</label>
<input id="oauth" hidden type="checkbox" data-default-val="@Model.ShowOAuth" data-toggle="toggle" data-width="120" data-onstyle="success" data-on="允许" data-off="关闭" />
</div>
</div>
</div>
<div class="modal-footer text-right">
<button data-method="loginSettings" class="btn btn-secondary" type="button"><i class="fa fa-save"></i><span>保存</span></button>
</div>
</div>
</div>
<div class="card" asp-auth="lockScreen">
<div class="card-header">自动锁屏设置</div>
<div class="card-body">
<div class="form-inline">
<div class="row">
<div class="form-group col-6">
<label class="control-label" for="lockScreen">自动锁屏</label>
<input id="lockScreen" hidden type="checkbox" data-default-val="@Model.AutoLockScreen" data-toggle="toggle" data-width="120" data-onstyle="success" data-on="开启" data-off="关闭" />
</div>
<div class="form-group col-6">
<label class="control-label" for="lockPeriod">时长间隔(秒)</label>
<input id="lockPeriod" type="number" class="form-control" min="30" value="@Model.LockScreenPeriod" />
</div>
</div>
</div>
<div class="modal-footer text-right">
<button data-method="saveAutoLock" class="btn btn-secondary" type="button"><i class="fa fa-save"></i><span>保存</span></button>
</div>
</div>
</div>

View File

@ -37,6 +37,7 @@
}
@await Html.PartialAsync("Navigator")
<section id="main-content" class="main-content @Model.ShowCardTitle">
<input id="lockScreenPeriod" type="hidden" asp-condition="@Model.EnableAutoLockScreen" value="@Model.LockScreenPeriod" />
<div class="main-header">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="~/Admin/Index"><i class="fa fa-home"></i>首页</a></li>

View File

@ -66,8 +66,13 @@
"ClientSecret": "3427f2d901ba9afc76c1842a7303b2d67f8e098e71acc15051f89fe6f3d265db",
"CallbackPath": "/signin-gitee",
"HomePath": "/Admin/Profiles",
"Scope": [ "user_info", "projects" ],
"Roles": [ "Administrators" ],
"Scope": [
"user_info",
"projects"
],
"Roles": [
"Administrators"
],
"App": "0",
"StarredUrl": "https://gitee.com/api/v5/user/starred/LongbowEnterprise/BootstrapAdmin"
},
@ -77,28 +82,49 @@
"ClientSecret": "ffa759ca599df941b869efecb5e750bc1b27334e",
"CallbackPath": "/signin-github",
"HomePath": "/Admin/Profiles",
"Scope": [ "user_info", "repo" ],
"Roles": [ "Administrators" ],
"Scope": [
"user_info",
"repo"
],
"Roles": [
"Administrators"
],
"App": "0",
"StarredUrl": "https://api.github.com/user/starred/ArgoZhang/BootstrapAdmin"
},
"WeChatOptions": {
"Enabled": true,
"ClientId": "wxe2944ebb9e66551c",
"ClientSecret": "a4e36ddb18af218818e44bb7b8744fe6",
"ClientId": "<AppId>",
"ClientSecret": "<secret>",
"CallbackPath": "/signin-weixin",
"HomePath": "/Admin/Profiles",
"Scope": [ "snsapi_login" ],
"Roles": [ "Administrators" ],
"Scope": [
"snsapi_login"
],
"Roles": [
"Administrators"
],
"App": "0"
},
"SMSOptions": {
"CompanyCode": "<CompanyCode>",
"MD5Key": "MD5Key",
"Roles": [ "Administrators" ],
"Roles": [
"Administrators"
],
"HomePath": "/Admin/Profiles",
"App": "0"
},
"AppMenus": [
"首页",
"测试页面",
"关于",
"返回码云",
"多级菜单",
"第二层",
"第三层",
"第四层"
],
"LongbowCache": {
"Enabled": true,
"CorsItems": [

View File

@ -15,6 +15,7 @@
"ConnectionStrings": {
"ba": "Data Source=.;Initial Catalog=BootstrapAdmin;User ID=sa;Password=sa"
},
"SupportQQBrowser": false,
"DB": [
{
"Enabled": false,
@ -55,6 +56,7 @@
],
"SwaggerPathBase": "",
"AllowOrigins": "http://localhost,http://ba.sdgxgz.cn",
"GiteeHealthChecks": false,
"Sentry": {
"Dsn": "https://70bdfff562e84fa7b9a43d65924ab9ad@sentry.io/1469396"
},

View File

@ -134,3 +134,10 @@ div.input-group .input-group-text {
.form-group:last-child input {
width: 80px;
}
@media (min-width: 576px) {
.form-inline .form-group {
flex: 0 1 auto;
margin-bottom: 1rem;
}
}

View File

@ -30,39 +30,22 @@
}
.login-wrap {
padding: 0;
margin: 18px 0 0 370px;
width: 280px;
width: 300px;
height: 274px;
position: relative;
left: 346px;
justify-content: center;
}
.slidercaptcha {
top: -278px;
left: -15px;
width: 300px;
}
.slidercaptcha, .slidercaptcha.oauth {
height: 280px;
}
.slidercaptcha.card .card-body {
padding: 15px 15px 0 15px;
}
.slidercaptcha, .slidercaptcha.forgot {
width: 310px;
height: 280px;
}
.login-wrap[data-auth="True"] {
margin: 20px 0 0 370px;
}
.login-wrap[data-auth="True"] .slidercaptcha {
top: -264px;
}
.login-wrap[data-auth="True"] .slidercaptcha, .slidercaptcha.forgot {
width: 310px;
height: 280px;
}
.login-wrap[data-auth="True"] .form-group {
margin-bottom: 0.75rem;
}
}

View File

@ -13,8 +13,9 @@
}
.login-wrap {
padding: 20px;
height: 300px;
display: flex;
flex-direction: column;
margin: 1rem;
}
.login-wrap .rememberPwd {
@ -27,14 +28,10 @@
width: 13px;
}
.login-wrap .card {
border-top-width: 1px;
.login-wrap .card, .login-wrap .card:hover, .modal .card, .modal .card:hover {
border: 1px solid #84bbe2;
}
.login-footer a:last-child {
float: right;
}
.btn-login {
background: #f67a6e;
color: #fff;
@ -42,7 +39,7 @@
font-weight: 300;
font-family: 'Open Sans', sans-serif;
box-shadow: 0 4px #e56b60;
margin-bottom: 0.625rem;
margin-bottom: 0.75rem;
outline: none !important;
margin-top: -0.25rem;
line-height: 1;
@ -66,11 +63,10 @@
background-color: #00adec;
border-radius: 4px;
box-shadow: 0 0 10px #fff;
left: 0;
right: 0;
top: -270px;
height: 226px;
z-index: 1080
height: 274px;
width: 286px;
z-index: 1080;
position: absolute;
}
.slidercaptcha canvas:first-child {
@ -83,8 +79,12 @@
margin-top: -2px;
}
.slidercaptcha.oauth {
height: 210px;
}
.slidercaptcha.card .card-body {
padding: 0.625rem 0 0 0;
padding: 0.75rem 0 0 0;
}
.slidercaptcha.card .card-header {
@ -97,18 +97,8 @@
color: #fff;
}
.slidercaptcha.forgot {
position: absolute;
left: auto;
right: 14px;
bottom: 14px;
top: auto;
margin: 0;
width: 274px;
}
.slidercaptcha.reg {
bottom: 60px;
.slidercaptcha.forgot, .slidercaptcha.reg {
bottom: 52px;
}
.login-other {

View File

@ -293,7 +293,7 @@ footer {
}
aside .sidebar, .sidebar-open aside:hover .sidebar {
top: 136px;
top: 121px;
transition: top .3s linear;
}
@ -315,8 +315,8 @@ footer {
}
aside .nav-header img, .sidebar-open aside:hover .nav-header img {
width: 3.75rem;
height: 3.75rem;
width: 2.8125rem;
height: 2.8125rem;
border-radius: 50%;
}

View File

@ -167,6 +167,32 @@
})(jQuery);
$(function () {
// 自动锁屏功能
var mousePosition = { screenX: 0, screenY: 0 };
var count = 1;
var lockScreenPeriod = parseInt($('#lockScreenPeriod').val());
if (typeof lockScreenPeriod === 'number' && !isNaN(lockScreenPeriod)) {
var traceMouseOrKey = window.setInterval(function () {
$(document).off('mousemove').one('mousemove', function (e) {
if (mousePosition.screenX !== e.screenX || mousePosition.screenY !== e.screenY) {
mousePosition.screenX = e.screenX;
mousePosition.screenY = e.screenY;
// 计数器归零
count = 1;
return;
}
});
}, 2000);
var lockHandler = window.setInterval(function () {
if (count++ * 5 > lockScreenPeriod) {
window.clearInterval(lockHandler);
window.clearInterval(traceMouseOrKey);
this.location.href = $.formatUrl("Account/Lock");
}
}, 5000);
}
var $sideMenu = $(".sidebar ul");
// breadcrumb

View File

@ -57,6 +57,12 @@
},
'button[data-method="css"]': function () {
this.log({ crud: '设置网站样式' });
},
'button[data-method="UISettings"]': function () {
this.log({ crud: '保存网站设置' });
},
'button[data-method="LoginSettings"]': function () {
this.log({ crud: '保存登录设置' });
}
}
};

View File

@ -1,5 +1,6 @@
$(function () {
var $imgUrl = $('#imgUrl');
$('[data-oauth="False"]').attr("data-original-title", "点击登录系统");
$(".container").autoCenter();
$("a[data-method]").on('click', function () {
@ -20,16 +21,20 @@
url: "api/OnlineUsers",
method: "put",
callback: function (result) {
// 返回真时表示三次验证需要滑块验证码
if (result) captcha.addClass('d-block');
else success();
}
});
},
capWidth: function () {
return $(window).width() < 768 ? 256 : 280;
return $(window).width() < 768 ? 256 : 272;
},
capHeight: function () {
return $(window).width() < 768 ? 106 : 150;
// 如果关闭 oAuth 认证 高度要缩小
var height = 150;
if ($(window).width() < 768) height = $('.slidercaptcha:first').hasClass('oauth') ? 96 : 150;
return height;
},
capRegSuccess: function () {
$.bc({
@ -126,10 +131,10 @@
var $loginPwd = $('#loginPwd');
var $loginSMS = $('#loginSMS');
if ($login.attr('data-demo') === 'True') {
$login.find('[name="userName"], [name="password"]').attr('data-valid', 'false');
$login.on('submit', function (e) {
var model = $loginType.attr('data-value');
if (model === 'username') {
$login.find('[data-valid="true"]').attr('data-valid', 'false');
if ($username.val() === '' && $password.val() === '') {
e.preventDefault();
location.href = "Gitee";

View File

@ -163,6 +163,12 @@ $(function () {
}
});
// clear parentID value
// bug https://gitee.com/LongbowEnterprise/dashboard/issues?id=I12E3S
$parentMenuName.next().find('button[data-method="clear"]').on('click', function () {
$parentMenuID.val('');
});
$btnPickIcon.on('click', function () {
$dialogNew.find('[data-toggle="LgbValidate"] [aria-describedby]').tooltip('hide');
$dialogNew.hide();

View File

@ -145,6 +145,14 @@ $(function () {
if (child.hasClass('dd-list')) {
child.find(':checkbox').prop('checked', val);
}
// 子节点全部取消时父级菜单也取消
$(this).parents('ol.dd-list').each(function (index, p) {
if (val === false) {
val = $(p).prev().next().find(':checked').length > 0;
}
$(p).prev().find(':checkbox').prop('checked', val);
});
}).children('.radio').hide();
});
});

View File

@ -52,6 +52,30 @@ $(function () {
}
});
break;
case 'loginSettings':
var mobile = $('#mobile').prop('checked') ? "1" : "0";
$.bc({
url: Settings.url, data: { name: '短信验证码登录', code: mobile, category: '网站设置' }, method: "post"
});
var oauth = $('#oauth').prop('checked') ? "1" : "0";
$.bc({
url: Settings.url, data: { name: 'OAuth 认证登录', code: oauth, category: '网站设置' }, title: '登录设置', method: "post"
});
break;
case 'saveAutoLock':
var autoLock = $('#lockScreen').prop('checked') ? "1" : "0";
$.bc({
url: Settings.url, data: { name: '自动锁屏', code: autoLock, category: '网站设置' }, method: "post"
});
$.bc({
url: Settings.url, data: { name: '自动锁屏时长', code: $('#lockPeriod').val(), category: '网站设置' }, title: '保存自动锁屏设置', method: "post",
callback: function (result) {
if (result) {
window.setTimeout(function () { window.location.reload(true); }, 1000);
}
}
});
break;
}
});

View File

@ -0,0 +1,18 @@
$(function () {
var url = 'api/SQL';
$('.card-body table').smartTable({
url: url,
sortName: 'LogTime',
sortOrder: 'desc',
queryParams: function (params) { return $.extend(params, { UserName: $("#txt_username").val(), OperateTimeStart: $("#txt_operate_start").val(), OperateTimeEnd: $("#txt_operate_end").val() }); },
columns: [
{ title: "所属用户", field: "UserName", sortable: true },
{ title: "执行时间", field: "LogTime", sortable: true },
{ title: "脚本内容", field: "SQL", sortable: false }
],
exportOptions: {
fileName: "SQL日志数据"
}
});
});

View File

@ -240,7 +240,6 @@
};
var handleDragMove = function (e) {
e.preventDefault();
if (!isMouseDown) return false;
var eventX = e.clientX || e.touches[0].clientX;
var eventY = e.clientY || e.touches[0].clientY;

View File

@ -2,6 +2,8 @@
font-weight: 500;
cursor: pointer;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
user-select: none;
white-space: nowrap;
margin: 0;

View File

@ -0,0 +1,15 @@
namespace Bootstrap.DataAccess.MongoDB
{
/// <summary>
/// DBLog 实体类
/// </summary>
public class DBLog : DataAccess.DBLog
{
/// <summary>
/// 保存数据库脚本日志方法 MongoDB 无脚本
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public override bool Save(DataAccess.DBLog p) => true;
}
}

View File

@ -8,12 +8,12 @@ using System.Linq;
namespace Bootstrap.DataAccess.MongoDB
{
/// <summary>
///
/// 操作日志实体类
/// </summary>
public class Log : DataAccess.Log
{
/// <summary>
///
/// 分页查询操作日志
/// </summary>
/// <param name="po"></param>
/// <param name="startTime"></param>
@ -64,7 +64,7 @@ namespace Bootstrap.DataAccess.MongoDB
}
/// <summary>
///
/// 查询所有操作日志
/// </summary>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
@ -89,7 +89,7 @@ namespace Bootstrap.DataAccess.MongoDB
private static void DeleteLogAsync() => System.Threading.Tasks.Task.Run(() => DbManager.Logs.DeleteMany(log => log.LogTime < DateTime.Now.AddDays(-7)));
/// <summary>
///
/// 保存操作日志
/// </summary>
/// <param name="log"></param>
/// <returns></returns>

View File

@ -10,9 +10,11 @@
<PackageReference Include="Longbow.Data" Version="2.3.8" />
<PackageReference Include="Longbow.GiteeAuth" Version="2.2.0" />
<PackageReference Include="Longbow.GitHubAuth" Version="2.2.0" />
<PackageReference Include="Longbow.OAuth" Version="2.2.2" />
<PackageReference Include="Longbow.Logging" Version="2.2.13" />
<PackageReference Include="Longbow.PetaPoco" Version="1.0.2" />
<PackageReference Include="Longbow.Security.Cryptography" Version="1.3.0" />
<PackageReference Include="Longbow.Tasks" Version="2.2.23" />
<PackageReference Include="Longbow.Web" Version="2.2.16" />
<PackageReference Include="Longbow.WeChatAuth" Version="2.2.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="2.2.6" />

View File

@ -0,0 +1,79 @@
using Longbow.Web.Mvc;
using PetaPoco;
using System;
namespace Bootstrap.DataAccess
{
/// <summary>
/// 后台数据库脚本执行日志实体类
/// </summary>
[TableName("DBLogs")]
public class DBLog
{
/// <summary>
/// 获得/设置 主键ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 获得/设置 当前登陆名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 获得/设置 数据库执行脚本
/// </summary>
public string SQL { get; set; }
/// <summary>
/// 获取/设置 用户角色关联状态 checked 标示已经关联 '' 标示未关联
/// </summary>
public DateTime LogTime { get; set; }
/// <summary>
/// 查询所有SQL日志信息
/// </summary>
/// <param name="po"></param>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="userName"></param>
/// <returns></returns>
public virtual Page<DBLog> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string userName)
{
var sql = new Sql("select * from DBLogs");
if (startTime.HasValue) sql.Where("LogTime >= @0", startTime.Value);
if (endTime.HasValue) sql.Where("LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
if (startTime == null && endTime == null) sql.Where("LogTime > @0", DateTime.Today.AddMonths(0 - DictHelper.RetrieveExceptionsLogPeriod()));
if (!string.IsNullOrEmpty(userName)) sql.Where("UserName = @0", userName);
sql.OrderBy($"{po.Sort} {po.Order}");
return DbManager.Create().Page<DBLog>(po.PageIndex, po.Limit, sql);
}
/// <summary>
/// 删除日志信息
/// </summary>
/// <returns></returns>
private static void DeleteLogAsync()
{
System.Threading.Tasks.Task.Run(() =>
{
var dtm = DateTime.Now.AddMonths(0 - DictHelper.RetrieveLogsPeriod());
DbManager.Create().Execute("delete from DBLogs where LogTime < @0", dtm);
});
}
/// <summary>
/// 保存新增的日志信息
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public virtual bool Save(DBLog p)
{
if (p == null) throw new ArgumentNullException(nameof(p));
DeleteLogAsync();
DbManager.Create(enableLog: false).Save(p);
return true;
}
}
}

View File

@ -1,4 +1,8 @@
using PetaPoco;
using Longbow.Data;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PetaPoco;
using System;
using System.Collections.Specialized;
@ -14,12 +18,28 @@ namespace Bootstrap.DataAccess
/// </summary>
/// <param name="connectionName"></param>
/// <param name="keepAlive"></param>
/// <param name="log">是否记录日志</param>
/// <returns></returns>
public static IDatabase Create(string connectionName = null, bool keepAlive = false)
public static IDatabase Create(string connectionName = null, bool keepAlive = false, bool enableLog = true)
{
if (Mappers.GetMapper(typeof(Exceptions), null) == null) Mappers.Register(typeof(Exceptions).Assembly, new BootstrapDataAccessConventionMapper());
var db = Longbow.Data.DbManager.Create(connectionName, keepAlive);
db.ExceptionThrown += (sender, args) => args.Exception.Log(new NameValueCollection() { ["LastCmd"] = db.LastCommand });
if (enableLog)
{
db.OnCommandExecuted(async provider =>
{
var context = provider.GetRequiredService<IHttpContextAccessor>();
var userName = context.HttpContext?.User.Identity.Name;
var log = new DBLog()
{
LogTime = DateTime.Now,
SQL = db.LastCommand,
UserName = userName
};
await LogHelper.AddDBLog(log).ConfigureAwait(false);
});
}
return db;
}
}

View File

@ -9,7 +9,7 @@ using System.Linq;
namespace Bootstrap.DataAccess
{
/// <summary>
///
/// 字典表实体类
/// </summary>
[TableName("Dicts")]
public class Dict : BootstrapDict
@ -210,5 +210,29 @@ namespace Bootstrap.DataAccess
/// </summary>
/// <returns></returns>
public bool RetrieveSidebarStatus() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "侧边栏状态" && d.Define == 0)?.Code ?? "1") == "1";
/// <summary>
/// 获得是否允许短信验证码登录
/// </summary>
/// <returns></returns>
public bool RetrieveMobileLogin() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "短信验证码登录" && d.Define == 0)?.Code ?? "1") == "1";
/// <summary>
/// 获得是否允许 OAuth 认证登录
/// </summary>
/// <returns></returns>
public bool RetrieveOAuthLogin() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "OAuth 认证登录" && d.Define == 0)?.Code ?? "1") == "1";
/// <summary>
/// 获得自动锁屏时长 默认 30 秒
/// </summary>
/// <returns></returns>
public int RetrieveAutoLockScreenPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "自动锁屏时长" && d.Define == 0)?.Code, 30);
/// <summary>
/// 获得自动锁屏是否开启 默认关闭
/// </summary>
/// <returns></returns>
public bool RetrieveAutoLockScreen() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "自动锁屏" && d.Define == 0)?.Code ?? "0") == "1";
}
}

View File

@ -203,12 +203,36 @@ namespace Bootstrap.DataAccess
/// 获得数据区卡片标题是否显示
/// </summary>
/// <returns></returns>
public static bool RetrieveCardTitleStatus() => DbContextManager.Create<Dict>()?.RetrieveCardTitleStatus() ?? true;
public static bool RetrieveCardTitleStatus() => DbContextManager.Create<Dict>().RetrieveCardTitleStatus();
/// <summary>
/// 获得侧边栏状态 未真时显示
/// </summary>
/// <returns></returns>
public static bool RetrieveSidebarStatus() => DbContextManager.Create<Dict>()?.RetrieveSidebarStatus() ?? true;
public static bool RetrieveSidebarStatus() => DbContextManager.Create<Dict>().RetrieveSidebarStatus();
/// <summary>
/// 获得是否允许短信验证码登录
/// </summary>
/// <returns></returns>
public static bool RetrieveMobileLogin() => DbContextManager.Create<Dict>()?.RetrieveMobileLogin() ?? false;
/// <summary>
/// 获得是否允许 OAuth 认证登录
/// </summary>
/// <returns></returns>
public static bool RetrieveOAuthLogin() => DbContextManager.Create<Dict>()?.RetrieveOAuthLogin() ?? false;
/// <summary>
/// 获得自动锁屏时长 默认 30 秒
/// </summary>
/// <returns></returns>
public static int RetrieveAutoLockScreenPeriod() => DbContextManager.Create<Dict>()?.RetrieveAutoLockScreenPeriod() ?? 30;
/// <summary>
/// 获得自动锁屏 默认关闭
/// </summary>
/// <returns></returns>
public static bool RetrieveAutoLockScreen() => DbContextManager.Create<Dict>()?.RetrieveAutoLockScreen() ?? false;
}
}

View File

@ -1,12 +1,15 @@
using Longbow.Web.Mvc;
using Longbow.Tasks;
using Longbow.Web.Mvc;
using PetaPoco;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace Bootstrap.DataAccess
{
/// <summary>
///
/// 操作日志相关操作类
/// </summary>
public static class LogHelper
{
@ -36,5 +39,55 @@ namespace Bootstrap.DataAccess
log.LogTime = DateTime.Now;
return DbContextManager.Create<Log>().Save(log);
}
#region
private static BlockingCollection<DBLog> _messageQueue = new BlockingCollection<DBLog>(new ConcurrentQueue<DBLog>());
/// <summary>
/// 添加数据库日志实体类到内部集合中
/// </summary>
/// <param name="log"></param>
public static System.Threading.Tasks.Task AddDBLog(DBLog log) => System.Threading.Tasks.Task.Run(() =>
{
if (!_messageQueue.IsAddingCompleted)
{
_messageQueue.Add(log);
}
});
/// <summary>
/// 查询所有SQL日志信息
/// </summary>
/// <param name="op"></param>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="userName"></param>
/// <returns></returns>
public static Page<DBLog> RetrieveDBLogs(PaginationOption op, DateTime? startTime, DateTime? endTime, string userName) => DbContextManager.Create<DBLog>().RetrievePages(op, startTime, endTime, userName);
/// <summary>
/// 数据库脚本执行日志任务实体类
/// </summary>
public class DbLogTask : ITask
{
/// <summary>
/// 任务执行方法
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public System.Threading.Tasks.Task Execute(CancellationToken cancellationToken)
{
var logs = new List<DBLog>();
while (_messageQueue.TryTake(out var log))
{
logs.Add(log);
};
using (var db = DbManager.Create(enableLog: false))
{
db.InsertBatch(logs);
}
return System.Threading.Tasks.Task.CompletedTask;
}
}
#endregion
}
}

View File

@ -1,6 +1,8 @@
using Bootstrap.Security;
using Bootstrap.Security.DataAccess;
using Longbow.Cache;
using Longbow.Configuration;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Linq;
@ -29,7 +31,24 @@ namespace Bootstrap.DataAccess
public static bool Save(BootstrapMenu p)
{
// 不允许保存系统菜单与前台演示系统的默认菜单
if (DictHelper.RetrieveSystemModel() && (p.Category == "0" || p.Application == "2")) return true;
if (DictHelper.RetrieveSystemModel())
{
if (p.Category == "0") return true;
// 查找原有数据比对是否为系统菜单与演示菜单
if (!string.IsNullOrEmpty(p.Id))
{
// 系统菜单
var menus = RetrieveAllMenus("Admin");
var menu = menus.FirstOrDefault(m => m.Id.Equals(p.Id, System.StringComparison.OrdinalIgnoreCase));
if (menu != null && menu.Category == "0") return true;
// 演示系统
var appMenus = ConfigurationManager.GetSection("AppMenus").Get<ICollection<string>>();
if (appMenus.Any(m => m.Equals(menu.Name, System.StringComparison.OrdinalIgnoreCase))) return true;
}
}
var ret = DbContextManager.Create<Menu>().Save(p);
if (ret) CacheCleanUtility.ClearCache(menuIds: string.IsNullOrEmpty(p.Id) ? new List<string>() : new List<string>() { p.Id });
@ -46,9 +65,15 @@ namespace Bootstrap.DataAccess
if (DictHelper.RetrieveSystemModel())
{
// 不允许删除系统菜单与前台演示系统的默认菜单
var systemMenus = RetrieveAllMenus("Admin").Where(m => m.Category == "0" || m.Application == "2");
var systemMenus = RetrieveAllMenus("Admin").Where(m => m.Category == "0");
value = value.Where(v => !systemMenus.Any(m => m.Id == v));
if (!value.Any()) return true;
// 演示系统
var appMenus = ConfigurationManager.GetSection("AppMenus").Get<ICollection<string>>();
var appIds = RetrieveAllMenus("Admin").Where(m => appMenus.Any(app => m.Name.Equals(app, System.StringComparison.OrdinalIgnoreCase))).Select(m => m.Id);
value = value.Where(m => !appIds.Any(app => app.Equals(m, System.StringComparison.OrdinalIgnoreCase)));
if (!value.Any()) return true;
}
var ret = DbContextManager.Create<Menu>().Delete(value);
if (ret) CacheCleanUtility.ClearCache(menuIds: value);

View File

@ -8,7 +8,7 @@
<PackageReference Include="Bootstrap.Security.DataAccess" Version="2.2.21" />
<PackageReference Include="Longbow.Cache" Version="2.2.15" />
<PackageReference Include="Longbow.Configuration" Version="2.2.7" />
<PackageReference Include="Longbow.Data" Version="2.3.7" />
<PackageReference Include="Longbow.Data" Version="2.3.8" />
<PackageReference Include="Longbow.Logging" Version="2.2.13" />
<PackageReference Include="Longbow.Web" Version="2.2.16" />
</ItemGroup>

3
watch-run-admin.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
dotnet watch --project ./src/admin/Bootstrap.Admin run

View File

@ -1 +1,3 @@
#! /bin/bash
dotnet watch --project ./src/admin/Bootstrap.Admin run

3
watch-run-client.cmd Normal file
View File

@ -0,0 +1,3 @@
@echo off
dotnet watch --project ./src/client/Bootstrap.Client run

View File

@ -1 +1,3 @@
#! /bin/bash
dotnet watch --project ./src/client/Bootstrap.Client run