!77 增加功能:网站设置增加登录界面切换功能

Merge pull request !77 from Argo/dev-login
This commit is contained in:
Argo 2020-03-13 23:19:33 +08:00 committed by Gitee
commit a9ae7ed140
19 changed files with 790 additions and 5 deletions

View File

@ -360,4 +360,22 @@
"Code": "/favicon.png",
"Define": NumberInt(1)
}
{
"Category": "系统首页",
"Name": "高仿码云",
"Code": "Login-Gitee",
"Define": NumberInt(0)
},
{
"Category": "系统首页",
"Name": "系统默认",
"Code": "Login",
"Define": NumberInt(0)
},
{
"Category": "网站设置",
"Name": "登录界面",
"Code": "Login",
"Define": NumberInt(0)
}
];

View File

@ -77,6 +77,12 @@ INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '默认
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '后台地址', 'http://localhost:50852', 0);
-- 系统登录首页设置
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统首页', '高仿码云', 'Login-Gitee', 1);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统首页', '系统默认', 'Login', 1);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('网站设置', '登录界面', 'Login', 1);
DELETE FROM Navigations Where Category = '0';
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0');
INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '个人中心', 20, 'fa fa-suitcase', '~/Admin/Profiles', '0');

View File

@ -76,6 +76,12 @@ INSERT INTO Dicts (Id, Category, Name, Code, Define) Values (SEQ_DICTS_ID.NEXTVA
INSERT INTO Dicts (Id, Category, Name, Code, Define) Values (SEQ_DICTS_ID.NEXTVAL, '网站设置', '默认应用程序', '0', 0);
INSERT INTO Dicts (Id, Category, Name, Code, Define) Values (SEQ_DICTS_ID.NEXTVAL, '网站设置', '后台地址', 'http://localhost:50852', 0);
-- 系统登录首页设置
INSERT INTO Dicts (Id, Category, Name, Code, Define) VALUES (SEQ_DICTS_ID.NEXTVAL, '系统首页', '高仿码云', 'Login-Gitee', 1);
INSERT INTO Dicts (Id, Category, Name, Code, Define) VALUES (SEQ_DICTS_ID.NEXTVAL, '系统首页', '系统默认', 'Login', 1);
INSERT INTO Dicts (Id, Category, Name, Code, Define) VALUES (SEQ_DICTS_ID.NEXTVAL, '网站设置', '登录界面', 'Login', 1);
DELETE FROM Navigations Where Category = '0';
INSERT INTO Navigations (Id, ParentId, Name, "ORDER", Icon, Url, Category) Values (SEQ_NAVIGATIONS_ID.NEXTVAL, 0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0');
INSERT INTO Navigations (Id, ParentId, Name, "ORDER", Icon, Url, Category) Values (SEQ_NAVIGATIONS_ID.NEXTVAL, 0, '个人中心', 20, 'fa fa-suitcase', '~/Admin/Profiles', '0');

View File

@ -81,6 +81,12 @@ INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '后台地址', 'http://localhost:50852', 0);
-- 系统登录首页设置
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统首页', '高仿码云', 'Login-Gitee', 1);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统首页', '系统默认', 'Login', 1);
INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('网站设置', '登录界面', 'Login', 1);
DELETE FROM Navigations Where Category = '0';
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0');
INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '个人中心', 20, 'fa fa-suitcase', '~/Admin/Profiles', '0');

View File

@ -81,6 +81,12 @@ INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设
INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'网站设置', N'后台地址', 'http://localhost:50852', 0)
-- 系统登录首页设置
INSERT INTO Dicts (Category, Name, Code, Define) VALUES (N'系统首页', N'高仿码云', N'Login-Gitee', 1);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES (N'系统首页', N'系统默认', N'Login', 1);
INSERT INTO Dicts (Category, Name, Code, Define) VALUES (N'网站设置', N'登录界面', N'Login', 1);
DELETE FROM Navigations Where Category = N'0'
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'后台管理', 10, N'fa fa-gear', N'~/Admin/Index', N'0')
INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'个人中心', 20, N'fa fa-suitcase', N'~/Admin/Profiles', N'0')

View File

@ -74,16 +74,27 @@ namespace Bootstrap.Admin.Controllers
/// 系统登录方法
/// </summary>
/// <param name="appId"></param>
/// <param name="view"></param>
/// <returns></returns>
[HttpGet]
public ActionResult Login([FromQuery]string? appId = null)
public ActionResult Login([FromQuery]string? appId = null, [FromQuery]string view = "")
{
if (DictHelper.RetrieveSystemModel())
{
ViewBag.UserName = "Admin";
ViewBag.Password = "123789";
}
return User.Identity.IsAuthenticated ? (ActionResult)Redirect("~/Home/Index") : View("Login", new LoginModel(appId));
return User.Identity.IsAuthenticated ? (ActionResult)Redirect("~/Home/Index") : LoginView(view, new LoginModel(appId));
}
private ViewResult LoginView(string view, LoginModel model)
{
if (string.IsNullOrEmpty(view))
{
// retrieve login view from db
view = DictHelper.RetrieveLoginView();
}
return View(view, model);
}
/// <summary>

View File

@ -32,6 +32,10 @@ namespace Bootstrap.Admin.Models
EnableDemo = DictHelper.RetrieveSystemModel();
AdminPathBase = DictHelper.RetrievePathBase();
EnableHealth = DictHelper.RetrieveHealth();
Logins = DictHelper.RetrieveLogins();
var view = DictHelper.RetrieveLoginView();
var viewName = Logins.FirstOrDefault(d => d.Code == view)?.Name ?? "系统默认";
LoginView = new KeyValuePair<string, string>(view, viewName);
var dicts = DictHelper.RetrieveDicts();
Apps = DictHelper.RetrieveApps().Where(d => !d.Key.Equals("BA", StringComparison.OrdinalIgnoreCase)).Select(k =>
@ -115,5 +119,15 @@ namespace Bootstrap.Admin.Models
/// 获得/设置 是否开启健康检查
/// </summary>
public bool EnableHealth { get; set; }
/// <summary>
/// 获得/设置 字典表中登录首页集合
/// </summary>
public IEnumerable<BootstrapDict> Logins { get; set; }
/// <summary>
/// 获得/设置 登录视图名称 默认是 Login
/// </summary>
public KeyValuePair<string, string> LoginView { get; set; }
}
}

View File

@ -0,0 +1,305 @@
@model LoginModel
@{
ViewBag.Title = Model.Title;
Layout = "_Layout";
}
@section css {
<environment include="Development">
<link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
<link href="~/lib/font-awesome/css/font-awesome.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link href="~/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="~/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
</environment>
<link href="~/lib/captcha/slidercaptcha.css" rel="stylesheet" />
<link href="~/css/theme.css" rel="stylesheet" asp-append-version="true" />
<link href="~/css/login-gitee.css" rel="stylesheet" asp-append-version="true" />
}
@section javascript {
<environment include="Development">
<script src="~/lib/twitter-bootstrap/js/bootstrap.bundle.js"></script>
<script src="~/lib/validate/jquery.validate.js"></script>
<script src="~/lib/validate/localization/messages_zh.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/twitter-bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="~/lib/validate/jquery.validate.min.js"></script>
<script src="~/lib/validate/localization/messages_zh.min.js"></script>
</environment>
<script src="~/lib/captcha/longbow.slidercaptcha.js"></script>
<script src="~/lib/longbow/longbow.common.js"></script>
<script src="~/lib/longbow/longbow.validate.js"></script>
<script src="~/js/login.js" asp-append-version="true"></script>
}
<div class="container-fluid">
<input id="imgUrl" type="hidden" value="@Model.ImageLibUrl" />
<div class="login-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">
没有帐号?
<a href="#">点此注册</a>
</span>
</div>
<div class="login-form-body">
<form id="login" method="post" class="form-signin">
<div class="login-wrap" data-toggle="LgbValidate" data-valid-button="button[type='submit']">
<div id="loginUser" class="form-group">
<input type="text" name="userName" class="form-control" data-toggle="tooltip" placeholder="用户名"
maxlength="16" data-required-msg="请输入用户名" value="" autofocus data-valid="true" />
</div>
<div id="loginPwd" class="form-group">
<input type="password" name="password" class="form-control" value="" data-toggle="tooltip"
placeholder="密码" maxlength="16" autocomplete="off" data-required-msg="请输入密码" 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="tel" id="phone" name="phone" 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">
<div class="input-group-text">
<span class="fa fa-lock"></span>
</div>
</div>
<input type="number" id="code" name="code" class="form-control digits" data-toggle="tooltip"
disabled value="" placeholder="验证码" maxlength="4" data-required-msg="请输入验证码"
data-valid="true" />
<div class="input-group-append">
<button type="button" id="btnSendCode" class="btn btn-sms" data-toggle="tooltip"
title="点击发送验证码">
发送验证码
</button>
</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 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-oauth="@Model.AllowOAuth" data-toggle="tooltip"
title="不填写密码默认使用 Gitee 认证" type="submit">
登 录
</button>
<div class="d-flex justify-content-center">
<a class="forget-password" href="#">已有帐号,忘记密码?</a>
</div>
<div asp-condition="@Model.AllowOAuth">
<div class="login-other">
<span class="text-muted">
其他方式登录
</span>
</div>
<div class="login-list">
<div class="item">
<a href="~/Account/Gitee" data-toggle="tooltip" title="使用 Gitee 帐号登录">
<img class="item" src="../images/gitee.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/GitHub" data-toggle="tooltip" title="使用 GitHub 帐号登录">
<img class="item" src="../images/git.svg" />
</a>
</div>
<div class="item">
<a href="#" data-toggle="tooltip" title="微信-暂未实现">
<img class="item" src="../images/weixin-2.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/Tencent" data-toggle="tooltip" title="使用 QQ 账号登录">
<img class="item" src="../images/qq.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/Alipay" data-toggle="tooltip" title="使用支付宝账号登录">
<img class="item" src="../images/zhifubao.svg" />
</a>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
</div>
<div class="login-footer">
<ui class="login-footer-body">
<li><a href="https://ba.sdgxgz.com" target="_blank">@@Bootstrap Admin</a></li>
<li><a href="https://gitee.com/LongbowEnterprise/BootstrapAdmin/wikis" target="_blank">帮助文档</a></li>
<li><a href="./Login?View=Login">系统默认登录页</a></li>
<li><a href="./Login?View=Login-Gitee">高仿码云登录页</a></li>
</ui>
</div>
</div>
<div class="modal fade" id="dialogNew" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content" data-toggle="LgbValidate" data-valid-button="#btnSubmit" data-valid-modal="#dialogNew">
<div class="modal-header">
<h5 class="modal-title" id="myModalLabel">新用户注册</h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="userName">登录名称:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user-plus"></span>
</div>
</div>
<input type="text" id="userName" autocomplete="off" class="form-control" placeholder="登录账号不可为空" userName="true" minlength="4" maxlength="16" remote="api/Register" data-remote-msg="此用户已存在" data-valid="true" />
</div>
</div>
<div class="form-group">
<label for="displayName">显示名称:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user-circle-o"></span>
</div>
</div>
<input type="text" id="displayName" class="form-control" value="" placeholder="显示名称不可为空" maxlength="20" data-valid="true" />
</div>
</div>
<div class="form-group">
<label for="password">密码:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-lock"></span>
</div>
</div>
<input type="password" id="password" class="form-control" value="" placeholder="密码不可为空" maxlength="16" data-valid="true" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label for="assurePassword">确认密码:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-lock"></span>
</div>
</div>
<input type="password" id="assurePassword" class="form-control" value="" placeholder="确认密码" maxlength="16" equalTo="#password" data-valid="true" autocomplete="off" />
</div>
</div>
<div class="form-group">
<label for="description">申请理由:</label>
<textarea id="description" class="form-control" placeholder="申请理由500字以内" rows="3" maxlength="500" data-valid="true"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
<i class="fa fa-times"></i>
<span>关闭</span>
</button>
<button type="button" class="btn btn-primary" id="btnSubmit">
<i class="fa fa-save"></i>
<span>提交</span>
</button>
<div class="slidercaptcha forgot reg card">
<div class="card-header">
<span>请完成安全验证</span>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="card-body"><div id="regcap"></div></div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="dialogForgot" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content" data-toggle="LgbValidate" data-valid-button="#btnForgot" data-valid-modal="#dialogForgot">
<div class="modal-header">
<h5 class="modal-title" id="myModalLabelForgot">忘记密码</h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="f_userName">登录账号:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user-plus"></span>
</div>
</div>
<input type="text" id="f_userName" autocomplete="off" class="form-control" placeholder="登录账号不可为空" minlength="4" maxlength="16" data-valid="true" />
</div>
</div>
<div class="form-group">
<label for="f_displayName">显示名称:</label>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
<span class="fa fa-user-circle-o"></span>
</div>
</div>
<input type="text" id="f_displayName" class="form-control" value="" placeholder="显示名称不可为空" maxlength="20" data-valid="true" />
</div>
</div>
<div class="form-group">
<label for="f_desc">申请理由:</label>
<textarea id="f_desc" class="form-control" placeholder="申请理由500字以内" rows="3" maxlength="500" data-valid="true">我是用户XXX我的手机号是XXXXXX由于密码忘记请将密码重置为123登录后我自行更改谢谢管理员</textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
<i class="fa fa-times"></i>
<span>关闭</span>
</button>
<button type="button" class="btn btn-danger" id="btnForgot">
<i class="fa fa-send-o"></i>
<span>提交</span>
</button>
<div class="slidercaptcha forgot card">
<div class="card-header">
<span>请完成安全验证</span>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="card-body"><div id="forgotcap"></div></div>
</div>
</div>
</div>
</div>
</div>

View File

@ -57,6 +57,27 @@
</div>
</div>
</div>
<div class="card">
<div class="card-header"><label class="control-label" data-toggle="lgbinfo" data-content="通过此功能进行整个网站的登录界面设置">后台管理登录地址设置</label></div>
<div class="card-body">
<div class="form-group">
<div class="form-group text-right">
<div class="btn-group" role="group">
<div class="btn-group" role="group">
<button id="loginView" class="btn btn-success dropdown-select dropdown-toggle" data-toggle="dropdown" value="@Model.LoginView.Key">@Model.LoginView.Value</button>
<div class="dropdown-menu">
@foreach (var d in Model.Logins)
{
<a href="#" data-val="@d.Code">@d.Name</a>
}
</div>
</div>
<button class="btn btn-secondary" type="button" data-method="saveLoginView">保存</button>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header"><label class="control-label" data-toggle="lgbinfo" data-content="此功能给前台网站拼接后台功能菜单时使用">后台管理地址设置</label></div>
<div class="card-body" data-toggle="LgbValidate" data-valid-button="[data-method='appPath']">

View File

@ -0,0 +1,197 @@
body {
-webkit-font-smoothing: antialiased;
}
.form-control:focus {
border-color: #66afe9;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6);
}
.login-wrap .rememberPwd i {
width: 13px;
}
.login-wrap .rememberPwd {
cursor: pointer;
margin-left: 2px;
}
.container-fluid {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
min-width: 1000px;
}
.login-container {
min-height: 500px;
box-shadow: 0px 20px 80px 0px rgba(0,0,0,0.3);
display: flex;
width: 1000px;
}
.login-container section {
width: 50%;
}
.login-container .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-container .login-sidebox::before, .login-container .login-sidebox::after {
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
}
.login-container .login-sidebox::before {
background: url(../images/left-1.png) no-repeat 0 0;
}
.login-container .login-sidebox::after {
background: url(../images/left-2.png) no-repeat right bottom;
}
.login-container .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: 1.714rem;
}
.login-other {
display: table;
text-align: center;
white-space: nowrap;
margin: 0.25rem 0 0.625rem 0;
}
.login-other:before, .login-other:after {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaAAAAACCAYAAACuTHuKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1OThBRDY4OUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1OThBRDY4QUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjU5OEFENjg3Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU5OEFENjg4Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+VU513gAAADVJREFUeNrs0DENACAQBDBIWLGBJQby/mUcJn5sJXQmOQMAAAAAAJqt+2prAAAAAACg2xdgANk6BEVuJgyMAAAAAElFTkSuQmCC");
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 50%;
background-repeat: no-repeat;
}
.login-other:before {
background-position: right 1em top 50%;
}
.login-other:after {
background-position: left 1em top 50%;
}
.login-list {
display: flex;
justify-content: space-between;
}
.login-list .item {
width: 32px;
height: 32px;
}
.btn-login {
color: #fff;
background: #fe7300;
}
.btn-login:hover {
background: #f38d30;
color: #fff;
}
.forget-password {
padding: 16px 0;
}
.login-footer {
position: absolute;
bottom: 40px;
}
.login-footer .login-footer-body {
display: flex;
width: 600px;
justify-content: space-around;
}
.login-footer .login-footer-body li {
list-style: none;
}
.login-footer .login-footer-body li a {
color: #7e8392;
}

View File

@ -0,0 +1,163 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" href="../favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="../favicon.png" />
<title>健康检查</title>
<link href="../lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="../lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
<link href="../lib/font-awesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="../css/login1.css" rel="stylesheet" asp-append-version="true" />
<!--[if lt IE 10 ]>
<link href="../css/IE8.css" rel="stylesheet" />
<![endif]-->
</head>
<body>
<!--[if lt IE 10 ]>
<div id="ieAlert" class="alert alert-danger alert-dismissible">
<div>当前浏览器版本太低不支持本系统请升级到至少IE10 <a href="../browser/IE10.exe" target="_blank">本地下载</a> <a href="https://support.microsoft.com/zh-cn/help/17621/internet-explorer-downloads" target="_blank">微软下载</a>或者使用Chrome浏览器 <a href="../browser/ChromeSetup.exe" target="_blank">本地下载</a></div>
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">关闭</span></button>
</div>
<![endif]-->
<div class="container-fluid">
<div class="login-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" target="_blank">码云托管平台 - Wiki</a></div>
</div>
</div>
</section>
<section class="login-form">
<div class="login-form-header">
<h2>登录</h2>
<span class="flex-self-end">
没有帐号?
<a href="/signup">点此注册</a>
</span>
</div>
<div class="login-form-body">
<form id="login" method="post" class="form-signin">
<div class="login-wrap" data-toggle="LgbValidate" data-valid-button="button[type='submit']">
<div id="loginUser" class="form-group">
<input type="text" name="userName" class="form-control" data-toggle="tooltip" placeholder="用户名"
maxlength="16" data-required-msg="请输入用户名" value="" autofocus data-valid="true" />
</div>
<div id="loginPwd" class="form-group">
<input type="password" name="password" class="form-control" value="" data-toggle="tooltip"
placeholder="密码" maxlength="16" autocomplete="off" data-required-msg="请输入密码" 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="tel" id="phone" name="phone" 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">
<div class="input-group-text">
<span class="fa fa-lock"></span>
</div>
</div>
<input type="number" id="code" name="code" class="form-control digits" data-toggle="tooltip"
disabled value="" placeholder="验证码" maxlength="4" data-required-msg="请输入验证码"
data-valid="true" />
<div class="input-group-append">
<button type="button" id="btnSendCode" class="btn btn-sms" data-toggle="tooltip"
title="点击发送验证码">发送验证码</button>
</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 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-oauth="@Model.AllowOAuth" data-toggle="tooltip"
title="不填写密码默认使用 Gitee 认证" type="submit">登 录</button>
<div class="d-flex justify-content-center">
<a class="forget-password" href="/password/new">已有帐号,忘记密码?</a>
</div>
<div asp-condition="@Model.AllowOAuth">
<div class="login-other">
<span class="text-muted">
其他方式登录
</span>
</div>
<div class="login-list">
<div class="item">
<a href="~/Account/Gitee" data-toggle="tooltip" title="使用 Gitee 帐号登录">
<img class="item" src="../images/gitee.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/GitHub" data-toggle="tooltip" title="使用 GitHub 帐号登录">
<img class="item" src="../images/git.svg" />
</a>
</div>
<div class="item">
<a href="#" data-toggle="tooltip" title="微信-暂未实现">
<img class="item" src="../images/weixin-2.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/Tencent" data-toggle="tooltip" title="使用 QQ 账号登录">
<img class="item" src="../images/qq.svg" />
</a>
</div>
<div class="item">
<a href="~/Account/Alipay" data-toggle="tooltip" title="使用支付宝账号登录">
<img class="item" src="../images/zhifubao.svg" />
</a>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
</div>
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="../lib/jquery/jquery.min.js"></script>
<script src="../lib/twitter-bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="../lib/bootstrap-table/bootstrap-table.min.js"></script>
<script src="../lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="../lib/longbow/longbow.common.js"></script>
<script src="../js/healths.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -238,6 +238,12 @@ $(function () {
}
});
break;
case 'saveLoginView':
var logView = $('#loginView').val();
$.bc({
url: Settings.url, data: [{ name: 'Login', code: logView }], title: '保存登录界面设置', method: "post"
});
break;
}
});

View File

@ -298,6 +298,7 @@
$.fn.extend({
autoCenter: function (options) {
if (this.length === 0) return;
options = $.extend({ top: 0 }, options);
var that = this;
var defaultVal = parseFloat(that.css('marginTop').replace('px', ''));

View File

@ -325,5 +325,17 @@ namespace Bootstrap.DataAccess
/// </summary>
/// <returns></returns>
public bool RetrieveHealth() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "健康检查" && d.Define == 0)?.Code ?? "0") == "1";
/// <summary>
/// 获得字典表登录界面数据
/// </summary>
/// <returns></returns>
public IEnumerable<BootstrapDict> RetrieveLogins() => DictHelper.RetrieveDicts().Where(d => d.Category == "系统首页" && d.Define == 1);
/// <summary>
/// 获得使用中的登录视图名称
/// </summary>
/// <returns></returns>
public string? RetrieveLoginView() => DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "网站设置" && d.Name == "登录界面" && d.Define == 1)?.Code;
}
}

View File

@ -165,7 +165,8 @@ namespace Bootstrap.DataAccess
["CookiePeriod"] = "Cookie保留时长",
["IPCachePeriod"] = "IP请求缓存时长",
["AppPath"] = "后台地址",
["EnableHealth"] = "健康检查"
["EnableHealth"] = "健康检查",
["Login"] = "登录界面"
};
var ret = SaveSettings(items.Where(i => cache.Any(c => c.Key == i.Name)).Select(i => new BootstrapDict()
{
@ -391,6 +392,18 @@ namespace Bootstrap.DataAccess
/// <returns></returns>
public static bool RetrieveHealth() => DbContextManager.Create<Dict>()?.RetrieveHealth() ?? true;
/// <summary>
/// 获得登录界面数据
/// </summary>
/// <returns></returns>
public static IEnumerable<BootstrapDict> RetrieveLogins() => DbContextManager.Create<Dict>()?.RetrieveLogins() ?? new BootstrapDict[0];
/// <summary>
/// 获得使用中的登录视图名称
/// </summary>
/// <returns></returns>
public static string RetrieveLoginView() => DbContextManager.Create<Dict>()?.RetrieveLoginView() ?? "Login";
/// <summary>
/// 保存前台应用配置信息
/// </summary>

View File

@ -29,7 +29,7 @@ namespace Bootstrap.Admin.Controllers
var content = await r.Content.ReadAsStringAsync();
Assert.Contains("登 录", content);
r = await client.GetAsync("/Account/Login");
r = await client.GetAsync("/Account/Login?AppId=BA&View=Login1");
var view = await r.Content.ReadAsStringAsync();
var tokenTag = "<input name=\"__RequestVerificationToken\" type=\"hidden\" value=\"";
var index = view.IndexOf(tokenTag);
@ -53,7 +53,7 @@ namespace Bootstrap.Admin.Controllers
[Fact]
public async void Login_Fail()
{
var r = await client.GetAsync("/Account/Login");
var r = await client.GetAsync("/Account/Login?AppId=BA");
Assert.True(r.IsSuccessStatusCode);
var content = await r.Content.ReadAsStringAsync();
Assert.Contains("登 录", content);