zoukankan      html  css  js  c++  java
  • CRUD全栈式编程架构之界面层的设计

    Layout的设计

    模板模式

    mvc的模板特别类似设计模式中模板方法模式,结合Layout中RenderSection和RenderBody方法可以将部分html展现逻辑延迟到具体的视图页面去实现里面实现。结合我们增删改查的逻辑,我们的用户界面,我们将页面分为这几个区域,实现部分逻辑以后,部分留给具体的页面去实现。例如图片中新增,编辑,删除,导入,导出,查询都是架构自带的操作,至于复制就给页面扩展,查询条件也留给具体的页面中扩展,模板中给出RenderSection即可。

    执行顺序

    这个执行顺序的问题可以通过调试去查找答案,大致是返回页面后,先执行具体页面的逻辑,当第一个@{} 代码段执行完毕之后,会检查有没有Layout页面,如果有则进入Layout顺序执行,如果Layout页面有RenderSection则会去字页面检查有没有定义,如果定义则执行,页面中除了RenderSection部分都会当作RenderBody中执行,但是实际程序运行中,页面会全部动态编译成dll去执行。具体可以查看Razor引擎模板的相关内容。

    元数据

    mvc定义了一套元数据机制,在模板中可以通过ViewData.ModelMatedata去访问这样可以搭配attribute做出很多扩展的设计,具体案例会在本文后面做详细说明。

    列表布局页

    @using Coralcode.Framework.Mvc.Models.MiniUI
    @using HCC.Web.Utils
    @{
        Layout = null;
        //如果不使用父类默认设定操作按钮,请重新制定参数
        if (ViewBag.DataOperation == null)
        {
            ViewBag.DataOperation =
                MiniUIDataOperation.Add | MiniUIDataOperation.Edit | MiniUIDataOperation.Delete 
                | MiniUIDataOperation.ExportTemplate | MiniUIDataOperation.Import | MiniUIDataOperation.Export;
        }
        MiniUIDataOperation dataOperation = (MiniUIDataOperation)ViewBag.DataOperation;
    
        if (ViewBag.AddEditDialogHeight == null)
        {
            ViewBag.AddEditDialogHeight = 600;
        }
        if (ViewBag.AddEditDialogWidth == null)
        {
            ViewBag.AddEditDialogWidth = 800;
        }
        string refreshUrl=ViewBag.ListUrl;
        if (ViewBag.ShowPager)
        {
            refreshUrl = ViewBag.PageUrl;
        }
    
    }
    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title></title>
        <meta http-equiv="content-type" content="text/Html; charset=UTF-8" />
        @Styles.Render("~/content/miniuicss")
        @Scripts.Render("~/script/miniuijs", "~/script/tooljs")
    </head>
    <body>
        <style type="text/css">
            html, body {
                margin: 0;
                padding: 0;
                border: 0;
                 100%;
                height: 100%;
                overflow: hidden;
            }
        </style>
        <div id="datagrid_toolbar">
            <div class="mini-toolbar" style="border-bottom: 0; padding: 0px;">
                <table style=" 100%;">
                    <tr>
                        <td style=" 100%;">
                            <div id="operation">
                                @if ((dataOperation & MiniUIDataOperation.Add) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-add" onclick="add()">增加</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Edit) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-edit" onclick="edit()">编辑</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Delete) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-remove" onclick="remove()">删除</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.ExportTemplate) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-download" href='@ViewBag.ExportTemplateUrl'>导出模板</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Import) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-upload" onclick="importAction()">导入</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Export) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-download" href='@ViewBag.ExportUrl'>导出</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Register) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-user" onclick="RegisterLesson()">预约</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.Sign) != 0)
                                {
                                    <a class="mini-button" iconcls="icon-tip" onclick='SignLesson()'>签到</a>
                                }
                                @if ((dataOperation & MiniUIDataOperation.InputUser) != 0)
                                {
                                    string currentMember = string.Empty;
                                    var userIdName = UserHelper.GetCookieIdName();
                                    if (userIdName != null)
                                    {
                                        currentMember = string.Format("(当前'{0}')",userIdName.Item2);
                                    }
    
                                    <a class="mini-button" iconcls="icon-user" id="a_userName" onclick='InputUserMemberView()'>获取会员@{@currentMember}</a>
                                }
                                @RenderSection("ExtendedOperation", false)
                            </div>
                        </td>
                        <td style="white-space: nowrap;">
                            <div id="query">
                                @RenderSection("Query", false)
                                <a class="mini-button" iconcls="icon-search" onclick="LoadData()">查询</a>
    
                            </div>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
        <!--撑满页面-->
        <div class="mini-fit">
            <div id="datagrid1" class="mini-datagrid" style=" 100%; height: 100%;"  showpager="@ViewBag.ShowPager" idfield="id"  multiselect="true">
                <div property="columns">
                    @Html.Partial("_HeaderPartial", (List<DataGridColumn>)ViewBag.Header)
                </div>
            </div>
        </div>
        @RenderBody()
    
        @* ReSharper disable once SyntaxIsNotAllowed *@
        <script type="text/javascript">
        mini.parse();
        var grid = mini.get("datagrid1");
        var url = '@Html.Raw(ViewBag.EditUrl)';
        var importUrl = '@Html.Raw(ViewBag.ImportUrl)';
        var title = '@ViewBag.Title';
    
    
        grid.set({
            url: "@Html.Raw(refreshUrl)",
            pageSize:20,
            pageIndex:10,
            sizeList:[10,20,50,100]
        });
    
        function LoadData() {
            var data="{" +  $("#query input[name]").map(function() {
                return $(this).attr("name") + ":" + "'"+$(this).val()+"'";
            }).get().join(", ")+"}";
            grid.load(mini.decode(data,false));
        }
    
        //todo 这里如果需要查询怎么办
        LoadData();
    
        var dynamicUrlParams = "";
    
        @if ((dataOperation & MiniUIDataOperation.Add) != 0)
        {
            <text>
        function add() {
            mini.open({
                url: url,
    
                title: "新增" + title,
                 @ViewBag.AddEditDialogWidth,
                height: @ViewBag.AddEditDialogHeight,
                onload: function() {
                    var iframe = this.getIFrameEl();
                    var data = { action: "new" };
                    //iframe.contentWindow.SetData(data);
                },
                ondestroy: function(action) {
    
                    grid.reload();
                }
            });
        }
        </text>
        }
        @if ((dataOperation & MiniUIDataOperation.Edit) != 0)
        {
            <text>
        function edit() {
    
            var row = grid.getSelected();
            if (row) {
                var editUrl = url + (url.indexOf('?') > 0 ? '&' : '?') + "id=" + row.Id;
    
                mini.open({
                    url: editUrl,
                    title: "编辑" + title,
                     @ViewBag.AddEditDialogWidth,
                    height: @ViewBag.AddEditDialogHeight,
    
                    ondestroy: function(action) {
                        grid.reload();
    
                    }
                });
    
            } else {
                alert("请选中一条记录");
            }
    
        }
        </text>
        }
        @if ((dataOperation & MiniUIDataOperation.Delete) != 0)
        {
            <text>
        function remove() {
    
            var rows = grid.getSelecteds();
    
            if (rows.length > 0) {
                if (confirm("确定删除选中记录?")) {
                    var ids = [];
                    for (var i = 0, l = rows.length; i < l; i++) {
                        var r = rows[i];
                        ids.push(r.Id);
                    }
                    var id = ids.join(',');
    
                    grid.loading("操作中,请稍后......");
                    var deleteUrl = '@Html.Raw(ViewBag.DeleteUrl)';
                    deleteUrl = deleteUrl + (deleteUrl.indexOf('?') > 0 ? '&' : '?') + "ids=" + id;
                    $.ajax({
                        type: 'post',
                        url: deleteUrl,
                        success: function(data) {
                            if (data.State == 0) {
                                grid.reload();
                                return;
                            }
                            grid.unmask();
                            alert(data.Data);
    
                        },
                        error: function() {
                        }
                    });
                }
            } else {
                alert("请选中一条记录");
            }
        }
        </text>
        }
        @if ((dataOperation & MiniUIDataOperation.Import) != 0)
        {
            <text>
        function importAction() {
            mini.open({
    
                url: importUrl,
                title: "导入" + title,
                 600,
                height: 300,
    
                ondestroy: function(action) {
                    grid.reload();
    
                }
            });
        }
        </text>
        }
    
        @if ((dataOperation & MiniUIDataOperation.Register) != 0)
            {
                <text>
        function RegisterLesson() {
            var rows = grid.getSelecteds();
            if (rows.length < 1) {
                alert("请选中一条记录");
                return;
            }
            if (rows.length > 1) {
                alert("每次只能预订一节课程");
                return;
            }
            var ids = [];
            for (var i = 0, l = rows.length; i < l; i++) {
                var r = rows[i];
                ids.push(r.Id);
            }
            var id = ids.join(',');
    
            grid.loading("操作中,请稍后......");
            var registerLessonUrl = '@Html.Raw(ViewBag.RegisterLessonUrl)';
            registerLessonUrl = registerLessonUrl
                    + (registerLessonUrl.indexOf('?') > 0 ? '&' : '?') + "ids=" + id
                    + "&"+dynamicUrlParams;
            $.ajax({
                type: 'post',
                url: registerLessonUrl,
                success: function (data) {
                    if (data.State == 0) {
                        grid.reload();
                        return;
                    }
                    grid.unmask();
                    alert(data.Data);
    
                },
                error: function () {
                }
            });
    
        }
    
        </text>
            }
        @if ((dataOperation & MiniUIDataOperation.Sign) != 0)
            {
                <text>
            </text>
            }
    
            @if ((dataOperation & MiniUIDataOperation.InputUser) != 0)
            {
                <text>
        
            function InputUserMemberView(){
                mini.prompt("请输入会员号码:", "请输入",
                function (action, value) {
                    if (action != "ok") {
                        return;
                    } 
                    var userLoginUrl = '/Portal/User/Login?number='+value+ "&"+dynamicUrlParams;
                    $.ajax({
                        type: 'post',
                        url: userLoginUrl,
                        success: function (data) {
                            if (data.State == 0) {
                                $("#a_userName").children("span").html("获取会员(当前'"+data.Data+"')")
                                return;
                            }
                            alert(data.Data);
    
                        },
                        error: function () {
                        }
                    });
    
    
    
                }
            );
            }
    
    
                
                </text>
            }
    
    
    
            function onDateRenderer(e) {
                var value = e.value;
                if (value) return mini.formatDate(value, 'yyyy-MM-dd');
                return "";
            }
            function onDateTimeRenderer(e) {
                var value = e.value;
                if (value) return mini.formatDate(value, 'yyyy-MM-dd hh:mm:dd');
                return "";
            }
            function onTimeRenderer(e) {
                var value = e.value;
                if (value) return mini.formatDate(value, 'hh:mm:dd');
                return "";
            }
        </script>
        @RenderSection("Script", false)
    </body>
    </html>
    

    操作配置化,并且可扩展

    MVC的模板加载顺序,基于mvc的模板顺序,我们可以在自模板中定义出页面操作,如果子页面没有定义,则在模板中给出默认定义。

    Flags的枚举 由于页面操作是可以交叉的,所以我们采用flags的枚举来作为判断依据,flags枚举其实就是二进制的位操作,建议没用过的好好去研究下。在很多地方都很有用,特别是条件组合的情况下。

    流式布局

    结合RennderSection的设计,模板并不知道操作和查询条件有多少,所以我们做成流式布局,操作左对齐,查询右对齐,在少数操作和少数查询的时候效果还不错,

    新增编辑布局页

    @{
        Layout = null;
    }
    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" />
        <title></title>
        <meta http-equiv="content-type" content="text/Html; charset=UTF-8" />
        <script type="text/javascript" src="@Url.Content("~/Content/js/jquery-1.6.2.min.js")"></script>
        <script type="text/javascript" src="@Url.Content("~/Content/js/boot.js")"></script>
        @Styles.Render("~/content/miniuicss")
        @Scripts.Render("~/script/miniuijs")
        @Scripts.Render("~/script/tooljs")
        <link href="@Url.Content("~/Content/css/edit.css")" type="text/css" rel="stylesheet"/>
    
        <script type="text/javascript" src="@Url.Content("~/Content/js/jquery.form.js")"></script>
    </head>
    <body style="margin: 0px;height: 100%">
    
        <form method="post" id="formmain" style=" 100%; height: 100%">
            <div class="mini-fit" style="padding: 5px">
    
                <table style="table-layout: fixed;  100%;">
                    @RenderBody()
                </table>
            </div>
    
    
            <div class="mini-toolbar" style="text-align:center;padding-top:8px;padding-bottom:8px; " borderStyle="border:1;">
    
                <a id="submit" class="mini-button" iconcls="icon-ok" onclick="submit()">确定</a>
                <span style="display: inline-block;  25px;"></span>
                <a id="cancel" class="mini-button" iconcls="icon-cancel" onclick="onCancel(this)">取消</a>
            </div>
    
        </form>
        @Scripts.Render("~/script/jquery.validate")
    <script type="text/javascript">
        
        function submit() {
            $.ajax({
                type: "Post",
                data:$("form").serialize(),
                success: function (jsonResult) {
    
                    if (jsonResult.State === 0) {
                        CloseWindow("save");
                        return;
                    }
                    alert(jsonResult.Data);
                }
            });
        };
        
        function onCancel(e) {
            CloseWindow("cancel");
        }
        function CloseWindow(action) {
            if (window.CloseOwnerWindow) window.CloseOwnerWindow(action);
            else window.close();
        }
    </script>
        @RenderSection("Script", false)
    </body>
    </html>
    

    界面尽量精简

    编辑模板操作ajax提交的方式,将提交逻辑封装在模板页中,子页面只需要填充输入字段即可这里要特别提醒,尽量做到编辑界面的简洁,将那些复杂的输入作为编辑模板扩展,这部分将在下一节中说明。

    自适应的布局

    布局中,将操作放在最下方提供提交和取消两个操作即可满足要求。剩下与输入相关的部分可以在具体页面中去做扩展。最终我们是要实现Html.EditForModel的扩展,暂时精力有限没有做到这一步,最后在更精简的设计中看是否有时间去实现这个逻辑。当然由于部分页面输入逻辑比较复杂,所以即使做出来了,也不能替代全部的编辑页面。

    MVC编辑模板

    挖掘MVC源代码地图

    我们查看mvc的源代码可以发现,mvc结合DataType提供了编辑和显示两种模板类型。放在Views/Shared的EditTemplate和DisplayTemplate中,同时在模板中也可以获取到对应模型属性的元数据,这里要特别注意,不要给html.textbox这类输入方法中提供name属性,mvc自己会在name中默认拼接上元数据中的属性名。掌握这种方式之后可以做在编辑页面做出更简洁的设计,如果你扩展的类型够多,那么将会给程序员编程提供很大的便利.

    富文本编辑

    我们选用DataType.MultilineText作为富文本的扩展,将ViewModel属性标记[DataType(DataType.MultilineText)],然后再编辑的时候只需Html.EditFor()即可实现自动调用,我们选用UEditer作为复文本框,只需简单几行代码就可以实现富文本框的扩展。

    @model string
    @Scripts.Render("~/script/ueditor")
    @Styles.Render("~/content/ueditor")
    @Html.TextArea("", Model, new { id = ViewData.ModelMetadata.PropertyName })
    <script type="text/javascript">
        var editor = new baidu.editor.ui.Editor();
        editor.render('@ViewData.ModelMetadata.PropertyName');
    </script>
    

    时间相关扩展

    在mvc的DataType的枚举中有DateTime,Date,Time三种和时间相关的类型,这里用mini ui自带的时间控件做的扩展,使用的时候只需要结合属性的DateTypeAttribute和
    Html.EditFor即可。

    DateTime扩展

    @model DateTime
    @{
        DateTime value = DateTime.Now;
        if (Model != DateTime.MinValue)
        {
            value=Model ;
        }
    }
    @Html.TextBox("", value, new { @class = "mini-datepicker", format = "yyyy-MM-dd H:mm:ss", timeFormat = "H:mm:ss", showTime = "true" ,width=165})
    

     Date扩展

    @model DateTime
    @{
        DateTime value = DateTime.Now;
        if (Model != DateTime.MinValue)
        {
            value = Model;
        }
    }
    @Html.TextBox("", value, new { @class = "mini-datepicker", format = "yyyy-MM-dd", showTime = "false" })
    

     Time扩展

    @model DateTime
    @{
        DateTime value = DateTime.Now;
        if (Model != DateTime.MinValue)
        {
            value = Model;
        }
    }
    @Html.TextBox(ViewData.ModelMetadata.PropertyName, value, new { @class = "mini-timespinner", format = "H:mm:ss" })
    

    菜单的设计

    菜单的数据结构

    首先看看整体的压面布局,分为顶栏,左边菜单,右边内容,底部关于这种布局。上边部分就很简单,给出用户信息和登出操作就好了。这里我使用miniui自带的树形控件做的菜单,结合样式miniui自带样式就可以简洁的实现如图的效果

    菜单加载就用miniui的tree就很方便了,用Identify和ParentId作为父子关系即可,其中parent属性忽略掉。

    var tree = mini.get("leftTree");
    tree.loadList(data.Data, "Identify", "ParentId");
    两行js语句即可
    
    public class MenuModel : IViewModel
      {
          /// <summary>
          ///     标识
          /// </summary>
          public string Identify { get; set; }
    
          /// <summary>
          ///     标题
          /// </summary>
          public string Text { get; set; }
    
          /// <summary>
          ///     父节点
          /// </summary>
          [JsonIgnore]
          public MenuModel Parent { get; set; }
    
          /// <summary>
          ///     父节点标识
          /// </summary>
          public string ParentId { get; set; }
    
          /// <summary>
          ///     链接
          /// </summary>
          public string Url { get; set; }
    
          /// <summary>
          ///     等级
          /// </summary>
          public int Level
          {
              get
              {
                  if (Parent == null)
                      return 0;
                  return Parent.Level + 1;
              }
          }
    
          /// <summary>
          ///     子节点
          /// </summary>
          public List<MenuModel> Children { get; set; }
    
          public long Id { get; set; }
      }
    

    菜单的服务

    using System.Collections.Generic;
    using HCC.Core.ViewModel;
    
    namespace HCC.Core.Services
    {
        public interface IMenuService
        {
            /// <summary>
            ///     根节点
            /// </summary>
            MenuModel Root { get; }
    
            /// <summary>
            ///     菜单注册
            /// </summary>
            /// <param name="menuName">菜单名称</param>
            /// <param name="url">页面地址</param>
            /// <param name="parentId">上级菜单</param>
            /// <param name="menuId">菜单Id</param>
            MenuModel Regist(string menuName, string url, string parentId, string menuId);
    
            /// <summary>
            ///     菜单注册
            /// </summary>
            /// <param name="menuName">菜单名称</param>
            /// <param name="url">页面地址</param>
            /// <param name="parentId">上级菜单</param>
            /// <param name="menuId">菜单Id</param>
            MenuModel Regist(string menuName, string url, string parentId);
    
            /// <summary>
            ///     注销菜单
            /// </summary>
            /// <param name="menuId"></param>
            /// <returns></returns>
            MenuModel Unregist(string menuId);
    
            /// <summary>
            ///     根据菜单ID获取菜单
            /// </summary>
            /// <param name="menuId"></param>
            /// <returns></returns>
            MenuModel FindById(string menuId);
    
            /// <summary>
            ///     获取子菜单
            /// </summary>
            /// <returns></returns>
            List<MenuModel> GetChildrenMenus(string parentId);
    
            /// <summary>
            ///     根据级别获取菜单
            /// </summary>
            /// <returns></returns>
            List<MenuModel> GetByLevel(List<int> levels);
    
            /// <summary>
            ///     获取全部菜单
            /// </summary>
            /// <returns></returns>
            List<MenuModel> GetAll();
    
            /// <summary>
            ///     重新注册菜单
            /// </summary>
            void ResetMenu();
        }
    }
    

    注意其中菜单服务这里,可以订阅eventbus事件来动态更新菜单

    using System.Collections.Generic;
    using System.Linq;
    using Coralcode.Framework.Aspect;
    using Coralcode.Framework.Data.Repository.Core;
    using Coralcode.Framework.Data.Specification;
    using Coralcode.Framework.Mapper;
    using Coralcode.Framework.MessageBus.Event;
    using Coralcode.Framework.Services;
    using Coralcode.Framework.Utils;
    using HCC.Core.Model;
    using HCC.Core.ViewModel;
    
    namespace HCC.Core.Services.Imp
    {
        [Inject(RegisterType = typeof (IMenuService), LifetimeManagerType = LifetimeManagerType.ContainerControlled)]
        public class MenuService : CrudCoralService<Menu, MenuModel>, IMenuService
        {
            internal static Dictionary<string, MenuModel> MenuCache = new Dictionary<string, MenuModel>();
    
            public MenuService(IRepository<Menu> repository, IEventBus eventBus)
                : base(repository, eventBus)
            {
                Root = new MenuModel
                {
                    Identify = "root",
                    Text = "后台管理",
                    Url = "",
                    Children = new List<MenuModel>(),
                    Parent = null
                };
                MenuCache.Add(Root.Identify, Root);
                var allMenus = Repository.GetAll().ToList();
                allMenus.ForEach(item => { Regist(item.Text, item.Url, item.ParentId, item.Identify); });
            }
    
            /// <summary>
            ///     根节点
            /// </summary>
            public MenuModel Root { get; private set; }
    
            public MenuModel Regist(string menuName, string url, string parentId, string menuId)
            {
                if (MenuCache.ContainsKey(menuId))
                    return MenuCache[menuId];
                if (string.IsNullOrEmpty(parentId) || !MenuCache.ContainsKey(parentId))
                    return null;
    
                var menu = new MenuModel
                {
                    Identify = menuId,
                    Text = menuName,
                    Url = url,
                    Children = new List<MenuModel>(),
                    ParentId = parentId,
                    Parent = MenuCache[parentId]
                };
    
                AddMenu(menu);
                MenuCache.Add(menu.Identify, menu);
                MenuCache[parentId].Children.Add(menu);
                return menu;
            }
    
            public MenuModel Regist(string menuName, string url, string parentId)
            {
                return Regist(menuName, url, parentId, GeneralMenuId(parentId, menuName));
            }
    
            public MenuModel Unregist(string menuId)
            {
                MenuModel model;
                if (!MenuCache.TryGetValue(menuId, out model))
                    return null;
                model.Parent.Children.Remove(model);
                UnregistChildren(model);
                Repository.UnitOfWork.Commit();
                return model;
            }
    
            public MenuModel FindById(string menuId)
            {
                return !MenuCache.ContainsKey(menuId) ? null : MenuCache[menuId];
            }
    
            public List<MenuModel> GetChildrenMenus(string parentId)
            {
                if (string.IsNullOrEmpty(parentId))
                    return DataMapperProvider.Mapper.Convert<List<MenuModel>, List<MenuModel>>(Root.Children);
                if (MenuCache.ContainsKey(parentId))
                    return DataMapperProvider.Mapper.Convert<List<MenuModel>, List<MenuModel>>(MenuCache[parentId].Children);
                return null;
            }
    
            public List<MenuModel> GetByLevel(List<int> levels)
            {
                return MenuCache.Values.Where(item => levels.Contains(item.Level)).ToList();
            }
    
            /// <summary>
            ///     重新注册菜单
            /// </summary>
            public void ResetMenu()
            {
                //删掉之前的菜单
                var menus = Repository.GetAll().ToList();
                if (menus.Count != 0)
                {
                    menus.ForEach(item => { Repository.Remove(item); });
                    Repository.UnitOfWork.CommitAndRefreshChanges();
                    MenuCache.Clear();
                    MenuCache.Add(Root.Identify, Root);
                }
    
    
                //课程管理
                var lessonMenu = Regist("课程管理", "", "root", "lessonmanager");
                Regist("私教课", "/portal/privatelesson/index", lessonMenu.Identify, "privatelesson");
                Regist("公开课", "/portal/publiclesson/index", lessonMenu.Identify, "publiclesson");
                Regist("体验课", "/portal/triallesson/index", lessonMenu.Identify, "triallesson");
                Regist("会员活动", "/portal/useractivity/index", lessonMenu.Identify, "useractivity");
    
    
                //人员管理
                var userManagerMenu = Regist("人员管理", "", "root", "personmanager");
    
                Regist("教练", "/portal/coach/index", userManagerMenu.Identify, "coachmanager");
    
                Regist("人员", "/portal/user/index", userManagerMenu.Identify, "usermanager");
                //系统管理
                var systemManagerMenu = Regist("系统管理", "", "root", "systemmanager");
    
                Regist("管理员", "/portal/manager/index", systemManagerMenu.Identify, "manager");
                Regist("新闻管理", "/portal/news/index", systemManagerMenu.Identify, "news");
                Regist("留言管理", "/portal/message/index", systemManagerMenu.Identify, "message");
                Regist("课程模板", "/portal/lessontemplate/index", systemManagerMenu.Identify, "lessontemplate");
                Regist("系统设置", "/portal/systemsetting/index", systemManagerMenu.Identify, "systemsetting");
                //统计查询
                var stasticsMenu = Regist("统计", "", "root", "systemstastistics");
                Regist("统计", "/portal/statistic/index", stasticsMenu.Identify, "stastistics");
            }
    
            private void UnregistChildren(MenuModel menu)
            {
                menu.Children.ForEach(item =>
                {
                    if (MenuCache.ContainsKey(item.Identify))
                        RemoveMenu(item);
                    UnregistChildren(item);
                });
                RemoveMenu(menu);
            }
    
            private void AddMenu(MenuModel menu)
            {
                if (MenuCache.ContainsKey(menu.Identify))
                    return;
                var model = Repository.GetFirst(new DirectSpecification<Menu>(item => item.Identify == menu.Identify));
                if (model != null)
                    return;
                Repository.Add(Convert(menu));
                Repository.UnitOfWork.Commit();
            }
    
            private void RemoveMenu(MenuModel menu)
            {
                if (MenuCache.ContainsKey(menu.Identify))
                    MenuCache.Remove(menu.Identify);
                var model = Repository.GetFirst(new DirectSpecification<Menu>(item => item.Identify == menu.Identify));
                if (model == null)
                    return;
                Repository.Remove(model);
            }
    
            private string GeneralMenuId(params string[] keys)
            {
                return StringUtil.FormatKey(keys.ToArray());
            }
        }
    }
    

    菜单的缓存

    菜单缓存采用和两种模式一种是根节点的树形模式,一种是字段缓存,这样既可以从树
    去访问,也可以从字典根据key去访问。

    Ps:界面代码比较乱,后面放出demo时候再整理,快了,由于最近确实比较忙,更新比较慢,见谅

  • 相关阅读:
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Python位运算符
  • 原文地址:https://www.cnblogs.com/Skyven/p/5674865.html
Copyright © 2011-2022 走看看