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时候再整理,快了,由于最近确实比较忙,更新比较慢,见谅

  • 相关阅读:
    《软件工程》-第三章随笔
    《软件工程》-第二章随笔
    《软件工程》-第一章随笔
    软件工程——理论、方法与实践③
    软件工程——理论、方法与实践②
    软件工程——理论、方法与实践①
    爬虫之SCRAPY
    爬虫之 App 爬取
    flask bootstrap
    爬虫之协程,selenium
  • 原文地址:https://www.cnblogs.com/Skyven/p/5674865.html
Copyright © 2011-2022 走看看