先来一堆关于上篇文章的废话(不喜者点此隐藏)
上篇文章发布后有一定的推荐量和浏量,对一个初学者来说,自认为还是挺不错的。最主要的是收到了不少的评论,有鼓励的,有建议的,当然也有反对的。最重要的是有一大牛级的人物对我表示了特别的关心,此人工作经验大于10年,准备单干。加了QQ聊了一阵,当然不是技术讨论,我估计也不够格跟他谈,主要是他表示关心和鼓励,虽然没有收留我的意向,再此仍深表谢意。以后可能会有技术问题咨询。我写文章最大的意图和乐趣在于把自己的想法写出来,然后希望能收获到比较好的建议和指正,从中找出自己的毛病,扩大自己的视野。
评论中,其实也就那么一两条是关于我实现想法的建议。其中有一个说到了操作权限,以下是原文引用:
“博主这个思路有个很大的问题,就是很难收敛。举个栗子吧,一个订单管理有新建、编辑、删除、归档这些操作,这样的聚合根就很难应用你的权限。增删改查很容易对应数据库操作,但是归档是个什么鬼?从业务上来看,归档就是把订单从业务库移动到历史库里面去,又增又删,还操作两个库。我看不出来你的系统能解决这个问题”
另外的都是觉得权限是与业务藕合,根本无法抽象。其中一个原文引用:
“学生信息管理:
班主任看自己所带班级的
年级组长看自己所担任年级的
校领导看全校的
而这种业务数据的界定,根本不是你角色控制的。
这是职务or岗位权限!
属于业务的一部分!
如果你要角色控制,也最多这这三种角色,但是你最后还是需要有职务信息(这种业务数据)来辅助你实现数据查询边界
还有一个特别懂我的人,相信他应该是认真的看过了,才会如此懂我。原文:
“反对的原因无非是无法完全抽象
一个行业有一个行业的权限
不同行权限有细微而又本质的区别导致无法抽象共用
也即是说 对象可能是这样 但是对对象的限制 层级关系 相互约束确是千奇百怪的
不过这个本文其实没有太大联系 博主写的权限 相信最终还是依赖其公司所面向的行业 而能从中看到些什么 从而优化我们的自己的权限 我觉得才是最重要的”
在这些评论后,我马上想到了我所忽略的真正重要的问题。于是在原来的基础上加了一个User的抽象类,一个角色抽象类,一个处理登陆用户权限的类,把用户的权限和他拥有的角色的权限综合。对于数据权限我目前有一个自认为比较可行的抽象方案,但是本文没有涉及,我想着如果这篇能有比较好的反响的话,我想另外写篇讨论一下。
细谈我对权限系统的简单理解
还是先申明一下:以下观点纯属性一个业外人士胡思乱想,不保证实用价值。如果你认同本人观点,你可以在此基础上进行优化。如果你认为有需要改造的地方,还请不吝赐教。
对于MVC服务系统,操作权限主要就是在登陆用户和一个具体控制器方法之间发生,我把一个方法设计成界面的一个按钮(操作权限),而按钮又被包含在一个菜单中(菜单权限),菜单又被包含在一个模块中。模块是一个比较大的权限,我在例子中主要是用来对用户身份做一个区分,比如有以开发人员身份登陆,我们就有一个开发人员功能模块,有管理员登陆的管理员模块,模块主要针对的是一个MVC的控制器。菜单主要用于区分一个模块下管理的对象,比如管理的角色,就有角色管理菜单,管理的是部门,就有一个部门管理菜单,这个菜单下的方法,也就是这个菜单界面的按钮,主要就是针对这个对象的一些特定操作。下面是一张草图,以展示从用户到一个具体操作的流程。但愿这段文字加上下面的图能表达出我的思路。对于操作权限的实现,我便是依据这个图来开展的。
一个用户在登陆后,他拥有的模块,菜单及菜单下的按钮已经被加载好了,而界面部分已经针对他的菜单权限有了不同的展示,所有可操作权限按菜单分类分配到不同菜单下对应的按钮。下面展示一下我实现的部分小功能效果展示。请不要介意界面的好看与否。主要看不同点,红色框起部分,几乎每个地方都有不同的。但是在同一个页面,对于小实例,我认为一个页面足已应付各种不同身份的登陆用户。由于我认为模块,菜单和按钮的管理是应该由开发人员来执行的,而权限对于开发人员是没有约束的,所以开发人员模块下,有两个固定的按钮,一个是添加,一个是授权。而其它身份的用户则不应该有操作这些的权限。
看看开发人员登陆点开发人员模块下的模块管理菜单效果
点管理员模块下的角色管理菜单下的变化
一般的无权限的用户登陆后的界面
在浏览器地址栏输入地址访问无权限的操作
搞一个开发者授权的菜单出来,列出所有的用户,给用户分配最大的管理权限
搞清流程和职责,代码实现喜欢怎么搞就怎么搞
到目前为止,开发人员这块我感觉差不多了。开发人员的职责无非就是按业务需要和逻辑开发一个MVC控制器和控制器下的方法,这跟平常的没有权限管理是一样一样的,如果要加权限管理,你只需要把它逻辑分类,保存到数据库,加上一些验证标签然后扔给前前端设计和管理员去管理分配。
模型都是最基本的属性,全部用的贫血的,如果用充血模型,API逻辑应该更清晰。比如用户隐藏字段的权限,可以写到用户类中去的。调用仓储接口来持久化,你可以用user.HideFiledToxx。
不多说了。我是把上篇文章的EF操作和水货RBAC生成DLL引用到这是测试项目来的。
后端就两个项目,非常简单。Domain层就一个服务是对上篇的进行二次封装,以持久化到数据库,另外一个是登陆用户服务类这两个类比较特别。其它都是一般的服务。这两个点是根据业务和数据库变化的。
namespace Domain.DataModels { public class User:YZY_RBAC.Core.YZYUser<int> { ) { } public string Name { get; set; } public string Telphone { get; set; } } }
User
using System.Collections.Generic; using YZY_RBAC.Core; namespace Domain.DataModels { public class Role:YZYRole<int> { ) { } /// <summary> /// 指定角色可操作的门 /// </summary> public virtual ICollection<Dep_Role> ManageDeps { get; set; } = new List<Dep_Role>(); } }
Role
using YZY_RBAC.Core; namespace Domain.DataModels { public class Relevance:BaseRelevance<int> { ) { } } }
Relevance
using System.Collections.Generic; using YZY_RBAC.Core; namespace Domain.DataModels { public class Module:BaseEntity<int> { ) { } public string Name { get; set; } public virtual ICollection<Menu> Menus { get; set; } public string Type { get; set; } public bool IsAdminModule { get; set; } public string Url { get; set; } } }
Module
using System.Collections.Generic; using YZY_RBAC.Core; namespace Domain.DataModels { public class Menu:BaseEntity<int> { ) { } public string Url { get; set; } public string RoleType { get; set; } public virtual ICollection<ActionButton> Buttons { get; set; } = new List<ActionButton>(); public string Name { get; set; } public virtual Module Module { get; set; } public int? ModuleId { get; set; } } }
Menu
using YZY_RBAC.Core; namespace Domain.DataModels { public class HideFiled:BaseHideFiled<int> { ) { } } }
HideFiled
using System.Collections.Generic; namespace Domain.DataModels { public class Employee:User { public virtual ICollection<Dep_Emp> Depatments { get; set; } = new List<Dep_Emp>(); /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 性别 /// </summary> public string Gender { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 工资 /// </summary> public double Salary { get; set; } } }
Employee
using System.Collections.Generic; using YZY_RBAC.Core; namespace Domain.DataModels { public class Deparentment:BaseEntity<int> { ) { } public string Name { get; set; } public string Number { get; set; } public int? ParentId { get; set; } public virtual Deparentment Parent { get; set; } public virtual ICollection<Dep_Emp> Employees { get; set; } = new List<Dep_Emp>(); public virtual ICollection<Dep_Role> Roles { get; set; } = new List<Dep_Role>(); public virtual ICollection<Deparentment> Childs { get; set; } = new List<Deparentment>(); public bool IsTop { get; set; } } }
Deparentment
using YZY_RBAC.Core; namespace Domain.DataModels { public class Dep_Role:BaseEntity<int> { ) { } public int DepId { get; set; } public virtual Deparentment Dep { get; set; } public int RoleId { get; set; } public virtual Role Role { get; set; } } }
Dep_Role
using YZY_RBAC.Core; namespace Domain.DataModels { public class Dep_Emp:BaseEntity<int> { ) { } public Deparentment Dep { get; set; } public int DepId { get; set; } public Employee Emp { get; set; } public int EmpId { get; set; } } }
Dep_Emp
using YZY_RBAC.Core; namespace Domain.DataModels { public class ActionButton:BaseEntity<int> { ) { } public int? MenuId { get; set; } public virtual Menu Menu { get; set; } public string Url { get; set; } public string Icon { get; set; } public string RoleType { get; set; } public string Name { get; set; } } }
ActionButton
上面这些代码这真心是蛮不好意思贴出来的。服务类就是些CURD我就不贴出来了,把两个特别点的贴出来。AuthorizeService就是个授权服务,将两个实体间的权限通过权限类型进行关联。LoginUserService是根据当前登陆用户的身份加载用户的所有权限集合,供前端用。但是我没有写测试代码,功能现在还不知道有没有问题。
using Domain.DataModels; using System; using System.Collections.Generic; using System.Linq; using YZY_RBAC.Core; namespace Domain.Service { public class AuthorizeService<TEntity>where TEntity:BaseEntity<int> { public static RBACManage<TEntity, int> rbac { get; set; } = new RBACManage<TEntity, int>(); private static RelevanceService releService; private static HideFiledService hideService; /// <summary> /// 初始化RBAC /// </summary> public static void InitiaRbac() { releService = new RelevanceService(); hideService = new HideFiledService(); rbac.RelevanceQuery = releService.Find(); rbac.HideFiledQuery = hideService.Find(); } /// <summary> /// 为当前实体授权指定的权限 /// </summary> /// <param name="entity"></param> /// <param name="per"></param> /// <param name="type"></param> public static void Authorize<TPer>(TEntity entity,TPer per,PermissionType type)where TPer:BaseEntity<int> { var rel = rbac.GetBindRelevance(entity, new Relevance(), per, type) as Relevance; if (!releService.Find().Any(o => o.EntityId == entity.Id && o.PermisId == per.Id)) releService.Add(rel); releService.Commit(); InitiaRbac(); } /// <summary> /// 为当前实体授权指定的权限 /// </summary> /// <param name="entity"></param> /// <param name="pers"></param> /// <param name="type"></param> public static void Authorize<TPer>(TEntity entity,IEnumerable<TPer>pers,PermissionType type) where TPer : BaseEntity<int> { ) { foreach(var p in pers) { var rel = rbac.GetBindRelevance(entity, new Relevance(), p, type) as Relevance; if (!releService.Find().Any(o => o.EntityId == entity.Id && o.PermisId == p.Id)) releService.Add(rel); } releService.Commit(); InitiaRbac(); } } /// <summary> /// 设置当前实体对其它实体隐藏指定的权限 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="per"></param> /// <param name="filedName"></param> public static void SetHideFiledToOther<T>(TEntity entity, T per, string filedName) where T:BaseEntity<int> { //保存申请的隐藏字段权限 var hide = rbac.GetRegisteHideFiled(entity, filedName, new HideFiled()) as HideFiled; if (!hideService.Find().Any(o => o.EntityId == entity.Id && o.HidePropertyName == filedName)) { hideService.Add(hide); hideService.Commit(); InitiaRbac(); } var rel = rbac.GetBindHideFiledToOtherEntityRelevance(entity, new Relevance(), per, filedName); //如数据库中不存在这个关联,则添加 if (!releService.Find().Any(o => o.EntityId == per.Id && o.PermissionType == PermissionType.Propety.ToString() && o.PermisId == hide.Id)) { releService.Add(rel as Relevance); } releService.Commit(); InitiaRbac(); } /// <summary> /// 设置当前实体对其它实体隐藏指定的权限 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="filedName"></param> /// <param name="others"></param> public static void SetHideFiledToOther<T>(TEntity entity,string filedName,IEnumerable<T>others)where T:BaseEntity<int> { ) { foreach(var o in others) { SetHideFiledToOther(entity, o, filedName); } } } /// <summary> /// 取消隐藏字段 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="filedName"></param> public static void ClearHideFiled(TEntity entity, string filedName) { if (hideService.Find().Any(o => o.EntityId == entity.Id && o.HidePropertyName == filedName)) { var hide =hideService.Find().Where(o => o.EntityId == entity.Id && o.HidePropertyName == filedName).FirstOrDefault(); hideService.Remove(hide); if (releService.Find().Any(o => o.PermisId == hide.Id && o.PermissionType == PermissionType.Propety.ToString())) { var rels = releService.Find().Where(o => o.PermisId == hide.Id && o.PermissionType == "Porpety").ToList(); foreach (var r in rels) { releService.Remove(r); } releService.Commit(); hideService.Commit(); InitiaRbac(); return; } } throw new Exception("没有找到指定的字段"); } /// <summary> /// 取消对指的其它实体的隐藏字段 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="filedName"></param> /// <param name="other"></param> public static void ClearHideFiledToOther<T>(TEntity entity,string filedName,T other)where T:BaseEntity<int> { if(hideService.Find().Any(o=>o.EntityId==entity.Id&&o.HidePropertyName==filedName)) { var hide = hideService.Find().Where(o => o.EntityId == entity.Id && o.HidePropertyName == filedName).FirstOrDefault(); hideService.Remove(hide); if(releService.Find().Any(o=>o.EntityId==other.Id&&o.PermisId==hide.Id&&o.PermissionType==PermissionType.Propety.ToString())) { var rel = releService.Find(o => o.EntityId == other.Id && o.PermissionType == "Propety" && o.PermisId == hide.Id).FirstOrDefault(); releService.Remove(rel); releService.Commit(); } hideService.Commit(); InitiaRbac(); return; } throw new Exception("没有找到指定的字段"); } /// <summary> /// 取消对指的其它实体的隐藏字段 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="filedName"></param> /// <param name="others"></param> public static void ClearHideFiledToOther<T>(TEntity entity, string filedName, IEnumerable<T>others) where T : BaseEntity<int> { ) { foreach (var o in others) ClearHideFiledToOther(entity, filedName, o); } } /// <summary> /// 取消当前实体的指定授权 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="other"></param> /// <param name="relFilter"></param> public static void ClearAuthorizetion<T> (TEntity entity,T other,Func<Relevance,bool>relFilter=null) where T:BaseEntity<int> { Relevance rel = null; if(relFilter==null) { if(releService.Find(o=>o.EntityId==entity.Id&&o.PermisId==other.Id).Any()) { rel = releService.Find(o => o.EntityId == entity.Id && o.PermisId == other.Id).FirstOrDefault(); releService.Remove(rel); releService.Commit(); InitiaRbac(); return; } } if(releService.Find(o=>o.EntityId==entity.Id&&o.PermisId==other.Id).AsEnumerable().Where(relFilter).Any()) { rel = releService.Find(o => o.EntityId == entity.Id && o.PermisId == other.Id).AsEnumerable().Where(relFilter).FirstOrDefault(); releService.Remove(rel); releService.Commit(); InitiaRbac(); return; } throw new Exception("没有找到指定的关联"); } /// <summary> /// 取消当前实体的指定授权 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="others"></param> /// <param name="relFilter"></param> public static void ClearAuthorizetion<T> (TEntity entity, IEnumerable<T> others, Func<Relevance, bool> relFilter = null) where T : BaseEntity<int> { ) { foreach (var o in others) ClearAuthorizetion(entity, o, relFilter); } } } }
AuthorizeService
using Domain.DataModels; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using YZY.Domain; using YZY_RBAC.Core; namespace Domain.Service { public class LoginUserService { public LoginUserService(User loginUser) { mage = new LoginUserMagage<int>(user); mage.HideFiledQuery = new HideFiledService().Find(); mage.RelevanceQuery = new RelevanceService().Find(); mage.RoleQuery = new RoleService().Find(); } private User user = UserManage<int>.GetCacheUser() as User; private Pager pager; private LoginUserMagage<int> mage; private List<ActionButton> btns = new List<ActionButton>(); private List<Deparentment> deps = new List<Deparentment>(); private List<Employee> ems = new List<Employee>(); private List<Menu> menus = new List<Menu>(); private List<Role> roles = new List<Role>(); private List<Module> modules = new List<Module>(); private List<User> users = new List<User>(); #region 属性 /// <summary> /// 当前登陆用户 /// </summary> public User LoginUser { get { return user; } } /// <summary> /// 当前登陆用户可访问或操作的按钮 /// </summary> public IEnumerable<ActionButton> Buttons { get { return btns; } } /// <summary> /// 登陆用户可访问的模块 /// </summary> public IEnumerable<Module> Modules { get { return modules; } } /// <summary> /// 当前登陆用户可访问或操作部门 /// </summary> public IEnumerable<Deparentment> Departs { get { return deps; } } /// <summary> /// 当前登陆用户可访问或操作员工 /// </summary> public IEnumerable<Employee> Employees { get { return ems; } } /// <summary> /// 当前登陆用户可访问或操作的菜单 /// </summary> public IEnumerable<Menu> Menus { get { return menus; } } /// <summary> /// 当前登陆用户可访问或操作的角色 /// </summary> public IEnumerable<Role> Roles { get { return roles; } } /// <summary> /// 登陆用户可访问的用户 /// </summary> public IEnumerable<User> Users { get { return users; } } //分页数据 public int EmpPageIndex { get; set; } public int EmpPageSize { get; set; } #endregion /// <summary> /// 加载当前登陆用户的权限资源和数据 /// </summary> public void LoadLoginUserResouces() { if (user != null) { #region 系统管理员登陆 if (user.IsSysAdmin) { deps = new DepartmentService().Find().ToList(); btns = new ButtonService().Find().ToList(); ems = new EmpService().FindPage(EmpPageIndex, EmpPageSize).ToList(); menus = new MenuService().Find().ToList(); roles = new RoleService().Find().ToList(); modules = new ModuleService().Find().ToList(); users = new UserService().Find().ToList(); return; } #endregion #region 以员工身份登陆的用户 string tel = user.Telphone; if (new EmpService().Find(o => o.Telphone == tel).Any()) { Employee em = new EmpService().Find(o => o.Telphone == tel).Single(); mage = new LoginUserMagage<int>(em); mage.HideFiledQuery = new HideFiledService().Find(); mage.RelevanceQuery = new RelevanceService().Find(); mage.RoleQuery = new RoleService().Find(); //获取后台已授权的数据 btns = mage.GetInPermissionResouces(new ButtonService().Find(), null).ToList(); menus = mage.GetInPermissionResouces(new MenuService().Find(), null).ToList(); roles = mage.GetInPermissionResouces(new RoleService().Find(), null).ToList(); modules = mage.GetInPermissionResouces(new ModuleService().Find(), null).ToList(); users = mage.GetInPermissionResouces(new UserService().Find(), null).Where(o => o.IsSysAdmin == false).ToList(); //默认的数据规则:用户只能访问自己部门和同部门的员工 deps = new Dep_EmpService().Find(o => o.Emp == em).Select(o => o.Dep).ToList(); //如果当前用户有角色权限,并集角色的部门 ) { foreach (var r in roles) { deps = new Dep_RoleService().Find(o => o.Role == r).ToList().Select(o => o.Dep).Union(deps).ToList(); } deps = deps.Distinct(new DistinctEntityId<Deparentment, int>()).ToList(); } //找出所有部门下的员工 foreach (var d in deps) { ems = ems.Union(new Dep_EmpService().Find(o => o.DepId == d.Id).ToList().Select(o => o.Emp)).ToList(); pager = new Pager(ems.Count); pager.Initia(EmpPageIndex, EmpPageSize); ems = ems.OrderBy(o => o.Id).Skip(pager.Skip).Take(pager.Take).ToList(); } //如果其中有隐藏字段的员工,替换掉 var hides = mage.GetHideFiledResouces(new EmpService().Find()); ) { ems = ems.Except(hides, new DistinctEntityId<Employee, int>()).Union(hides).ToList(); } return; } #endregion #region 以角色或其它身份登陆 //获取后台已授权的数据 btns = mage.GetInPermissionResouces(new ButtonService().Find(), null).ToList(); menus = mage.GetInPermissionResouces(new MenuService().Find(), null).ToList(); roles = mage.GetInPermissionResouces(new RoleService().Find(), null).ToList(); modules = mage.GetInPermissionResouces(new ModuleService().Find(), null).ToList(); users = mage.GetInPermissionResouces(new UserService().Find(), null).Where(o => o.IsSysAdmin == false).ToList(); //如果当前用户有角色权限,并集角色的部门 ) { var drs = new Dep_RoleService(); foreach (var r in roles) { if (drs.Find(o => o.RoleId == r.Id).Any()) { deps.Add(drs.Find(o => o.RoleId == r.Id).Select(o => o.Dep).Single()); } //deps = new Dep_RoleService().Find(o => o.Role == r).ToList().Select(o => o.Dep).Union(deps).ToList(); } deps = deps.Distinct(new DistinctEntityId<Deparentment, int>()).ToList(); } //找出所有部门下的员工 foreach (var d in deps) { ems = ems.Union(new Dep_EmpService().Find(o => o.DepId == d.Id).ToList().Select(o => o.Emp)).ToList(); } //如果其中有隐藏字段的员工,替换掉 var hids = mage.GetHideFiledResouces(new EmpService().Find()); ) { ems = ems.Except(hids, new DistinctEntityId<Employee, int>()).Union(hids).ToList(); } #endregion } } /// <summary> /// 根据地址和权限类型判断当前登陆用户是否有该操作权限 /// </summary> /// <param name="url"></param> /// <param name="type"></param> /// <returns></returns> public bool CheckActionAuthorize(string url,PermissionType type) { if (type == PermissionType.Button) { ButtonService service = new ButtonService(); ActionButton action = null; if (service.Find(o => o.Url == url).Any()) action = service.Find(o => o.Url == url).First(); if (action == null) throw (new Exception("没有找到指定URL的操作,请确定URL和TYPE正确")); return mage.CheckPermission(action); } if (type == PermissionType.Menu) { MenuService service = new MenuService(); Menu action = null; if (service.Find(o => o.Url == url).Any()) action = service.Find(o => o.Url == url).First(); if (action == null) throw (new Exception("没有找到指定URL的操作,请确定URL和TYPE正确")); return mage.CheckPermission(action); } if(type== PermissionType.Module) { ModuleService service = new ModuleService(); Module action = null; if (service.Find(o => o.Url == url).Any()) action = service.Find(o => o.Url == url).First(); if (action == null) throw (new Exception("没有找到指定URL的操作,请确定URL和TYPE正确")); return mage.CheckPermission(action); } return false; } } }
LoginUserService
EF上下文
关健是实体之间的关联关系配置,relevance实体的关联是通过代码逻辑来实现的,其它的是上下文配置的。好像都有注释的。是的,用的正是CodeFirst
using System.Data.Entity; using YZY.Datas.EF; using System.Data.Entity.ModelConfiguration.Conventions; using Domain.DataModels; namespace EFDbcontext { public class RBACDemoContext:EFUnitOfWork { public RBACDemoContext() : base("RBACDemoContext") { } public virtual DbSet<User> Users { get; set; } public virtual DbSet<Module> Modules { get; set; } public virtual DbSet<Role> Roles { get; set; } public virtual DbSet<Relevance> Relevance { get; set; } public virtual DbSet<HideFiled> HideFiled { get; set; } public virtual DbSet<ActionButton> Buttons { get; set; } public virtual DbSet<Deparentment> Departments { get; set; } public virtual DbSet<Employee> Employees { get; set; } public virtual DbSet<Menu> Menus { get; set; } public virtual DbSet<Dep_Emp> Dep_Emp { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //配置按钮和菜单的1:N关系 modelBuilder.Entity<ActionButton>() .HasOptional(o => o.Menu) .WithMany(o => o.Buttons) .HasForeignKey(o => o.MenuId); //配置部门的层级关系 modelBuilder.Entity<Deparentment>() .HasOptional(o => o.Parent).WithMany(o => o.Childs).HasForeignKey(o => o.ParentId); //配置部门和员工的N:N关系 modelBuilder.Entity<Dep_Emp>().HasKey(o => new { o.DepId, o.EmpId }); modelBuilder.Entity<Dep_Emp>() .HasRequired(o => o.Dep).WithMany(o => o.Employees).HasForeignKey(o => o.DepId); modelBuilder.Entity<Dep_Emp>() .HasRequired(o => o.Emp).WithMany(o => o.Depatments).HasForeignKey(o => o.EmpId); //配置部门和角色的N:N关系 modelBuilder.Entity<Dep_Role>().HasKey(o => new { o.DepId, o.RoleId }); modelBuilder.Entity<Dep_Role>() .HasRequired(o => o.Dep).WithMany(o => o.Roles).HasForeignKey(o => o.DepId); modelBuilder.Entity<Dep_Role>() .HasRequired(o => o.Role).WithMany(o => o.ManageDeps).HasForeignKey(o => o.RoleId); //配置模块和菜单的1:N关系 modelBuilder.Entity<Menu>() .HasOptional(o => o.Module).WithMany(o => o.Menus).HasForeignKey(o => o.ModuleId); } } }
RBACDemoContext
MVC部分:视图模型和登陆鉴权
是的,没有用到DTO。小例子,没必要用上DTO,也没用到json,因为我并没有把后端做成WebApi或是WebService,前端用的也正是.net MVC。
using Domain.DataModels; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCDemo.Models { public class LoginUserResouces { public List<Menu> Menus { get; set; } public List<ActionButton> Buttons { get; set; } public List<Deparentment> Departs { get; set; } public List<Employee> Employees { get; set; } public List<Role> Roles { get; set; } public List<Module> Modules { get; set; } public List<User> Users { get; set; } } }
LoginUserResouces
我的用户与服务器交互用的是cookie和缓存,没有用session,本来是想用memcached缓存的,但是我的mem装在虚拟机在,开个VS,IIS基本机器要炸了,根本开不了其它的了。无奈之下才用的MS的缓存。
using Domain.DataModels; using Domain.Service; using MVCDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using YZY.Domain; namespace MVCDemo.Controllers { public class BaseController:Controller { public BaseController() { if (new LoginUserService(UserManage<int>.GetCacheUser() as User) != null) { lus = new LoginUserService(UserManage<int>.GetCacheUser() as User); LoadResouce(); } } /// <summary> /// 当前登陆用户 /// </summary> public User LoginUser { get { return lus.LoginUser; } } private LoginUserService lus ; /// <summary> /// 是否启用登陆检测 /// </summary> public bool IsCheckLogin { get; set; } = true; /// <summary> /// 跳转登陆页前的url /// </summary> public string LastUrl { get { return lastUrl; } } private string lastUrl; /// <summary> /// 缓存 /// </summary> public ICache Cache { get { return DependencyContext.Resolve<ICache>(); } } public LoginUserResouces Resouces { get { return resouces; } } private LoginUserResouces resouces = new LoginUserResouces(); /// <summary> /// 加载用户的所有权限供控制器 /// </summary> private void LoadResouce() { if (lus != null) { lus.LoadLoginUserResouces(); resouces.Buttons = lus.Buttons.ToList(); resouces.Departs = lus.Departs.ToList(); resouces.Employees = lus.Employees.ToList(); resouces.Menus = lus.Menus.ToList(); resouces.Roles = lus.Roles.ToList(); resouces.Modules = lus.Modules.ToList(); resouces.Users = lus.Users.ToList(); } } protected override void OnActionExecuting(ActionExecutingContext filterContext) { if (IsCheckLogin) { //如果没有登陆跳转到登陆页面 if (LoginUser == null) { lastUrl = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName + "/" + filterContext.ActionDescriptor.ActionName; //将跳转前的url保存到缓存中 if (Cache.GetCache("LastUrl") == null) Cache.AddCache("LastUrl", lastUrl); else { Cache.DelCache("LastUrl"); Cache.AddCache("LastUrl", lastUrl); } filterContext.HttpContext.Response.Redirect("/Login/Index"); } } } } }
BaseController
基类控制器目前还没有写错误处理和日志记录,又是一个未成品,主要是没写测试,很多功能可能还有错误。下面是鉴权标签类和登陆控制器代码
using Domain.DataModels; using Domain.Service; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using YZY.Domain; using YZY_RBAC.Core; namespace MVCDemo.Controllers { //指示当前标签类可用于类或者方法,每个类或者方法只能有一个当前标签 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple =false)] public class UserAuthorizeAttribute:AuthorizeAttribute { public PermissionType Type { get; set; } public override void OnAuthorization(AuthorizationContext filterContext) { //此处可以通过修改身份认证的provide来获取当前的用户:通过filterContext.HttpContext.User; //User u = service.LoginUser; LoginUserService service = null; if (UserManage<int>.GetCacheUser() != null) { service = new LoginUserService(UserManage<int>.GetCacheUser() as User); } if (service != null) { if (service.LoginUser != null) { string conUrl = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.ToLower(); string actUrl = conUrl + "/" + filterContext.ActionDescriptor.ActionName; string checkUrl = ""; if (Type == PermissionType.Module) { checkUrl = conUrl; } else { checkUrl = actUrl; } if (service.LoginUser.IsSysAdmin) return; bool yn = false; try { yn = service.CheckActionAuthorize(checkUrl, Type); } //错误应该不要紧,用户没登陆会自动跳转到登陆页面,直到有用户,所以没有处理catch catch { } if (!yn) { filterContext.Result = new ContentResult { Content = "你没有权限,不是通过界面搞进来的?" }; /*此处应跳转至错误页面 filterContext.HttpContext.Response.Redirect("url"); 或者filterContext.Result = new RedirectToRouteResult( new RouteValueDictionary { { "action", url }, { "controller", url } });*/ } } } } } }
UserAuthorizeAttribute
using Domain.DataModels; using Domain.Service; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using YZY.Domain; namespace MVCDemo.Controllers { public class LoginController : BaseController { public LoginController() { IsCheckLogin = false; } private UserService service = new UserService(); private EmpService emService = new EmpService(); // GET: Login public ActionResult Index() { return View(); } [HttpPost] public ActionResult Account() { IsCheckLogin = false; string acc = Request["Account"]; string pwd = Request["Password"]; string rem = Request["Rember"]; User u = null; if( !service.Find(o=>o.Account==acc).Any()&& !emService.Find(o => o.Account == acc).Any()) { return Content("no:帐户不存在"); } if (service.Find(o => o.Account == acc).Any()) u = service.Find(o => o.Account == acc).First(); else if(emService.Find(o=>o.Account==acc).Any()) { u = emService.Find(o => o.Account == acc).First(); } if (u != null) { string depwd = UserManage<int>.GetDeCryptPwd(u.Password); if (depwd == pwd) { if (rem == "true" && u != null) { UserManage< * * ; UserManage< * * ; UserManage<int>.AddCacheUser(u); } UserManage<int>.AddCacheUser(u); if (Cache.GetCache("LastUrl")==null) return Content("ok:/Home/Index"); return Content("ok:/" + Cache.GetCache("LastUrl").ToString()); } } return Content("no:密码不正确"); } } }
LoginController
本来是为了方便我扩展了控制器的一些方法,结果发现用处不是很大
using Domain.DataModels; using Domain.Service; using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using YZY.Domain; using YZY_RBAC.Core; namespace MVCDemo.Controllers { public static class ExtController { public static ButtonService btnService { get; set; } = new ButtonService(); public static MenuService menuService { get; set; } = new MenuService(); public static ModuleService modService { get; set; } = new ModuleService(); private static ILogger logger = DependencyContext.Resolve<ILogger>(); /// <summary> /// 将当前控制器注册到数据库 /// </summary> /// <param name="controller"></param> /// <param name="perType"></param> /// <param name="name"></param> public static void RegiterToDb (this Controller controller,PermissionType perType,string name) { string controlUrl = controller.RouteData.Values["controller"].ToString().ToLower(); string url = controlUrl + "/" + controller.RouteData.Values["action"].ToString().ToLower(); if(perType== PermissionType.Button) { var btn = new ActionButton(); btn.Name = name; btn.Url = url; try { btnService.Add(btn); } catch (Exception ex) { throw new CustomWarring("没有添加成功", "UI", logger.LogLevel, ex); } return; } if(perType== PermissionType.Module) { var module = new Module(); module.Name = name; module.Url = controlUrl; modService.Add(module); return; } if(perType== PermissionType.Menu) { var menu = new Menu(); menu.Name = name; menu.Url = url; menuService.Add(menu); return; } throw new CustomWarring("当前权限类型不能用于注册MVC控制器或控制器方法", "UI", logger.LogLevel); } public static void BindingButtonToMenu(this Controller controller, string menuName) { string url = controller.RouteData.Values["controller"].ToString().ToLower(); url += "/" + controller.RouteData.Values["action"].ToString().ToLower(); var btn = btnService.GetForUrl(url); var menu = menuService.GetForName(menuName); btnService.SetToMenu(btn.Name, menuName); } public static void BindingMenuToModule(this Controller controller,string moduleName) { string url = controller.RouteData.Values["controller"].ToString().ToLower(); url += "/" + controller.RouteData.Values["action"].ToString().ToLower(); var menu = menuService.GetForUrl(url); menuService.SetIntoModule(menu.Name, moduleName); } } }
ExtController
MVC部分:控制器
不想写字了,直接上代码吧,有问题的欢迎评论,我会积极参与
using Domain.DataModels; using Domain.Service; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using YZY.Domain; using YZY_RBAC.Core; using Newtonsoft.Json; namespace MVCDemo.Controllers { //整个打成控制器级别的权限,除非被分配了权限,除了开发者其它都进不来 //对于模块,菜单,按钮的添加修改等开发者工作,没有存入数据库中 [UserAuthorize(Type= PermissionType.Module)] public class AdminController : BaseController { private ILogger logger = DependencyContext.Resolve<ILogger>(); private ModuleService modService=new ModuleService(); private MenuService menService=new MenuService(); // GET: Admian /// <summary> /// 模块管理菜单 /// </summary> /// <returns></returns> [UserAuthorize(Type=PermissionType.Menu)] public ActionResult ModuleManage() { if(!menService.Find(o=>o.Name=="模块管理").Any()) { this.RegiterToDb(PermissionType.Menu, "模块管理"); } this.BindingMenuToModule("开发人员模块"); return Content(PermissionType.Module.ToString()); } /// <summary> /// 菜单管理菜单 /// </summary> /// <returns></returns> [UserAuthorize(Type = PermissionType.Menu)] public ActionResult MenuManage() { if (!menService.Find(o => o.Name == "菜单管理").Any()) { this.RegiterToDb(PermissionType.Menu, "菜单管理"); } this.BindingMenuToModule("开发人员模块"); return Content(PermissionType.Menu.ToString()); } /// <summary> /// 按钮管理菜单 /// </summary> /// <returns></returns> [UserAuthorize(Type = PermissionType.Menu)] public ActionResult ButtonManage() { if (!menService.Find(o => o.Name == "按钮管理").Any()) { this.RegiterToDb(PermissionType.Menu, "按钮管理"); } this.BindingMenuToModule("开发人员模块"); return Content(PermissionType.Button.ToString()); } /// <summary> /// 添加模块 /// </summary> /// <param name="moduleName"></param> /// <returns></returns> [UserAuthorize(Type=PermissionType.Button)] public ActionResult AddModule() { if (Request["Name"]==null||Request["Url"]==null) { throw new CustomWarring("请求参数配置有误"); } string moduleName = Request["Name"]; string url = Request["Url"]; if (string.IsNullOrEmpty(moduleName)) return Content("no:模块称不能为空"); var module = new Module { Name = moduleName, Url = url, Type=PermissionType.Module.ToString() }; try { modService.Add(module); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } catch (Exception) { throw; } return Content("ok:添加加成功"); } [UserAuthorize(Type=PermissionType.Button)] public ActionResult EditModule() { string controlName = Request["controlName"]; string name = Request["moduleName"]; string type = Request["type"]; if (string.IsNullOrEmpty(controlName)||string.IsNullOrEmpty(name)) throw new CustomWarring("名称或控制器地址不能为空", "UI", logger.LogLevel); try { var module = modService.GetForName(name); module.Name = name; module.Url = controlName; module.Type = type; modService.Update(module); modService.Commit(); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } //这部分错误日志应在基类和配置文件完成 catch (Exception ex) { logger.Log("", ex); throw; } return Content("ok:修改成功"); } /// <summary> /// 添加按钮 /// </summary> /// <returns></returns> [UserAuthorize(Type=PermissionType.Button)] public ActionResult AddButton() { if (Request["Name"]==null || Request["Url"] == null || Request["MenuName"] == null) { throw new Exception("请求参数配置有误"); } string name = Request["Name"]; string url = Request["Url"]; string menuName = Request["MenuName"]; if (name == string.Empty || url == null) return Content("no:名称或地址不能为空"); if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(url)) return Content("no:名称或地址不能空"); try { ButtonService btnService = new ButtonService(); ActionButton btn = new ActionButton { Name = name, Url = url, RoleType = PermissionType.Button.ToString() }; btnService.Add(btn); if (!string.IsNullOrEmpty(menuName)) btnService.SetToMenu(name, menuName); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } catch (Exception) { throw; } return Content("ok:添加加成功"); } /// <summary> /// 修改按钮 /// </summary> /// <returns></returns> public ActionResult EditBtn() { try { string json = Request["btnJson"]; int n;int id; if (!int.TryParse(Request["btnId"], out n)) throw new Exception(); id = n; ActionButton btn = JsonConvert.DeserializeObject<ActionButton>(Request["btnJson"]); if (string.IsNullOrEmpty(btn.Name)) return Content("no:名称不能为空"); if (string.IsNullOrEmpty(btn.Url)) return Content("no:地址不能为空"); var service = new ButtonService(); var change = service.Find().Single(o => o.Id == id); if (service.Find(o => o.Name == btn.Name&&o.Name!=change.Name).Any()) return Content("no:数据库中已有该名称的按钮"); if (service.Find(o => o.Url == btn.Url&&o.Url!=change.Url).Any()) return Content("数据库中已有该地址的按钮"); change.Icon = btn.Icon; change.Name = btn.Name; change.RoleType = btn.RoleType; change.Url = btn.Url; service.Update(change); service.Commit(); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } //这部分错误日志应在基类和配置文件完成 catch (Exception ex) { logger.Log("",ex); throw; } return Content("ok:添加加成功"); } /// <summary> /// 添加菜单 /// </summary> /// <returns></returns> [UserAuthorize(Type = PermissionType.Button)] public ActionResult AddMenu() { if (Request["Name"] == null || Request["Url"] == null || Request["ModuleName"] == null) { throw new Exception("请求参数配置有误"); } string name = Request["Name"]; string url = Request["Url"]; string moduleName = Request["ModuleName"]; if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(url)) return Content("no:名称或地址不能空"); try { Menu menu = new Menu { Name = name, Url = url,RoleType=PermissionType.Menu.ToString() }; menService.Add(menu); if (!string.IsNullOrEmpty(moduleName)) menService.SetIntoModule(name, moduleName); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } catch (Exception) { throw; } return Content("ok:添加加成功"); } [UserAuthorize(Type = PermissionType.Button)] public ActionResult AuthorizeAppManager() { string userid = Request["UserId"]; if (userid == null) throw new Exception(); try { int id = int.Parse(userid); var manager = new UserService().FindById(id); AuthorizeService<User>.InitiaRbac(); AuthorizeService<User>.Authorize (manager,modService.Find().Where(o => o.Name != "开发人员模块").AsEnumerable(), PermissionType.Module); AuthorizeService<User>.Authorize (manager, menService.Find() .Where(o => o.Name != "模块管理" &&o.Name!= "菜单管理" && o.Name!= "按钮管理").AsEnumerable(), PermissionType.Menu); AuthorizeService<User>.Authorize (manager, new ButtonService().Find().AsEnumerable(), PermissionType.Button); AuthorizeService<User>.Authorize (manager, new UserService().Find() .Where(o => o.IsSysAdmin ==false).AsEnumerable(), PermissionType.User); AuthorizeService<User>.Authorize (manager, new DepartmentService().Find().AsEnumerable(), PermissionType.Group); AuthorizeService<User>.Authorize (manager, new RoleService().Find().AsEnumerable(), PermissionType.Role); AuthorizeService<User>.Authorize (manager, new EmpService().Find().AsEnumerable(), PermissionType.Data); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } catch (Exception) { throw; } return Content("ok:已成功添加网站管理员"); } } }
AdminController
using Domain.DataModels; using Domain.Service; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using YZY.Domain; using YZY_RBAC.Core; namespace MVCDemo.Controllers { [UserAuthorize(Type = PermissionType.Module)] public class RoleModuleController : BaseController { // GET: Role public ActionResult RoleManage() { try { if (!new MenuService().Find(o => o.Name == "角色管理").Any()) { this.RegiterToDb(PermissionType.Menu, "角色管理"); this.BindingMenuToModule("管理员操作模块"); } } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } return Content("ok:角色管理菜单添加成功"); } /// <summary> /// 添加角色 /// </summary> /// <param name="role"></param> /// <returns></returns> [UserAuthorize(Type=PermissionType.Button)] public ActionResult AddRole() { string roleName = Request["Name"]; string roleType = Request["Type"]; Role role = new Role { RoleName = roleName, RoleType = roleType }; try { new RoleService().Add(role); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } return Content("ok:角色" + role.RoleName + "添加成功"); } /// <summary> /// 为角色添加权限 /// </summary> /// <returns></returns> [UserAuthorize(Type=PermissionType.Button)] public ActionResult AuthorizeForRole() { string roleName = Request["RoleName"]; string type = Request["Type"]; string targetName = Request["TargetName"]; if (roleName == null || string.IsNullOrEmpty(roleName)) return Content("no:角色不能为空"); try { Role role = new RoleService().GetForName(roleName); Helper.AuthorizeMenyForType(role, targetName, type); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } string successMsg = string.Format("ok:已成功为角色{0}添加{1}权限", roleName, targetName); return Content(successMsg); } /// <summary> /// 取消角色的权限 /// </summary> /// <returns></returns> [UserAuthorize(Type = PermissionType.Button)] public ActionResult CancelAuthorize() { string roleName = Request["RoleName"]; string type = Request["Type"]; string targetName = Request["TargetName"]; if (roleName == null || string.IsNullOrEmpty(roleName)) return Content("no:角色不能为空"); try { Role role = new RoleService().GetForName(roleName); Helper.CancelAuthorizeMenyForType(role, targetName, type); } catch (CustomWarring cw) { if (cw.Code == "UI") return Content("no:" + cw.Message); throw cw; } string successMsg = string.Format("ok:已成功为角色{0}添加{1}权限", roleName, targetName); return Content(successMsg); } /// <summary> /// 为角色分配可管理的部门 /// </summary> /// <returns></returns> [UserAuthorize(Type=PermissionType.Button)] public ActionResult AllotDepartment() { string roleName = Request["RoleName"]; if (roleName == null || string.IsNullOrEmpty(roleName)) return Content("no:角色名称不能为空"); if (Request["DepNames"]==null||Request["DepNames"]==string.Empty) return Content("no:目权限名称不能空"); try { var depNames = Helper.GetNamesArray(Request["DepNames"]); var role = new RoleService().GetForName(roleName); var service = new Dep_RoleService(); var depService = new DepartmentService(); foreach (var name in depNames) { var dep = depService.GetForName(name); service.Add(new Dep_Role { RoleId = role.Id, DepId = dep.Id }); } service.Commit(); } catch (Exception) { return Content("no:添加失败"); throw ; } string successMsg = "ok:角色已成功分配到部门" ; return Content(successMsg); } } }
RoleModuleController
using Domain.DataModels; using Domain.Service; using MVCDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using YZY.Domain; namespace MVCDemo.Controllers { public class HomeController :BaseController { // GET: Home public ActionResult Index() { //测试插入一个用户 if (!new UserService().Find(o => o.Name == "test").Any()) { new UserService().Add(new User { Name = "test", Account = "test", Password = ", Telphone = " }); } ViewBag.IsAdmin = false; ViewBag.PerTypes = Helper.GetUITypes(); if (LoginUser != null) { ViewBag.UserName = LoginUser.Name; ViewBag.IsAdmin = LoginUser.IsSysAdmin; } else { ViewBag.UserName = "游客"; } LoginUserResouces lr = new LoginUserResouces(); lr = Resouces; return View(lr); } public ActionResult LogOut() { if (Cache.GetCache("LastUrl") == null) Cache.AddCache("LastUrl", "Home/Index"); Cache.DelCache("LastUrl"); Cache.AddCache("LastUrl", "Home/Index"); return new EmptyResult(); } } }
HomeController
MVC部分:视图
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <link href="~/Content/bootstrap.min.css" rel="stylesheet" /> <script src="~/scripts/jquery-1.9.1.min.js"></script> <script src="~/scripts/bootstrap.min.js"></script> <title>登陆</title> <style type="text/css"> body{ background-color:#2F4051; } .login-holder { -webkit-border-radius: 6px; -moz-border-radius: 6px; -ms-border-radius: 6px; -o-border-radius: 6px; border-radius: 6px; position: absolute; top: %; left: %; display: block; margin-top: -185px; margin-left: -205px; width: 420px; height: auto; background: white; padding: 10px; } .login-holder .form-footer { padding: 20px; } </style> <script type="text/javascript"> $(function () { $("#btn").click(function () { $.post("/Login/Account", { "Account": $("#Account").val(), "Password": $("#Password").val(), "Rember": $("#Rember").is(":checked") }, function (data) { var yn = data.split(':'); ] == "ok") { window.location.href = yn[]; } else { alert(yn[]); } }) }); }); </script> </head> <body> <div> <div class="login-holder col-md-6 col-md-offset-3"> <h2 class="page-header text-center text-primary"> 欢迎!请登陆 </h2> <form role="form" method="post"> <div class="form-group"> <input class="form-control" id="Account" type="text" placeholder="输入帐号"> </div> <div class="form-group"> <input class="form-control" id="Password" type="password" placeholder="输入密码"> </div> <div class="form-footer"> <label> <input id="> 一个月免登陆 </label><br /> <button class="btn btn-info btn-submit" id="btn" type="button">登陆</button> </div> </form> </div> </div> </body> </html>
登陆
现在只做出来两个视图,完成前面展示效果,Home视图抠的一个模板,所以有很多的JS和CSS文件,自己尝试写过,太痛苦了,所以干脆全扒下来算了,时间都浪费在上面划不来
@{ Layout = null; } @model MVCDemo.Models.LoginUserResouces <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>首页</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Loading Bootstrap --> <link href="~/aaaa/css/bootstrap.min.css" rel="stylesheet" /> <!-- Loading Stylesheets --> <link href="~/aaaa/css/font-awesome.css" rel="stylesheet"> <link href="~/aaaa/css/style.css" rel="stylesheet" type="text/css"> <link href="~/aaaa/less/style.less" rel="stylesheet" title="lessCss" id="lessCss"> <!-- Loading Custom Stylesheets --> <link href="~/aaaa/css/custom.css" rel="stylesheet"> <link rel="shortcut icon" href="~/aaaa/images/favicon.ico"> <!-- Load JS here for Faster site load =============================--> <script src="~/aaaa/js/jquery-1.10.2.min.js"></script> <script src="~/aaaa/js/jquery-ui-1.10.3.custom.min.js"></script> <script src="~/aaaa/js/less-1.5.0.min.js"></script> <script src="~/aaaa/js/jquery.ui.touch-punch.min.js"></script> <script src="~/aaaa/js/bootstrap.min.js"></script> <script src="~/aaaa/js/bootstrap-select.js"></script> <script src="~/aaaa/js/bootstrap-switch.js"></script> <script src="~/aaaa/js/jquery.tagsinput.js"></script> <script src="~/aaaa/js/jquery.placeholder.js"></script> <script src="~/aaaa/js/bootstrap-typeahead.js"></script> <script src="~/aaaa/js/application.js"></script> <script src="~/aaaa/js/moment.min.js"></script> <script src="~/aaaa/js/jquery.dataTables.min.js"></script> <script src="~/aaaa/js/jquery.sortable.js"></script> <script src="~/aaaa/js/jquery.gritter.js" type="text/javascript"></script> <script src="~/aaaa/js/jquery.nicescroll.min.js"></script> <script src="~/aaaa/js/skylo.js"></script> <script src="~/aaaa/js/prettify.min.js"></script> <script src="~/aaaa/js/jquery.noty.js"></script> <script src="~/aaaa/js/bic_calendar.js"></script> <script src="~/aaaa/js/jquery.accordion.js"></script> <script src="~/aaaa/js/theme-options.js"></script> <script src="~/aaaa/js/bootstrap-progressbar.js"></script> <script src="~/aaaa/js/bootstrap-progressbar-custom.js"></script> <script src="~/aaaa/js/bootstrap-colorpicker.min.js"></script> <script src="~/aaaa/js/bootstrap-colorpicker-custom.js"></script> <!-- Core JS =============================--> <script src="~/aaaa/js/core.js"></script> <style type="text/css"> .yuandian{ margin-right:20px; } </style> <script type="text/javascript"> $(function () { //设置全局初始变量 ).find("span[class='hidden']") var leftMenuName = $(selectMenu).attr("menuname"); var leftMenuUrl = $(selectMenu).attr("url"); var leftMenuId = $(selectMenu).attr("menuid"); var btns = $('#actionbtnlist').children("a"); //对非开发人员隐藏按钮 function hiddenBtn(){ if (leftMenuName == "按钮管理") { if ($("#authorize").hasClass("hidden")) { $("#authorize").removeClass("hidden") } if ($("#add").hasClass("hidden")) { $("#add").removeClass("hidden") } } else if (leftMenuName == "模块管理") { if ($("#authorize").hasClass("hidden")) { $("#authorize").removeClass("hidden") } if ($("#add").hasClass("hidden")) { $("#add").removeClass("hidden") } } else if (leftMenuName == "菜单管理") { if ($("#authorize").hasClass("hidden")) { $("#authorize").removeClass("hidden") } if ($("#add").hasClass("hidden")) { $("#add").removeClass("hidden") } } else { $("#authorize").addClass("hidden") $("#add").addClass("hidden") } } hiddenBtn() //清除模态框 function clear() { $('#addModal').find("input").addClass("hidden").attr("placeholder", "") $('#addModal').find("input").val('') $('#addModal').find('textarea').val('') $("#modalTitle").html(""); } clear(); //界面转换 function change() { clear() //菜单界面 var menu = document.getElementById(leftMenuUrl); $("#head").find("span[class='menu-title']").html(leftMenuName); if ($(menu).hasClass("hidden")) { $(menu).removeClass("hidden"); $(menu).siblings().addClass("hidden"); } //按钮界面 $(btns).each(function () { if ($(this).attr("menuid") == leftMenuId) { if ($(this).hasClass('hidden')) { $(this).removeClass("hidden") } } else { if ($(this).not(":hidden")) { $(this).addClass('hidden') } } }) } change() //模态框设置 $('.modal').on('show.bs.modal', function () { $(); }) $('.modal').on('hidden.bs.modal', clear()) //重新登陆 $("#Logout").click(function () { $.post("/Home/LogOut", {}, function () { window.location.href = "/Login/Index"; }) }) //菜单点击界面响应 $(".menu").click(function () { leftMenuId=$(this).children("span[class='hidden']").attr("menuid") leftMenuUrl = $(this).children("span[class='hidden']").attr("url") leftMenuName = $(this).children("span[class='hidden']").attr("menuname") change() hiddenBtn() }) //添加按钮点击事件 $("#add").click(function () { clear() var modalele = $('#addModal') var name = $(modalele).find("input[id='name']") var url = $(modalele).find("input[id='url']") var account = $(modalele).find("input[id='account']") var password = $(modalele).find("input[id='password']") var telphone = $(modalele).find("input[id='telphone']") var targetname = $(modalele).find("input[id='targetname']") if (leftMenuName == "模块管理") { addModule(name, url, modalele) } else if (leftMenuName == "菜单管理") { addMenu(name, url, targetname, modalele) } else if (leftMenuName == "按钮管理") { addBtn(name, url, targetname, modalele) } $(modalele).find("attr[data-dismiss='modal']").click(clear) }) //添加模块 function addModule(name, url,modalele) { $("#modalTitle").html("添加模块"); name.removeClass("hidden").attr("placeholder", "输入要添加的模块名称"); url.removeClass("hidden").attr("placeholder", "输入要添加的模块控制器地址"); $(modalele).modal("show"); var submit = $(modalele).find("button[id='modalSubmit']") $(submit).click(function () { $.post("/admin/addmodule", { "Name": name.val(), "Url":url.val() }, function (data) { var datas = data.split(':'); ] == "ok") { window.location.reload(); } else { alert(datas[]) clear() } }) }) } //添加菜单 function addMenu(name, url, modulename,modalele) { $("#modalTitle").html("添加菜单"); name.removeClass("hidden").attr("placeholder", "输入要添加的菜单名称"); url.removeClass("hidden").attr("placeholder", "输入要添加的菜单地址"); modulename.removeClass("hidden").attr("placeholder", "输入要添加到的模块名称") modalele.modal("show"); var submit = $(modalele).find("button[id='modalSubmit']") $(submit).click(function () { $.post("/admin/addmenu", { "Name": name.val(), "Url": url.val(), "ModuleName": modulename.val() }, function (data) { var datas = data.split(':'); ] == "ok") { window.location.reload(); clear() } else { alert(datas[]) } }) }) } //添加按钮 function addBtn(name, url, menuname, modalele) { $("#modalTitle").html("添加按钮"); name.removeClass("hidden").attr("placeholder", "输入要添加的按钮名称") url.removeClass("hidden").attr("placeholder", "输入按钮访问地址") menuname.removeClass("hidden").attr("placeholder", "输入要添加到的菜单名称") modalele.modal("show"); var submit = $(modalele).find("button[id='modalSubmit']") $(submit).click(function () { $.post("/admin/addbutton", { "Name": name.val(), "Url": url.val(), "MenuName": menuname.val() }, function (data) { var datas = data.split(':'); ] == "ok") { window.location.reload(); clear() } else { alert(datas[]) } }) }) } //查看,修改模态框 $("#ManageEditModal").on('show.bs.modal', function (event) { var button = $(event.relatedTarget) var name = button.data('name') var url = button.data('url') var type = button.data('type') var action = button.data('action') var btnId = button.data('btnid') if (action == "btnEdit") { $(this).find('.modal-title').text('编辑' + name+'按钮') $(this).find('input').attr("readonly", null) $(this).find("input[id='name']").val(name) $(this).find("input[id='url']").val(url) $(this).find("textarea[id='type']").val(type).attr("readonly",null) $(this).find('button[id="editSubmit"]').removeClass("hidden") .click(function () { name = $('#ManageEditModal').find("input[id='name']").val() url = $('#ManageEditModal').find("input[id='url']").val() type = $('#ManageEditModal').find("textarea[id='type']").val() $.post("/admin/editbtn", { "btnJson": '{"Name":"' + name + '","Url":"' + url + '","RoleType":"' + type + '"}', "btnId":btnId }, function (data) { var input = data.split(':'); ] == "ok") { $('#ManageEditModal').on("hidden") window.location.reload() } ]=="no") { alert(input[]) } }) }) } if (action == "btnLook") { $(this).find('.modal-title').text('查看' + name + '按钮') $(this).find('input').attr("readonly","") $(this).find("input[id='name']").val(name) $(this).find("input[id='url']").val(url) $(this).find("textarea[id='type']").val(type).attr("readonly","") $(this).find('button[id="editSubmit"]').addClass("hidden") } }) var authorUser = $("#admin-authouser-tbody").children('tr').children('td').children('div').children('a') authorUser.click(function () { $.post("/admin/AuthorizeAppManager", { "UserId":$(this).attr("userid") }, function (data) { var query = data.split(':') alert(query[]) window.location.reload(query[] == "ok") }) }) //按钮集合点击事件 $(btns).click(function () { ) { //找出模态框 var modalele = $('#addModal') //找出需要的控件 var name = $(modalele).find("input[id='name']") var roletype = $(modalele).find("input[id='url']") //显示模态框和相关控件 $("#modalTitle").html("添加按钮"); name.removeClass("hidden").attr("placeholder", "输入要添加的角色名称") roletype.removeClass("hidden").attr("placeholder", "输入角色的类型") modalele.modal("show"); //设置访问地址 var url = "/" + $(this).attr("url") var submit = $(modalele).find("button[id='modalSubmit']") $(submit).click(function () { $.post(url, { "Name": $(name).val(), "Type": $(roletype).val() }, function (data) { var serverdatas = data.split(':') alert(serverdatas[]) $(modalele).on('hidden') ] == "ok") { window.location.reload() } }) }) } }) }) </script> </head> <body> <div class="site-holder"> <!--横向导航 --> <nav class="navbar" role="navigation"> <!-- Logo --> <div class="navbar-header"> <a class="navbar-brand" > <i class="fa fa-list btn-nav-toggle-responsive text-white"></i> <span class="logo"> RBAC<strong>Test</strong>Demo <i class="fa fa-bookmark"></i> </span> </a> </div> <!-- 右侧图标 --> <div class="collapse navbar-collapse"> <ul class="nav navbar-nav user-menu navbar-right "> <!--用户图标--> <li> <a href="#" class="settings dropdown-toggle" data-toggle="dropdown"> <i class="fa fa-user"></i> </a> <ul class="dropdown-menu"> <li><a><i class="fa fa-user"></i> @ViewBag.UserName</a></li> <li class="divider"></li> <li><a id="Logout" class="text-danger"><i class="fa fa-lock"></i>重新登陆</a></li> </ul> </li> <!--样式颜色设置开关--> <li> <a href="#" class="settings"> <i </span> </a> </li> </ul> </div> </nav> <!--主体部分 --> <div class="box-holder"> <!-- 左侧竖向导航 --> <div class="left-sidebar"> <div class="sidebar-holder"> <ul class="nav nav-list"> <!-- 左侧导航开头 --> <li class="nav-toggle"> <button class="btn btn-nav-toggle text-primary"><i class="fa fa-angle-double-left toggle-left"></i> </button> </li> <!--模块--> @foreach (var item in Model.Modules) { <li> <a class="dropdown" data-original-title=@item.Name> <i class="fa fa-paperclip"></i> <span class="hidden-minibar"><strong> @item.Name</strong> </span> </a> @if (Model.Menus.Where(o => o.ModuleId == item.Id).Any()) { <ul id="menulist"> <!--菜单--> @foreach (var menu in Model.Menus.Where(o => o.ModuleId == item.Id)) { if (menu.ModuleId == item.Id) { <li class="menu"> <a data-original-title=@menu.Name> <i class="fa fa-pencil"></i> <span class="hidden-minibar"> @menu.Name</span> </a> <span menuname="@menu.Name" url="@menu.Url" menuid="@menu.Id"class="hidden" ></span> </li> } } </ul> } </li> } </ul> </div> </div> <!-- 开发者或管理员界面 --> <div class="content" id="managerView"> <div class="row"> <div class="col-mod-12"> <!--面包屑导航--> @*<ul class="breadcrumb"> <li><a >Dashboard</a></li> <li><a >Tables</a></li> <li class="active">Dynamic Tables</li> </ul>*@ <!--搜索框--> @*<div class="form-group hiddn-minibar pull-right"> <input type="text" class="form-control form-cascade-control nav-input-search" size=" placeholder="Search through site" /> <span class="input-icon fui-search"></span> </div>*@ <!--标题--> <h3 id="head" class="page-header"> <span class="menu-title"></span> <i class="fa fa-info-circle animated bounceInDown show-info"></i> </h3> <!--横块--> <blockquote class="page-information hidden "> <p> </p> </blockquote> </div> </div> <div class="row inbox"> <!--操作集合--> <div id="manageActionContaner" class="col-md-2 mail-left-box"> <div class="panel panel-cascade"> <div class="panel-heading "> <h3 class="text-primary panel-title"> <i class="fa fa-align-justify"></i> 操作按钮 <span class="pull-right"> <a class="panel-minimize"><i class="fa fa-chevron-up"></i></a> </span> </h3> </div> <div class="panel-body buttons-demo"> <div class="row"> <div id="actionbtnlist" class="col-md-12"> @{ var colors = new List<string> { "btn btn-success btn-block", "btn btn-info btn-block", "btn btn-warning btn-block" }; ; } @foreach (var item in Model.Buttons) { ) { n = ; } var color = colors[n]; <a class="@color hidden" url="@item.Url" menuid="@item.MenuId"> @item.Name</a> n++; } <br /> </div> </div> <!-- Large Buttons --> </div> </div> <div class="panel panel-cascade"> <div class="panel-heading "> <h3 class="panel-title text-primary"> <i class="fa fa-align-justify"></i> 其他数据 <span class="pull-right"> <a class="panel-minimize"><i class="fa fa-chevron-up"></i></a> </span> </h3> </div> <div class="panel-body list-group inbox-options"> <a class="list-group-item"><i class="fa fa-inbox"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-bolt"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-magic"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-bookmark-o"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-check-square-o"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-ban"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-trash-o"></i> 其他数据 </a> <a class="list-group-item"><i class="fa fa-archive"></i> 其他数据 </a> </div> </div> </div> <!--菜单对应视图数据--> <div id="manageMenuContainer" class="col-md-10 mail-right-box"> <!--头部--> <div class="mail-options-nav"> <div class="mail-pagination btn-group yuandian"> <h4 class="text-primary"> <i class="fa fa-align-justify"></i> 列表展示 </h4> </div> <div class="btn-group mail-options popover-options"> <a id="add" class="btn btn-success"><i class="fa fa-archive"></i> 添加</a> <a id="authorize" class="btn btn-warning" > <i class="fa fa-ban"></i> 删除 </a> </div> <div class="mail-pagination pull-right "> <label - of </label> <a class="btn btn-default"><i class="fa fa-angle-double-left"></i></a> <a class="btn btn-default"><i class="fa fa-angle-double-right"></i></a> <a class="btn btn-info"><i class="fa fa-cogs"></i></a> </div> </div> <div class="mails"> <!----------------- 模块管理-------------> <div id="admin/modulemanage" class="hidden"> <table class="table table-bordered table-hover table-striped display"> <thead> <tr> <th class="text-center"> <input type="checkbox" /> </th> <th class="text-center">模块名称</th> <th class="text-center">地址</th> <th class="text-center">操作</th> </tr> </thead> <tbody> @foreach (var item in Model.Modules) { var edit = "edit-" + item.Id; var del = "del-" + item.Id; var see = "see-" + item.Id; <tr class="odd gradeX"> <td class="text-center"> <input type="checkbox" /> </td> <td class="text-center "> @item.Name</td> <td class="text-center "> @item.Url </td> <td class="text-center "> <div class="btn-group mail-options"> <a id="@edit" class="btn btn-success btn-sm"> <i class="fa fa-edit"></i> 编辑 </a> <a id="@see" class="btn btn-warning btn-sm"> <i class="fa fa-trash-o"></i> 查看 </a> </div> </td> </tr> } </tbody> </table> </div> <!------------------菜单管理------------> <div id="admin/menumanage" class="hidden"> <table class="table table-bordered table-hover table-striped display"> <thead> <tr> <th class="text-center"> <input type="checkbox" /> </th> <th class="text-center">名称</th> <th class="text-center">地址</th> <th class="text-center">操作</th> </tr> </thead> <tbody> @foreach (var item in Model.Menus) { var edit = "edit-" + item.Id; var del = "del-" + item.Id; var see = "see-" + item.Id; <tr class="odd gradeX"> <td class="text-center"> <input type="checkbox" /> </td> <td class="text-center "> @item.Name</td> <td class="text-center "> @item.Url </td> <td class="text-center "> <div class="btn-group mail-options"> <a id="@see" class="btn btn-warning btn-sm"> <i class="fa fa-trash-o"></i> 查看 </a> </div> </td> </tr> } </tbody> </table> </div> <!-------------------按钮管理------------> <div id="admin/buttonmanage" class="hidden"> <table id="btnManageTable" class="table table-bordered table-hover table-striped display"> <thead> <tr> <th class="text-center"> <input type="checkbox" /> </th> <th class="text-center">名称</th> <th class="text-center">地址</th> <th class="text-center">操作</th> </tr> </thead> <tbody> @foreach (var item in Model.Buttons) { <tr class="odd gradeX"> <td class="text-center"> <input type="checkbox" /> </td> <td class="text-center "> @item.Name</td> <td class="text-center "> @item.Url </td> <td class="text-center "> <div class="btn-group mail-options"> <a class="btn btn-success btn-sm" data-toggle="modal" data-target="#ManageEditModal" data-name="@item.Name" data-url="@item.Url" data-type="@item.RoleType" data-action="btnEdit" data-btnid="@item.Id"> <i class="fa fa-edit"></i> 编辑 </a> <a class="btn btn-warning btn-sm" data-toggle="modal" data-target="#ManageEditModal" data-name="@item.Name" data-url="@item.Url" data-type="@item.RoleType" data-action="btnLook" data-btnid="@item.Id"> <i class="fa fa-trash-o"></i> 查看 </a> </div> </td> </tr> } </tbody> </table> </div> <!-------------------开发人员授权管理------------> <div id="admin/menu" class="hidden"> <table id="admin-authouser-table" class="table table-bordered table-hover table-striped display"> <thead> <tr> <th class="text-center"> <input type="checkbox" /> </th> <th class="text-center">用户名称</th> <th class="text-center">帐号</th> <th class="text-center">电话</th> </tr> </thead> <tbody id="admin-authouser-tbody"> @foreach (var item in Model.Users) { if (!item.IsSysAdmin) { <tr class="odd gradeX"> <td class="text-center"> <input type="checkbox" /> </td> <td class="text-center "> @item.Name</td> <td class="text-center "> @item.Account </td> <td class="text-center"> @item.Telphone</td> <td class="text-center "> <div class="btn-group mail-options"> <a userid="@item.Id" class="btn btn-success btn-sm"> <i class="fa fa-edit"></i> 授权为网站管理员 </a> </div> </td> </tr> } } </tbody> </table> </div> <!-------------------角色管理------------> <div id="rolemodule/rolemanage" class="hidden"> <table class="table table-bordered table-hover table-striped display"> <thead> <tr> <th class="text-center"> <input type="checkbox" /> </th> <th class="text-center">角色名称</th> <th class="text-center">角色类型</th> </tr> </thead> <tbody> @foreach (var item in Model.Roles) { var edit = "edit-" + item.Id; var del = "del-" + item.Id; var see = "see-" + item.Id; <tr class="odd gradeX"> <td class="text-center"> <input type="checkbox" /> </td> <td class="text-center "> @item.RoleName</td> <td class="text-center "> @item.RoleType </td> </tr> } </tbody> </table> </div> </div> </div> </div> <!-----------------------------模态框-----------------------------------------------> <!--添加框--> <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="addModuleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header bg-primary text-white"> <button type="button" class="close text-white" data-dismiss="modal" aria-hidden="true"> × </button> <h3 id="modalTitle" class="modal-title">Subject</h3> </div> <div class="modal-body"> <div class="icon-show"> <form id="addForm" role="form"> <div class="form-group"> <input class="form-control" id="name" type="text" placeholder=""> </div> <div class="form-group"> <input class="form-control" id="url" type="text" placeholder=""> </div> <div class="form-group"> <input class="form-control" id="account" type="text" placeholder=""> </div> <div class="form-group"> <input class="form-control" id="password" type="password" placeholder=""> </div> <div class="form-group"> <input class="form-control" id="telphone" type="text" placeholder=""> </div> <div class="form-group"> <input class="form-control" id="targetname" type="text" placeholder=""> </div> </form> </div> </div> <div class="modal-footer"> <button id="close" data-dismiss="modal" type="button" class="btn bg-primary text-white">退出</button> <button id="modalSubmit" type="button" class="btn bg-primary text-white">提交</button> </div> </div> </div> </div> <!--修改框--> <div class="modal fade" id="ManageEditModal" tabindex="-1" role="dialog" aria-labelledby="ManageEditModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header bg-primary text-white"> <button type="button" class="close text-white" data-dismiss="modal" aria-hidden="true"> × </button> <h3 id="modalTitle" class="modal-title">编辑</h3> </div> <div class="modal-body"> <div class="icon-show"> <form id="ManageEditForm" role="form" class="form-horizontal"> <div class="form-group"> <label id="labelName" for="name" class="control-label col-md-2">按钮名称</label> <div class="col-md-10"> <input class="form-control" id="name" type="text" placeholder=""> </div> </div> <div class="form-group"> <label id="labelUrl" for="url" class="control-label col-md-2">地址</label> <div class="col-md-10"> <input class="form-control" id="url" type="text" placeholder=""> </div> </div> <div class="form-group"> <label id="labelType" for="type" class="control-label col-md-2">属性</label> <div class="col-md-10"> <textarea rows=" class="form-control" id="type" type="text" ></textarea> </div> </div> </form> </div> </div> <div class="modal-footer"> <button id="close" data-dismiss="modal" type="button" class="btn bg-primary text-white">退出</button> <button id="editSubmit" type="button" class="btn bg-primary text-white">提交修改</button> </div> </div> </div> </div> </div> <!--用户界面--> <div id="userView" class="content hidden"> </div> <!-- 右侧页面编辑模块 --> <div class="right-sidebar right-sidebar-hidden"> <div class="right-sidebar-holder"> <h4 class="page-header text-primary text-center"> 页面样式颜色选项 </h4> <ul class="list-group theme-options"> <!---样式--> <li class="list-group-item" href="#"> <div class="checkbox"> <label> <input type="checkbox" id="fixedNavbar" value=""> 顶部导航栏 </label> </div> <div class="checkbox"> <label> <input type="checkbox" id="fixedNavbarBottom" value=""> 底部导航栏 </label> </div> <div class="checkbox"> <label> <input type="checkbox" id="boxed" value=""> 缩小居中 </label> </div> <div class="form-group backgroundImage hidden"> <label class="control-label">Paste Image Url and then hit enter</label> <input type="text" class="form-control" id="backgroundImageUrl" /> </div> </li> <!--颜色--> <li class="list-group-item" href="#"> 颜色搭配选项 <ul class="list-inline predefined-themes"> <li><a class="badge" style="background-color:#54b5df" data-color-primary="#54b5df" data-color-secondary="#2f4051" data-color-link="#FFFFFF"> </a></li> <li><a class="badge" style="background-color:#d85f5c" data-color-primary="#d85f5c" data-color-secondary="#f0f0f0" data-color-link="#474747"> </a></li> <li><a class="badge" style="background-color:#3d4a5d" data-color-primary="#3d4a5d" data-color-secondary="#edf0f1" data-color-link="#777e88"> </a></li> <li><a class="badge" style="background-color:#A0B448" data-color-primary="#A0B448" data-color-secondary="#485257" data-color-link="#AFB5AA"> </a></li> <li><a class="badge" style="background-color:#2FA2D1" data-color-primary="#2FA2D1" data-color-secondary="#484D51" data-color-link="#A5B1B7"> </a></li> <li><a class="badge" style="background-color:#2f343b" data-color-primary="#2f343b" data-color-secondary="#525a65" data-color-link="#FFFFFF"> </a></li> </ul> </li> <li class="list-group-item"> 主体颜色 <div class="input-group colorpicker-component bscp" data-color="#54728c" data-color-format="hex" id="colr"> <span class="input-group-addon"><i style="background-color: #54728c"></i></span> <input type="text" value="#54728c" id="primaryColor" readonly class="form-control" /> </div> </li> <li class="list-group-item" href="#"> 左侧导航背景颜色 <div class="input-group colorpicker-component bscp" data-color="#f9f9f9" data-color-format="hex" id="Scolr"> <span class="input-group-addon"><i style="background-color: #f9f9f9"></i></span> <input type="text" value="#f9f9f9" id="secondaryColor" readonly class="form-control" /> </div> </li> <li class="list-group-item" href="#"> 左侧导航字体颜色 <div class="input-group colorpicker-component bscp" data-color="#54728c" data-color-format="hex" id="Lcolr"> <span class="input-group-addon"><i style="background-color: #54728c"></i></span> <input type="text" value="#54728c" id="linkColor" readonly class="form-control" /> </div> </li> <li class="list-group-item" href="#"> 右侧导航背景色 <div class="input-group colorpicker-component bscp" data-color="#f9f9f9" data-color-format="hex" id="Rcolr"> <span class="input-group-addon"><i style="background-color: #f9f9f9"></i></span> <input type="text" value="#f9f9f9" id="rightsidebarColor" readonly class="form-control" /> </div> </li> </ul> </div> </div> </div> </div> </body> </html>
首页
做前端界面真的好痛苦啊,不知道有没调试的工具。我都不想干这种义务劳动了。