支持前台菜单,以及后台子菜单样式

This commit is contained in:
Argo-Lenovo 2016-11-05 23:15:07 +08:00
parent 4529655248
commit 33d65cd0b0
18 changed files with 235 additions and 99 deletions

View File

@ -247,6 +247,8 @@
<Content Include="Views\Admin\Profiles.cshtml" />
<Content Include="Views\Shared\Footer.cshtml" />
<Content Include="Views\Shared\MenuTree.cshtml" />
<Content Include="Views\Shared\SubNavigation.cshtml" />
<Content Include="Views\Shared\SubMenu.cshtml" />
<None Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</None>

View File

@ -132,6 +132,7 @@ ul.sidebar-menu {
ul.sidebar-menu li ul.sub li:last-child {
border-radius: 0 0 4px 4px;
-webkit-border-radius: 0 0 4px 4px;
padding-bottom: 10px;
}
ul.sidebar-menu li ul.sub li a {

View File

@ -217,7 +217,7 @@ a.logo {
font-weight: 300;
}
.log-arrow-up {
.arrow-up {
background: url("../images/arrow-up.png") no-repeat;
width: 20px;
height: 11px;
@ -375,6 +375,60 @@ a.logo {
right: 5px;
}
.dropdown-menu.menu {
top: 50px;
left: 15px;
margin-right: 15px;
}
.dropdown-menu.menu .arrow-up {
left: 43px;
top: -10px;
}
.dropdown-menu.menu .menu-submenu {
padding: 0 16px;
}
.dropdown-menu.menu .menu-submenu ul {
float: left;
padding-left: 10px;
padding-right: 10px;
}
.dropdown-menu.menu .menu-submenu li p {
color: #323232;
font-size: 14px;
text-transform: none;
font-weight: bold;
border-bottom: solid 1px #a9d86e;
padding: 10px 0 4px 0;
margin-bottom: 14px;
}
.dropdown-menu.menu .menu-submenu li p.active {
color: #FF6C60;
}
.dropdown-menu.menu .menu-submenu li a {
margin-bottom: 15px;
display: inline-block;
color: #323232;
font-size: 13px;
}
.dropdown-menu.menu .menu-submenu li a.active {
color: #FF6C60;
}
.dropdown-menu.menu .menu-submenu li a:hover {
color: #FF6C60;
}
.dropdown-menu.menu .menu-submenu li a i {
padding-right: 6px;
}
.notify-row {
margin-top: 4px;
padding-right: 10px;

View File

@ -18,7 +18,6 @@ namespace Bootstrap.Admin.Controllers
public ActionResult Index()
{
var v = new ContentModel();
v.ShowMenu = "hide";
v.Url = "/Content/html/dummy.html";
return View(v);
}

View File

@ -1,8 +1,12 @@

namespace Bootstrap.Admin.Models
{
public class ContentModel : HeaderBarModel
{
public string Url { get; set; }
}

namespace Bootstrap.Admin.Models
{
public class ContentModel : HeaderBarModel
{
public ContentModel()
{
ShowMenu = true;
}
public string Url { get; set; }
}
}

View File

@ -1,4 +1,5 @@
using Bootstrap.DataAccess;
using System.Collections.Generic;
using System.Web;
namespace Bootstrap.Admin.Models
@ -14,22 +15,27 @@ namespace Bootstrap.Admin.Models
DisplayName = user.DisplayName;
UserID = user.ID;
HomeUrl = "~/";
Menus = MenuHelper.RetrieveLinksByUserId(user.ID);
}
/// <summary>
///
/// </summary>
public int UserID { get; set; }
public int UserID { get; protected set; }
/// <summary>
///
/// </summary>
public string DisplayName { get; set; }
public string DisplayName { get; protected set; }
/// <summary>
///
/// </summary>
public string ShowMenu { get; set; }
public bool ShowMenu { get; protected set; }
/// <summary>
///
/// </summary>
public string HomeUrl { get; set; }
public string HomeUrl { get; protected set; }
/// <summary>
/// 获得/设置 前台菜单
/// </summary>
public IEnumerable<Menu> Menus { get; private set; }
}
}

View File

@ -9,14 +9,13 @@ namespace Bootstrap.Admin.Models
{
public NavigatorBarModel(string url)
{
Menus = MenuHelper.RetrieveMenus().ToList();
Menus.ForEach(m => m.Active = m.Url.Equals(url, StringComparison.OrdinalIgnoreCase) ? "active" : "");
Navigations = MenuHelper.RetrieveNavigationsByUserId(UserID);
Navigations.ToList().ForEach(m => m.Active = m.Url.Equals(url, StringComparison.OrdinalIgnoreCase) ? "active" : "");
HomeUrl = "~/Admin/Index";
ShowMenu = "hide";
}
/// <summary>
///
/// </summary>
public List<Menu> Menus { get; set; }
public IEnumerable<Menu> Navigations { get; set; }
}
}

View File

@ -9,4 +9,12 @@
}
$(window).on('load', iframeResposive);
$(window).on('resize', iframeResposive);
$('.menu-submenu a').click(function (event) {
event.preventDefault();
$('.menu-submenu a, .menu-submenu p').removeClass('active');
$(this).addClass('active');
$(this).parents("ul").first().find('p').addClass('active');
$('iframe').attr('src', $(this).attr('href'));
});
});

View File

@ -28,13 +28,13 @@
<label class="control-label" for="txt_menus_category">菜单类别</label>
<input type="text" class="form-control hide" id="txt_menus_category" />
<div class="btn-group">
<button type="button" class="btn btn-default">未选择</button>
<button type="button" class="btn btn-default">全部</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">下拉按钮</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#" data-val="">未选择</a></li>
<li><a href="#" data-val="">全部</a></li>
<li><a href="#" data-val="0">系统菜单</a></li>
<li><a href="#" data-val="1">自定义菜单</a></li>
</ul>
@ -84,7 +84,7 @@
<div class="form-group col-lg-6">
<label class="control-label" for="url">路径</label>
<input type="text" class="form-control" id="url" name="url" maxlength="50" />
</div>
</div>
<div class="form-group col-lg-6">
<label class="control-label" for="order">菜单序号</label>
<div class="input-group">
@ -116,5 +116,5 @@
@section customModal {
@Html.Partial("RoleConfig")
@Html.Partial("IconView")
@Html.Partial("MenuTree", Model.Menus)
@Html.Partial("MenuTree", Model.Navigations)
}

View File

@ -5,22 +5,22 @@
<div class="fa fa-bars tooltips" data-placement="right" data-original-title="展开/收起 导航条"></div>
</div>
<!--logo start-->
<a href="#" class="logo">@Model.Title</a>
<a href="#" data-toggle="dropdown" class="logo dropdown-toggle">@Model.Title</a>
<!--logo end-->
<nav class="navbar lgbMenu @Model.ShowMenu">
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">参数设置 <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="~/Home/Rules">规则设置</a></li>
<li class="divider"></li>
<li><a href="~/Home/Terminals">输入口设置</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</nav>
@if (Model.Menus.Count() > 0 && Model.ShowMenu)
{
<ul class="dropdown-menu menu">
<div class="menu-arrow arrow-up"></div>
<li>
<div class="menu-submenu">
@foreach (var menu in Model.Menus)
{
@Html.Partial("SubMenu", menu)
}
</div>
</li>
</ul>
}
<div class="top-nav">
<!--search & user info start-->
<ul class="nav pull-right top-menu">
@ -235,7 +235,7 @@
<input id="userId" type="text" class="hide" value="@Model.UserID" />
</a>
<ul class="dropdown-menu extended logout">
<div class="log-arrow-up"></div>
<div class="arrow-up"></div>
<li><a href="#"><i class=" fa fa-suitcase"></i>个人中心</a></li>
<li><a href="~/Admin"><i class="fa fa-cog"></i>设置</a></li>
<li><a href="#"><i class="fa fa-bell-o"></i>通知<span class="badge bg-success">5</span></a></li>

View File

@ -1,4 +1,4 @@
@model List<Menu>
@model IEnumerable<Menu>
<div class="modal-content menu-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>

View File

@ -1,13 +1,19 @@
@model Bootstrap.Admin.Models.NavigatorBarModel
@model NavigatorBarModel
<aside>
<div id="sidebar" class="nav-collapse ">
<!-- sidebar menu start-->
<ul class="sidebar-menu" id="nav-accordion">
@foreach (var menu in Model.Menus)
@foreach (var menu in Model.Navigations)
{
<li><a href="@Url.Content(menu.Url)" class="@menu.Active"><i class="@menu.Icon"></i><span>@menu.Name</span></a></li>
<li class="sub-menu">
<a href="@Url.Content(menu.Url)" class="@menu.Active"><i class="@menu.Icon"></i><span>@menu.Name</span></a>
@if(menu.Menus.Count() > 0)
{
@Html.Partial("SubNavigation", menu.Menus)
}
</li>
}
</ul>
<!-- sidebar menu end-->
</div>
</aside>
</aside>

View File

@ -0,0 +1,11 @@
@model Menu
<ul>
<li>
<p>@Model.Name</p>
</li>
@foreach (var menu in Model.Menus)
{
<li><a href="@Url.Content(menu.Url)" class="@menu.Active"><i class="@menu.Icon"></i><span>@menu.Name</span></a></li>
}
</ul>

View File

@ -0,0 +1,13 @@
@model IEnumerable<Menu>
<ul class="sub">
@foreach (var menu in Model)
{
<li class="sub-menu">
<a href="@Url.Content(menu.Url)" class="@menu.Active"><i class="@menu.Icon"></i><span>@menu.Name</span></a>
@if (menu.Menus.Count() > 0)
{
@Html.Partial("SubNavigation", menu.Menus)
}
</li>
}
</ul>

View File

@ -1,4 +1,5 @@

using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
/// <summary>
@ -42,5 +43,9 @@ namespace Bootstrap.DataAccess
/// 获得/设置 是否当前被选中 active为选中
/// </summary>
public string Active { get; set; }
/// <summary>
///
/// </summary>
public IEnumerable<Menu> Menus { get; set; }
}
}

View File

@ -21,11 +21,11 @@ namespace Bootstrap.DataAccess
/// </summary>
/// <param name="tId"></param>
/// <returns></returns>
public static IEnumerable<Menu> RetrieveMenus(string tId = null)
public static IEnumerable<Menu> RetrieveMenus()
{
string sql = "select n.*, d.Name as CategoryName from Navigations n inner join Dicts d on n.Category = d.Code and d.Category = N'菜单' and d.Define = 0";
var ret = CacheManager.GetOrAdd(RetrieveMenusDataKey, CacheSection.RetrieveIntervalByKey(RetrieveMenusDataKey), key =>
return CacheManager.GetOrAdd(RetrieveMenusDataKey, CacheSection.RetrieveIntervalByKey(RetrieveMenusDataKey), key =>
{
string sql = "select n.*, d.Name as CategoryName from Navigations n inner join Dicts d on n.Category = d.Code and d.Category = N'菜单' and d.Define = 0";
List<Menu> Menus = new List<Menu>();
DbCommand cmd = DBAccessManager.SqlDBAccess.CreateCommand(CommandType.Text, sql);
try
@ -51,7 +51,6 @@ namespace Bootstrap.DataAccess
catch (Exception ex) { ExceptionManager.Publish(ex); }
return Menus;
}, CacheSection.RetrieveDescByKey(RetrieveMenusDataKey));
return string.IsNullOrEmpty(tId) ? ret : ret.Where(t => tId.Equals(t.ID.ToString(), StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 查询某个用户所配置的菜单
@ -63,7 +62,7 @@ namespace Bootstrap.DataAccess
string key = string.Format("{0}-{1}", RetrieveMenusByUserIDDataKey, userId);
return CacheManager.GetOrAdd(key, CacheSection.RetrieveIntervalByKey(RetrieveMenusByUserIDDataKey), k =>
{
string sql = "select distinct n.* from UserRole ur,NavigationRole nr,Navigations n where ur.RoleID=nr.RoleID and nr.NavigationID=n.ID and ur.UserID = @UserID";
string sql = "select n.* from Navigations n inner join NavigationRole nr on n.ID = nr.NavigationID inner join UserRole ur on nr.RoleID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.ID = @UserID union select n.* from Navigations n inner join NavigationRole nr on n.ID = nr.NavigationID inner join RoleGroup rg on nr.RoleID = rg.RoleID inner join UserGroup ur on rg.GroupID = ur.GroupID inner join Users u on ur.UserID = u.ID where u.ID = @UserID";
List<Menu> Menus = new List<Menu>();
DbCommand cmd = DBAccessManager.SqlDBAccess.CreateCommand(CommandType.Text, sql);
try
@ -91,6 +90,38 @@ namespace Bootstrap.DataAccess
}, CacheSection.RetrieveDescByKey(RetrieveMenusByUserIDDataKey));
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public static IEnumerable<Menu> RetrieveNavigationsByUserId(int userId)
{
var navs = (userId == 0 ? RetrieveMenus() : RetrieveMenusByUserId(userId)).Where(m => m.Category == "0");
var root = navs.Where(m => m.ParentId == 0);
CascadeMenu(navs, root);
return root;
}
private static void CascadeMenu(IEnumerable<Menu> navs, IEnumerable<Menu> level)
{
level.ToList().ForEach(m =>
{
m.Menus = navs.Where(sub => sub.ParentId == m.ID);
CascadeMenu(navs, m.Menus);
});
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public static IEnumerable<Menu> RetrieveLinksByUserId(int userId)
{
var navs = (userId == 0 ? RetrieveMenus() : RetrieveMenusByUserId(userId)).Where(m => m.Category == "1");
var root = navs.Where(m => m.ParentId == 0);
CascadeMenu(navs, root);
return root;
}
/// <summary>
/// 删除菜单信息
/// </summary>
/// <param name="ids"></param>

View File

@ -1,47 +1,47 @@
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Common;
using System.Data;
namespace Bootstrap.DataAccess.Tests
{
[TestClass]
public class LogHelperTests
{
private Log Log { get; set; }
[TestInitialize]
public void Initialized()
{
Log = new Log() { OperationType = 1, UserName = "_测试用户名称_", OperationTime = System.DateTime.Now, OperationIp = "0.0.0.0",Remark="" };
}
[TestCleanup]
public void CleanUp()
{
using (DbCommand cmd = DBAccessManager.SqlDBAccess.CreateCommand(CommandType.Text, "delete from Logs where UserName='_测试用户名称_'"))
{
DBAccessManager.SqlDBAccess.ExecuteNonQuery(cmd);
}
}
[TestMethod]
public void RetrieveLogsTest()
{
Assert.IsTrue(LogHelper.RetrieveLogs().Count() >= 0, "带有参数的LogHelper.RetrieveLogs方法调用失败请检查数据库连接或者数据库SQL语句");
}
[TestMethod]
public void SaveLogTest()
{
Assert.IsTrue(LogHelper.SaveLog(Log), "新增日志信息出错,请检查LogHelper的SaveLog 方法");
var logs = LogHelper.RetrieveLogs();
Assert.IsTrue(logs.Count() > 0, "新增日志信息出错,请检查LogHelper的SaveLog 方法");
}
[TestMethod]
public void DeleteLogTest()
{
// 先判断数据环境是否可以删除,没有数据先伪造数据
var log = LogHelper.RetrieveLogs().FirstOrDefault(l => l.UserName == Log.UserName);
if (log == null) LogHelper.SaveLog(Log);
log = LogHelper.RetrieveLogs().FirstOrDefault(l => l.UserName == Log.UserName);
Assert.IsTrue(LogHelper.DeleteLog(log.ID.ToString()), "删除日志信息出错");
}
}
}
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Common;
using System.Data;
namespace Bootstrap.DataAccess.Tests
{
[TestClass]
public class LogHelperTests
{
private Log Log { get; set; }
[TestInitialize]
public void Initialized()
{
Log = new Log() { CRUD = "Test", RequestUrl = "Test", UserName = "_测试用户名称_", ClientIp = "0.0.0.0", ClientAgent = "Test" };
}
[TestCleanup]
public void CleanUp()
{
using (DbCommand cmd = DBAccessManager.SqlDBAccess.CreateCommand(CommandType.Text, "delete from Logs where UserName='_测试用户名称_'"))
{
DBAccessManager.SqlDBAccess.ExecuteNonQuery(cmd);
}
}
[TestMethod]
public void RetrieveLogsTest()
{
Assert.IsTrue(LogHelper.RetrieveLogs().Count() >= 0, "带有参数的LogHelper.RetrieveLogs方法调用失败请检查数据库连接或者数据库SQL语句");
}
[TestMethod]
public void SaveLogTest()
{
Assert.IsTrue(LogHelper.SaveLog(Log), "新增日志信息出错,请检查LogHelper的SaveLog 方法");
var logs = LogHelper.RetrieveLogs();
Assert.IsTrue(logs.Count() > 0, "新增日志信息出错,请检查LogHelper的SaveLog 方法");
}
[TestMethod]
public void DeleteLogTest()
{
// 先判断数据环境是否可以删除,没有数据先伪造数据
var log = LogHelper.RetrieveLogs().FirstOrDefault(l => l.UserName == Log.UserName);
if (log == null) LogHelper.SaveLog(Log);
log = LogHelper.RetrieveLogs().FirstOrDefault(l => l.UserName == Log.UserName);
Assert.IsTrue(LogHelper.DeleteLog(log.ID.ToString()), "删除日志信息出错");
}
}
}

View File

@ -33,7 +33,7 @@ namespace Bootstrap.DataAccess.Tests
}
[TestMethod]
public void RetrieveMenuByUserIDTest()
public void RetrieveMenuByUserIDTest()
{
Assert.IsTrue(MenuHelper.RetrieveMenusByUserId(1).Count() > 1, "根据用户ID查询菜单的MenuHelper.RetrieveMenusByUserId方法调用失败");
}
@ -50,9 +50,6 @@ namespace Bootstrap.DataAccess.Tests
var menu = menus.FirstOrDefault(m => m.Name == Menu.Name);
menu.Icon = "fa";
Assert.IsTrue(MenuHelper.SaveMenu(menu), string.Format("更新菜单ID = {0} 操作失败,请检查 MenuHelper.SaveMenu 方法", menu.ID));
var dest = MenuHelper.RetrieveMenus(menu.ID.ToString());
Assert.IsTrue(dest.Count() == 1, "带参数的MenuHelper.RetrieveMenus方法调用失败");
Assert.AreEqual(menu.Icon, dest.First().Icon, string.Format("更新菜单ID = {0} 操作失败,请检查 MenuHelper.SaveMenu 方法", menu.ID));
}
[TestMethod]