本次實現欄目的瀏覽、添加、修改和刪除。
欄目一共有三種類型。
- 常規欄目-可以添加子欄目,也可以添加內容模型。當不選擇內容模型時,不能添加內容。
- 單頁欄目-欄目只有一個頁面,可以設置視圖。
- 鏈接欄目-欄目為一個鏈接,點擊后轉到相應鏈接。
在視圖中原本欄目的樹形顯示插件使用Bootstrap TreeView 1.2.0(MVC5 網站開發之六 管理員 2、添加、刪除、重置密碼、修改密碼、列表瀏覽),后來使用中發現zTree使用起來更習慣,所以更換成zTree了。
目錄
MVC5 網站開發之六 管理員 2、添加、刪除、重置密碼、修改密碼、列表瀏覽
一、欄目類型
1、欄目類型枚舉
在Ninesky.Core項目【右鍵】添加文件夾“Category”,在文件夾上【右鍵】添加類“CategoryType”。完成如下代碼
using System.ComponentModel.DataAnnotations; namespace Ninesky.Core.Category { /// <summary> /// 欄目類型 /// </summary> public enum CategoryType { /// <summary> /// 常規欄目 /// </summary> [Display(Name = "常規欄目", Description = "可以添加內容,不能添加子欄目")] General, /// <summary> /// 單頁欄目 /// </summary> [Display(Name = "單頁欄目", Description = "僅有一個頁面的欄目")] Page, /// <summary> /// 外部鏈接 /// </summary> [Display(Name = "外部鏈接", Description = "點擊跳轉到指定鏈接")] Link } }
2、枚舉的詳細信息類
此類有Text、Value、Name、Description四個屬性,分別代表枚舉的字符串形式、枚舉值、標注名稱、標注詳細說明。前兩個是枚舉的固有屬性,后兩個通過添加[Display(Name = "", Description = "")]為枚舉添加這兩個屬性,主要目的方便枚舉的中文顯示。
Ninesky.Auxiliary【右鍵】->添加->類,輸入類名EnumItemDetails
namespace Ninesky.Auxiliary { /// <summary> /// 枚舉詳細信息 /// </summary> public class EnumItemDetails { /// <summary> /// 枚舉的字符串形式 /// </summary> public string Text { get; set; } /// <summary> /// 枚舉值 /// </summary> public int Value { get; set; } /// <summary> /// 標注名稱 /// </summary> public string Name { get; set; } /// <summary> /// 標注詳細說明 /// </summary> public string Description { get; set; } } }
3、枚舉轉換為詳細信息列表方法
Ninesky.Auxiliary【右鍵】->添加->類,輸入類名Convert
在類中引入命名空間 System.ComponentModel.DataAnnotations和 using System.Reflection
添加EnumToDetailsList靜態方法,將枚舉轉換為詳細信息列表
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Reflection; namespace Ninesky.Auxiliary { /// <summary> /// 轉換類 /// </summary> public class Convert { /// <summary> /// 轉換枚舉類型為詳細信息列表 /// </summary> /// <param name="_enum">枚舉類型</param> /// <returns></returns> public static List<EnumItemDetails> EnumToDetailsList(Enum _enum) { List<EnumItemDetails> _itemDetails = new List<EnumItemDetails>(); //字段元數據 FieldInfo _fileInfo; //顯示屬性 DisplayAttribute _displayAttribute; foreach (var _item in Enum.GetValues(_enum.GetType())) { try { _fileInfo = _item.GetType().GetField(_item.ToString()); _displayAttribute = (DisplayAttribute)_fileInfo.GetCustomAttribute(typeof(DisplayAttribute)); if (_displayAttribute != null) _itemDetails.Add(new EnumItemDetails() { Text = _item.ToString(), Value = (int)_item, Name = _displayAttribute.Name, Description = _displayAttribute.Description }); else _itemDetails.Add(new EnumItemDetails() { Text = _item.ToString(), Value = (int)_item }); } catch { _itemDetails.Add(new EnumItemDetails() { Text = _item.ToString(), Value = (int)_item }); } } return _itemDetails; } } }
二、欄目模型類
1、共有信息模型
Ninesky.Core/Category【右鍵】->添加->類,輸入類名Category。
引入命名空間System.ComponentModel.DataAnnotations和System.ComponentModel.DataAnnotations.Schema
using System.ComponentModel.DataAnnotations; namespace Ninesky.Core.Category { /// <summary> /// 欄目模型類 /// </summary> public class Category { [Key] public int CategoryID { get; set; } /// <summary> /// 欄目類型 /// </summary> [Required(ErrorMessage = "{0}必填")] [Display(Name = "欄目類型")] public CategoryType Type { get; set; } /// <summary> /// 父欄目ID /// </summary> [Required(ErrorMessage = "{0}必填")] [Display(Name = "父欄目")] public int ParentID { get; set; } /// <summary> /// 父欄目路徑格式【0,……,父欄目ID】 /// </summary> [Display(Name = "父欄目路徑")] public string ParentPath { get; set; } /// <summary> /// 深度【表示欄目所處層次,根欄目為0,依次類推】 /// </summary> [Required()] [Display(Name = "深度")] public int Depth { get; set; } /// <summary> /// 欄目名稱 /// </summary> [Required(ErrorMessage = "{0}必填")] [StringLength(50, ErrorMessage ="必須少于{1}個字")] [Display(Name = "欄目名稱")] public string Name { get; set; } /// <summary> /// 欄目說明 /// </summary> [DataType(DataType.MultilineText)] [StringLength(1000, ErrorMessage = "必須少于{1}個字")] [Display(Name = "欄目說明")] public string Description { get; set; } /// <summary> /// 欄目排序【同級欄目數字越小越靠前】 /// </summary> [Display(Name = "欄目排序")] public int Order { get; set; } /// <summary> /// 打開方式 /// </summary> [Display(Name = "打開方式")] public string Target { get; set; } } }
2、常規欄目模型
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryGeneral。
using System.ComponentModel.DataAnnotations; namespace Ninesky.Core.Category { /// <summary> /// 常規欄目 /// </summary> public class CategoryGeneral { [Key] public int CategoryGeneralID { get; set; } /// <summary> /// 欄目ID /// </summary> [Required()] [Display(Name ="欄目ID")] public int CategoryID { get; set; } /// <summary> /// 欄目視圖 /// </summary> [Required()] [Display(Name = "欄目視圖")] public string View { get; set; } /// <summary> /// 內容類型ID【0時表示此欄目無內容模型,不能添加內容】 /// </summary> [Required()] [Display(Name = "內容類型")] public int ContentTypeID { get; set; } /// <summary> /// 欄目視圖 /// </summary> [Display(Name = "內容視圖")] public string ContentView { get; set; } } }
3、單頁欄目模型
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryPage。
using System.ComponentModel.DataAnnotations; namespace Ninesky.Core.Category { /// <summary> /// 單頁欄目模型 /// </summary> public class CategoryPage { [Key] public int CategoryPageID { get; set; } /// <summary> /// 欄目ID /// </summary> [Required(ErrorMessage = "{0}必填")] [Display(Name = "欄目ID")] public int CategoryID { get; set; } /// <summary> /// 欄目視圖 /// </summary> [Required(ErrorMessage = "{0}必填")] [StringLength(255, ErrorMessage = "必須少于{1}個字")] [Display(Name = "欄目視圖")] public string View { get; set; } } }
4、鏈接欄目模型
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryLink。
using System.ComponentModel.DataAnnotations; namespace Ninesky.Core.Category { /// <summary> /// 外部鏈接欄目模型 /// </summary> public class CategoryLink { [Key] public int CategoryLinkID { get; set; } /// <summary> /// 欄目ID /// </summary> [Required(ErrorMessage = "{0}必填")] [Display(Name = "欄目ID")] public int CategoryID { get; set; } /// <summary> /// 鏈接地址 /// </summary> [Required(ErrorMessage = "{0}必填")] [StringLength(255, ErrorMessage = "必須少于{1}個字")] [Display(Name = "鏈接地址")] public string Url { get; set; } } }
三、欄目管理類
1、共有信息管理類
Ninesky.Core/Category【右鍵】->添加->類,輸入類CategoryManager
從類圖中可以看出,該有有添加、查找子欄目、查找欄目列表、查找欄目路徑、查找根欄目和更新欄目等方法。沒有刪除是因為刪除方法在基類中就實現了。
添加方法
添加欄目有3個重載,分別用于添加常規欄目,添加單頁欄目,添加鏈接欄目。第一個不帶參數會在方法中new一個CategoryGeneral出來并調用第二個方法。
更新方法
更新有2個重載,分別用于三種欄目的更新。
整個類的代碼如下:
using Ninesky.Auxiliary; using System.Collections.Generic; using System.Linq; namespace Ninesky.Core.Category { /// <summary> /// 欄目管理 /// </summary> public class CategoryManager : BaseManager<Category> { #region 添加欄目 /// <summary> /// 添加欄目【Code:2-常規欄目信息不完整,3-單頁欄目信息不完整,4-鏈接欄目信息不完整,5-欄目類型不存在】 /// </summary> /// <param name="category">欄目數據【包含欄目類型對應數據】</param> /// <returns></returns> public override Response Add(Category category) { return Add(category, new CategoryGeneral() { CategoryID = category.CategoryID, ContentView = "Index", View = "Index" }); } /// <summary> /// 添加欄目 /// </summary> /// <param name="category">基本信息</param> /// <param name="general">常規欄目信息</param> /// <returns></returns> public Response Add(Category category,CategoryGeneral general) { Response _response = new Response() { Code = 1 }; _response = base.Add(category); general.CategoryID = category.CategoryID; var _generalManager = new CategoryGeneralManager(); _generalManager.Add(general); return _response; } /// <summary> /// 添加欄目 /// </summary> /// <param name="category">基本信息</param> /// <param name="page">單頁欄目信息</param> /// <returns></returns> public Response Add(Category category, CategoryPage page) { Response _response = new Response() { Code = 1 }; _response = base.Add(category); page.CategoryID = category.CategoryID; var _pageManager = new CategoryPageManager(); _pageManager.Add(page); return _response; } /// <summary> /// 添加欄目 /// </summary> /// <param name="category">基本信息</param> /// <param name="link">鏈接欄目信息</param> /// <returns></returns> public Response Add(Category category, CategoryLink link) { Response _response = new Response() { Code = 1 }; _response = base.Add(category); link.CategoryID = category.CategoryID; var _linkManager = new CategoryLinkManager(); _linkManager.Add(link); return _response; } #endregion #region 更新欄目 /// <summary> /// 更新欄目 /// </summary> /// <param name="category">欄目</param> /// <param name="general">常規信息</param> /// <returns></returns> public Response Update(Category category, CategoryGeneral general) { Response _response = new Response() { Code = 1 }; _response = base.Update(category); if (_response.Code == 1) { general.CategoryID = category.CategoryID; var _generalManager = new CategoryGeneralManager(); if(general.CategoryGeneralID ==0) _response = _generalManager.Add(general); else _response = _generalManager.Update(general); } if (_response.Code == 1) _response.Message = "更新欄目成功!"; return _response; } /// <summary> /// 更新欄目 /// </summary> /// <param name="category">欄目</param> /// <param name="page">單頁信息</param> /// <returns></returns> public Response Update(Category category, CategoryPage page) { Response _response = new Response() { Code = 1 }; _response = base.Update(category); if (_response.Code == 1) { page.CategoryID = category.CategoryID; var _pageManager = new CategoryPageManager(); if(page.CategoryPageID ==0) _response = _pageManager.Add(page); else _response = _pageManager.Update(page); } if (_response.Code == 1) _response.Message = "更新欄目成功!"; return _response; } /// <summary> /// 更新欄目 /// </summary> /// <param name="category">欄目</param> /// <param name="link">鏈接信息</param> /// <returns></returns> public Response Update(Category category, CategoryLink link) { Response _response = new Response() { Code = 1 }; _response = base.Update(category); if (_response.Code == 1) { link.CategoryID = category.CategoryID; var _linkManager = new CategoryLinkManager(); if(link.CategoryLinkID == 0) _response = _linkManager.Add(link); else _response = _linkManager.Update(link); } if (_response.Code == 1) _response.Message = "更新欄目成功!"; return _response; } #endregion /// <summary> /// 查找子欄目 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public List<Category> FindChildren(int id) { return Repository.FindList(c => c.ParentID == id, new OrderParam() { Method = OrderMethod.ASC, PropertyName = "Order" }).ToList(); } /// <summary> /// 查找根欄目 /// </summary> /// <returns></returns> public List<Category> FindRoot() { return FindChildren(0); } /// <summary> /// 查找欄目路徑 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public List<Category> FindPath(int id) { List<Category> _categories = new List<Category>(); var _category = Find(id); while (_category != null) { _categories.Insert(0, _category); _category = Find(_category.ParentID); } return _categories; } /// <summary> /// 查找列表 /// </summary> /// <param name="number">返回數量【0-全部】</param> /// <param name="type">欄目類型【null 全部】</param> /// <param name="orderParams">【排序參數】</param> /// <returns></returns> public List<Category> FindList(int number, CategoryType? type,OrderParam[] orderParams) { List<Category> _categories; if (orderParams == null) orderParams = new OrderParam[] { new OrderParam() { Method = OrderMethod.ASC, PropertyName = "ParentPath" }, new OrderParam() { Method = OrderMethod.ASC, PropertyName = "Order" } }; if (type == null) _categories = base.Repository.FindList(c => true, orderParams, number).ToList(); else _categories = base.Repository.FindList(c => c.Type == type, orderParams, number).ToList(); return _categories; } }
2、常規欄目
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryGeneralManager。類里只有一個方法,根據欄目id刪除常規欄目,其他兩個重載也類似。
using Ninesky.Auxiliary; namespace Ninesky.Core.Category { /// <summary> /// 常規欄目管理 /// </summary> public class CategoryGeneralManager : BaseManager<CategoryGeneral> { /// <summary> /// 刪除常規欄目-根據欄目ID /// </summary> /// <param name="categoryID">欄目ID</param> /// <returns></returns> public Response DeleteByCategoryID(int categoryID) { return base.Delete(cg => cg.CategoryID == categoryID); } } }
3、單頁欄目
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryPageManager 。
using Ninesky.Auxiliary; namespace Ninesky.Core.Category { /// <summary> /// 單頁欄目管理 /// </summary> public class CategoryPageManager : BaseManager<CategoryPage> { /// <summary> /// 刪除單頁欄目-根據欄目ID /// </summary> /// <param name="categoryID">欄目ID</param> /// <returns></returns> public Response DeleteByCategoryID(int categoryID) { return base.Delete(cp=> cp.CategoryID == categoryID); } } }
4、鏈接欄目
Ninesky.Core/Category【右鍵】->添加->類,輸入類名CategoryLinkManager。
using Ninesky.Auxiliary; namespace Ninesky.Core.Category { /// <summary> /// 鏈接欄目管理 /// </summary> public class CategoryLinkManager : BaseManager<CategoryLink> { /// <summary> /// 刪除鏈接欄目-根據欄目ID /// </summary> /// <param name="categoryID">欄目ID</param> /// <returns></returns> public Response DeleteByCategoryID(int categoryID) { return base.Delete(cl => cl.CategoryID == categoryID); } } }
四、欄目效果的實現
Ninesky.Web/Areas/Control/Controllers【右鍵】->添加->控制器,輸入控制器名CategoryController。
添加私有變量CategoryManager categoryManager,并在構造函數中初始化。
using Ninesky.Auxiliary; using Ninesky.Core.Category; using Ninesky.Core.Content; using Ninesky.Web.Models; using System.Collections.Generic; using System.Web.Mvc; namespace Ninesky.Web.Areas.Control.Controllers { /// <summary> /// 欄目控制器 /// </summary> [AdminAuthorize] public class CategoryController : Controller { private CategoryManager categoryManager; public CategoryController() { categoryManager = new CategoryManager(); } }
1、左側樹形列表
在控制器中添加Tree方法
/// <summary> /// 樹形節點數據 /// </summary> /// <returns></returns> public ActionResult Tree(bool showIcon=false) { List<TreeNode> _nodes = new List<TreeNode>(); //欄目并進行排序使最深的節點排在最前 var _categories = categoryManager.FindList(0, null, new OrderParam[] { new OrderParam() { Method = OrderMethod.ASC, PropertyName = "ParentPath" }, new OrderParam() { Method = OrderMethod.ASC, PropertyName = "Order" } }); TreeNode _node; //遍歷常規欄目 foreach (var _category in _categories) { _node = new TreeNode() { pId = _category.ParentID, id = _category.CategoryID, name = _category.Name, url = Url.Action("Modify", "Category", new { id = _category.CategoryID }) }; if (showIcon) { switch (_category.Type) { case CategoryType.General: _node.icon = Url.Content("~/Content/Images/folder.png"); break; case CategoryType.Page: _node.icon = Url.Content("~/Content/Images/page.png"); break; case CategoryType.Link: _node.icon = Url.Content("~/Content/Images/link.png"); break; } } _nodes.Add(_node); } return Json(_nodes); }
在Ninesky.Web/Areas/Control/Views/Category/[右鍵] 添加視圖-視圖名稱為SideNavPartialView,類型為分部視圖
<div class="panel panel-default"> <div class="panel-heading"> <div class="panel-title"><span class="glyphicon glyphicon-lock"></span> 欄目列表</div> </div> <div class="panel-body"> <ul id="categorytree" class="ztree" style="margin:0;padding:0"></ul> </div> </div> <script type="text/javascript"> $(document).ready(function () { //父欄目選擇框 zTree var zTreeCategory; // zTree 的參數配置 var setting = { data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId", rootPId: 0 }, key: { name: "name" } } }; $.post("@Url.Action("Tree", "Category",new { showIcon=true })", null, function (data) { zTreeCategory = $.fn.zTree.init($("#categorytree"), setting, data); }, "json"); }); </script>
2、添加欄目
添加欄目界面如下圖:
視圖中有兩個標簽:“基本資料”標簽顯示欄目的共有信息(Category類),“高級設置”標簽顯示欄目附加信息(根據欄目類型顯示常規、單頁或鏈接欄目信息)。這里一共涉及4個視圖。
- 欄目類型選擇框數據
在在CategoryController添加Add方法public ActionResult DropdownTree(),該方法返回Json類型可以做父欄目的欄目樹。
/// <summary> /// 下拉樹【常規欄目】 /// </summary> /// <returns></returns> public ActionResult DropdownTree() { //欄目并進行排序使最深的節點排在最前 var _categories = categoryManager.FindList(0, CategoryType.General, new OrderParam[] { new OrderParam() { Method = OrderMethod.ASC, PropertyName = "ParentPath" }, new OrderParam() { Method = OrderMethod.ASC, PropertyName = "Order" } }); List<TreeNode> _nodes = new List<TreeNode>(); //遍歷常規欄目 foreach (var _category in _categories) { _nodes.Add(new TreeNode() { pId = _category.ParentID, id = _category.CategoryID, name = _category.Name }); } return Json(_nodes); }
- 欄目共有信息(頁面視圖)
在CategoryController添加Add方法,返回頁面視圖
/// <summary> /// 添加欄目 /// </summary> /// <param name="id">父欄目ID</param> /// <returns></returns> public ActionResult Add(int? id) { Category _category = new Category() { ParentID = 0 }; if (id != null && id>0 ) { var _parent = categoryManager.Find((int)id); if (_parent != null && _parent.Type == CategoryType.General) _category.ParentID = (int)id; } return View(_category); }
右鍵添加視圖,模型選擇Category
@model Ninesky.Core.Category.Category @{ ViewBag.Title = "添加欄目"; } @section SideNav{@Html.Partial("SideNavPartialView")} <ol class="breadcrumb"> <li><span class="glyphicon glyphicon-home"></span> @Html.ActionLink("首頁", "Index", "Home")</li> <li>@Html.ActionLink("欄目管理", "Index", "Category")</li> <li class="active">添加欄目</li> </ol> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> @Html.ValidationSummary(false, "", new { @class = "text-danger" }) <ul id="myTabs" class="nav nav-tabs" role="tablist"> <li role="presentation"><a href="#base" role="tab" data-toggle="tab" aria-controls="base">基本資料</a></li> <li id="tabadvanced" role="presentation"><a href="#advanced" role="tab" data-toggle="tab" aria-controls="advanced">高級設置</a></li> </ul> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="base"> <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.ParentID, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.HiddenFor(model => model.ParentID) <div class="input-group" style="width:280px"> <input id="ParentName" type="text" class="form-control" readonly /> <ul class="dropdown-menu dropdown-menu-left ztree" style="display:none;width:100%" id="parenttree"></ul> <div class="input-group-btn open"> <button id="btn-CategoryID" type="button" class="btn btn-default"><span class="caret"></span></button> </div> </div> @Html.ValidationMessageFor(model => model.ParentID, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Type, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EnumDropDownListFor(model => model.Type, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Type, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Order, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Order, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Order, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Target, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Target, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Target, "", new { @class = "text-danger" }) </div> </div> </div> <div role="tabpanel" class="tab-pane" id="advanced"> 1 </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="保存" class="btn btn-default" /> </div> </div> </div> } <script type="text/javascript"> //顯示隱藏標簽頁 function showTabBySelect() { switch ($("#Type").find("option:selected").text()) { case "常規欄目": $("#advanced").load("@Url.Action("AddGeneral")"); break; case "單頁欄目": $("#advanced").load("@Url.Action("AddPage")"); break; case "外部鏈接": $("#advanced").load("@Url.Action("AddLink")"); break; } } $(document).ready(function () { showTabBySelect(); $("#Type").change(function () { showTabBySelect(); }); //父欄目選擇框 zTree var zTreeObj; // zTree 的參數配置 var setting = { data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId", rootPId: 0 }, key: { name: "name" } }, callback: { onClick: function (event, treeId, treeNode) { $("#ParentID").val(treeNode.id); $("#ParentName").val(treeNode.name); $("#parenttree").slideUp(); } } }; // zTree 的數據屬性, $.post("@Url.Action("DropdownTree")", null, function (data) { zTreeObj = $.fn.zTree.init($("#parenttree"), setting, data); var newNode = { name: "無", id: "0", pId: "-1" }; newNode = zTreeObj.addNodes(null, 0, newNode); var node = zTreeObj.getNodeByParam("id", $("#ParentID").val(), null); if (node != null) { $("#ParentName").val(node.name); zTreeObj.selectNode(node); } }, "json"); }); $("#btn-CategoryID").click(function () { $("#parenttree").slideDown(); }); //父欄目選擇框 zTree </script>
- 常規欄目(分部視圖)
在控制器中添加“AddGeneral”方法,返回分部視圖。方法中通過ViewBag.ContentTypeItems向前臺傳遞內容類型列表
/// <summary> /// 常規欄目信息 /// </summary> /// <returns></returns> public ActionResult AddGeneral() { var _general = new CategoryGeneral() { ContentView="Index", View="Index" }; List<SelectListItem> _contentTypeItems = new List<SelectListItem>() { new SelectListItem() { Value = "0", Text = "無", Selected = true } }; ContentTypeManager _contentTypeManager = new ContentTypeManager(); var _contentTypes = _contentTypeManager.FindList(); foreach(var contentType in _contentTypes) { _contentTypeItems.Add(new SelectListItem() { Value= contentType.ContentTypeID.ToString(), Text= contentType.Name }); } ViewBag.ContentTypeItems = _contentTypeItems; return PartialView(_general); }
右鍵添加視圖,模型CategoryGeneral,分部視圖
@model Ninesky.Core.Category.CategoryGeneral <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.View, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.View, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.View, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ContentTypeID, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.DropDownListFor(model => model.ContentTypeID,(IEnumerable<SelectListItem>)ViewBag.ContentTypeItems, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.ContentTypeID, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ContentView, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.ContentView, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ContentView, "", new { @class = "text-danger" }) </div> </div>
- 單頁欄目的(分部視圖)
同常規欄目,代碼如下
/// <summary> /// 添加單頁欄目 /// </summary> /// <returns></returns> public ActionResult AddPage() { var _page = new CategoryPage() { View="Index" }; return PartialView(_page); }
@model Ninesky.Core.Category.CategoryPage <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.View, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.View, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.View, "", new { @class = "text-danger" }) </div> </div>
- 鏈接欄目的分部視圖
同上,代碼如下:
/// <summary> /// 添加外部鏈接 /// </summary> /// <returns></returns> public ActionResult AddLink() { var _link = new CategoryLink() { Url="http://" }; return PartialView(_link); }
@model Ninesky.Core.Category.CategoryLink <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.Url, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Url, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Url, "", new { @class = "text-danger" }) </div> </div>
這幾個action代碼都很簡單,只有在AddGeneral中進行了內容內容類型的查詢
然后實現添加欄目后臺處理代碼
[HttpPost] [ValidateAntiForgeryToken()] public ActionResult Add() { Category _category = new Category(); if (TryUpdateModel(_category, new string[] { "Type", "ParentID", "Name", "Description", "Order", "Target" })) { //檢查父欄目 if (_category.ParentID > 0) { var _parentCategory = categoryManager.Find(_category.ParentID); if (_parentCategory == null) ModelState.AddModelError("ParentID", "父欄目不存在,請刷新后重新添加"); else if (_parentCategory.Type != CategoryType.General) ModelState.AddModelError("ParentID", "父欄目不允許添加子欄目"); else { _category.ParentPath = _parentCategory.ParentPath + "," + _parentCategory.CategoryID; _category.Depth = _parentCategory.Depth + 1; } } else { _category.ParentPath = "0"; _category.Depth = 0; } //欄目基本信息保存 Response _response = new Auxiliary.Response() { Code = 0, Message = "初始失敗信息" }; //根據欄目類型進行處理 switch (_category.Type) { case CategoryType.General: var _general = new CategoryGeneral(); TryUpdateModel(_general); _response = categoryManager.Add(_category, _general); break; case CategoryType.Page: var _page = new CategoryPage(); TryUpdateModel(_page); _response = categoryManager.Add(_category, _page); break; case CategoryType.Link: var _link = new CategoryLink(); TryUpdateModel(_link); _response = categoryManager.Add(_category, _link); break; } if (_response.Code == 1) return View("Prompt", new Ninesky.Web.Models.Prompt() { Title = "添加欄目成功", Message = "添加欄目【" + _category.Name + "】成功" }); else return View("Prompt", new Ninesky.Web.Models.Prompt() { Title = "添加失敗", Message = "添加欄目【" + _category.Name + "】時發生系統錯誤,未能保存到數據庫,請重試" }); } return View(_category); }
方法中使用TryUpdateModel根據需要的字段綁定模型,然后判斷父欄目是否存在、是否可以添加子欄目。最后根據欄目類型使用TryUpdateModel綁定常規欄目,單頁欄目或鏈接欄目信息并保存到數據庫。
3、修改欄目
修改欄目和添加欄目方式基本類似,這里只貼代碼。注意后臺處理時相比添加處理方法要驗證選擇地父欄目是否是其本身或其子欄目。
#region 修改 /// <summary> /// 修改 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public ActionResult Modify(int id) { var _category = categoryManager.Find(id); if (_category == null) return View("Prompt", new Prompt() { Title="錯誤", Message="欄目不存在!" }); return View(_category); } /// <summary> /// 修改 /// </summary> /// <returns></returns> [HttpPost] [ValidateAntiForgeryToken] public ActionResult Modify(int id, FormCollection form) { Category _category = categoryManager.Find(id); if (_category == null) return View("Prompt", new Prompt() { Title = "錯誤", Message = "欄目不存在!" }); if(TryUpdateModel(_category, new string[] { "Type", "ParentID", "Name", "Description", "Order", "Target" })) { //檢查父欄目 if (_category.ParentID > 0) { var _parentCategory = categoryManager.Find(_category.ParentID); if (_parentCategory == null) ModelState.AddModelError("ParentID", "父欄目不存在,請刷新后重新添加"); else if (_parentCategory.Type != CategoryType.General) ModelState.AddModelError("ParentID", "父欄目不允許添加子欄目"); else if(_parentCategory.ParentPath.IndexOf(_category.ParentPath)>=0) ModelState.AddModelError("ParentID", "父欄目不能是其本身或其子欄目"); else { _category.ParentPath = _parentCategory.ParentPath + "," + _parentCategory.CategoryID; _category.Depth = _parentCategory.Depth + 1; } } else { _category.ParentPath = "0"; _category.Depth = 0; } //欄目基本信息保存 Response _response = new Auxiliary.Response() { Code = 0, Message = "初始失敗信息" }; //根據欄目類型進行處理 switch (_category.Type) { case CategoryType.General: var _generalManager = new CategoryGeneralManager(); var _general = _generalManager.Find(g=>g.CategoryID == id); if (_general == null) _general = new CategoryGeneral() { CategoryID = id, View = "Index", ContentView = "Index" }; if(TryUpdateModel(_general)) _response = categoryManager.Update(_category, _general); break; case CategoryType.Page: var _pageManager = new CategoryPageManager(); var _page = _pageManager.Find(p => p.CategoryID == id); if (_page == null) _page = new CategoryPage() { CategoryID = id, View = "index" }; if (TryUpdateModel(_page)) _response = categoryManager.Update(_category, _page); break; case CategoryType.Link: var _linkManager = new CategoryLinkManager(); var _link = _linkManager.Find(l => l.CategoryID == id); if (_link == null) _link = new CategoryLink() { CategoryID = id, Url = "http://" }; if(TryUpdateModel(_link))_response = categoryManager.Update(_category, _link); break; } if (ModelState.IsValid) { if (_response.Code == 1) return View("Prompt", new Ninesky.Web.Models.Prompt() { Title = "修改欄目成功", Message = "修改欄目【" + _category.Name + "】成功" }); else return View("Prompt", new Ninesky.Web.Models.Prompt() { Title = "修改欄目失敗", Message = "修改欄目【" + _category.Name + "】時發生系統錯誤,未能保存到數據庫,請重試" }); } } return View(_category); } /// <summary> /// 常規欄目 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public ActionResult ModifyGeneral(int id) { List<SelectListItem> _contentTypeItems = new List<SelectListItem>() { new SelectListItem { Text = "無", Value = "0" } }; ContentTypeManager _contentTypeManager = new ContentTypeManager(); var _contentTypes = _contentTypeManager.FindList(); foreach (var contentType in _contentTypes) { _contentTypeItems.Add(new SelectListItem() { Value = contentType.ContentTypeID.ToString(), Text = contentType.Name }); } ViewBag.ContentTypeItems = _contentTypeItems; var _generalManager = new CategoryGeneralManager(); var _general = _generalManager.Find(g => g.CategoryID == id); if (_general == null) _general = new CategoryGeneral() { ContentView = "index", View = "index" }; return PartialView(_general); } /// <summary> /// 單頁欄目 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public ActionResult ModifyPage(int id) { var _pageManager = new CategoryPageManager(); var _page = _pageManager.Find(g => g.CategoryID == id); if (_page == null) _page = new CategoryPage() { View = "index" }; return PartialView(_page); } /// <summary> /// 鏈接欄目 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> public ActionResult ModifyLink(int id) { var _linkManager = new CategoryLinkManager(); var _link = _linkManager.Find(g => g.CategoryID == id); if (_link == null) _link = new CategoryLink() { Url = "http://" }; return PartialView(_link); } #endregion
Modify 視圖
@model Ninesky.Core.Category.Category @{ ViewBag.Title = "修改欄目"; } @section SideNav{@Html.Partial("SideNavPartialView")} <ol class="breadcrumb"> <li><span class="glyphicon glyphicon-home"></span> @Html.ActionLink("首頁", "Index", "Home")</li> <li>@Html.ActionLink("欄目管理", "Index", "Category")</li> <li class="active">修改欄目</li> </ol> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.CategoryID) <ul id="myTabs" class="nav nav-tabs" role="tablist"> <li role="presentation"><a href="#base" role="tab" data-toggle="tab" aria-controls="base">基本資料</a></li> <li id="tabadvanced" role="presentation"><a href="#advanced" role="tab" data-toggle="tab" aria-controls="advanced">高級設置</a></li> </ul> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="base"> <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.ParentID, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.HiddenFor(model => model.ParentID) <div class="input-group" style="width:280px"> <input id="ParentName" type="text" class="form-control" readonly /> <ul class="dropdown-menu dropdown-menu-left ztree" style="display:none;width:100%" id="parenttree"></ul> <div class="input-group-btn open"> <button id="btn-CategoryID" type="button" class="btn btn-default"><span class="caret"></span></button> </div> </div> @Html.ValidationMessageFor(model => model.ParentID, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Type, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EnumDropDownListFor(model => model.Type, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Type, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Order, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Order, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Order, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Target, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Target, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Target, "", new { @class = "text-danger" }) </div> </div> </div> <div role="tabpanel" class="tab-pane" id="advanced"> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="保存" class="btn btn-default" /> </div> </div> </div> } <script type="text/javascript"> //顯示隱藏標簽頁 function showTabBySelect() { switch ($("#Type").find("option:selected").text()) { case "常規欄目": $("#advanced").load("@Url.Action("ModifyGeneral",new { id= Model.CategoryID })"); break; case "單頁欄目": $("#advanced").load("@Url.Action("ModifyPage", new { id = Model.CategoryID })"); break; case "外部鏈接": $("#advanced").load("@Url.Action("ModifyLink", new { id = Model.CategoryID })"); break; } } $(document).ready(function () { showTabBySelect(); $("#Type").change(function () { showTabBySelect(); }); //父欄目選擇框 zTree var zTreeObj; // zTree 的參數配置 var setting = { data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId", rootPId: 0 }, key: { name: "name" } }, callback: { onClick: function (event, treeId, treeNode) { $("#ParentID").val(treeNode.id); $("#ParentName").val(treeNode.name); $("#parenttree").slideUp(); } } }; // zTree 的數據屬性, $.post("@Url.Action("DropdownTree")", null, function (data) { zTreeObj = $.fn.zTree.init($("#parenttree"), setting, data); var newNode = { name: "無", id: "0", pId: "-1" }; newNode = zTreeObj.addNodes(null, 0, newNode); var node = zTreeObj.getNodeByParam("id", $("#ParentID").val(), null); if (node != null) { $("#ParentName").val(node.name); zTreeObj.selectNode(node); } }, "json"); }); $("#btn-CategoryID").click(function () { $("#parenttree").slideDown(); }); //父欄目選擇框 zTree 結束 </script>
ModifyGeneral分部視圖
@model Ninesky.Core.Category.CategoryGeneral <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.View, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.View, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.View, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ContentTypeID, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.DropDownListFor(model => model.ContentTypeID,(IEnumerable<SelectListItem>)ViewBag.ContentTypeItems, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.ContentTypeID, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ContentView, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.ContentView, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ContentView, "", new { @class = "text-danger" }) </div> </div>
ModifyPage分部視圖
@model Ninesky.Core.Category.CategoryPage <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.View, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.View, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.View, "", new { @class = "text-danger" }) </div> </div>
ModifyLink分部視圖
@model Ninesky.Core.Category.CategoryLink <br /> <br /> <div class="form-group"> @Html.LabelFor(model => model.Url, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Url, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Url, "", new { @class = "text-danger" }) </div> </div>
4、刪除欄目
在Category控制器中添加Delete(int id),方法的方式為[httppost],返回json類型提示。在方法中要先確定欄目是否存在,然后判斷是否有子欄目,如果有子欄目則不能刪除(其實還應該判斷是否有內容),如無子欄目則連帶欄目類型對應的數據一起刪除。
/// <summary> /// 刪除欄目 /// </summary> /// <param name="id">欄目ID</param> /// <returns></returns> [HttpPost] public ActionResult Delete(int id) { Response _resp = new Auxiliary.Response(); var _category = categoryManager.Find(id); if (_category == null) { _resp.Code = 0; _resp.Message = "欄目不存在"; } else { if (categoryManager.Count(c=>c.ParentID == _category.CategoryID)>0) { _resp.Code = 0; _resp.Message = "該欄目欄目有子欄目,請先刪除子欄目"; } else { switch(_category.Type) { case CategoryType.General: new CategoryGeneralManager().DeleteByCategoryID(_category.CategoryID); break; case CategoryType.Page: new CategoryPageManager().DeleteByCategoryID(_category.CategoryID); break; case CategoryType.Link: new CategoryLinkManager().DeleteByCategoryID(_category.CategoryID); break; } _resp = categoryManager.Delete(_category); } } return Json(_resp); }
然后打開Modify視圖。在保存按鈕旁添加一個刪除按鈕,如下圖
然后在js代碼最后添加刪除js代碼,如下圖:
完成后效果如下圖:
==========================================
文章列表