zoukankan      html  css  js  c++  java
  • Orchard模块开发全接触8:改造后台

    后台默认提供了 Content 的管理,但是,所有的内容类型揉杂在一起,而我们需要更深度的定制一些功能,比如,我们只想管理订单,又比如,我们需要对注册用户进行管理。本篇的内容包括:

    1:自定义 admin menu;

    2:使用 content query;

    3:使用 paging utilities;

    4:创建 list 与 edit;

    一:扩展 Admin Menu

    首先我们必须要实现 INavigationProvider 接口,我们创建 AdminMenu.cs:

    using Orchard.Environment;
    using Orchard.Localization;
    using Orchard.UI.Navigation;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.Routing;

    namespace TMinji.Shop
    {
        public class AdminMenu : INavigationProvider
        {
            private readonly Work<RequestContext> _requestContextAccessor;

            public string MenuName
            {
                get { return "admin"; }
            }

            public AdminMenu(Work<RequestContext> requestContextAccessor)
            {
                _requestContextAccessor = requestContextAccessor;
                T = NullLocalizer.Instance;
            }

            private Localizer T { get; set; }

            public void GetNavigation(NavigationBuilder builder)
            {

                var requestContext = _requestContextAccessor.Value;
                var idValue = (string)requestContext.RouteData.Values["id"];
                var id = 0;

                if (!string.IsNullOrEmpty(idValue))
                {
                    int.TryParse(idValue, out id);
                }

                builder

                    // Image set
                    .AddImageSet("webshop")

                    // "Webshop"
                    .Add(item => item

                        .Caption(T("Webshop"))
                        .Position("2")
                        .LinkToFirstChild(false)

                        // "Customers"
                        .Add(subItem => subItem
                            .Caption(T("Customers"))
                            .Position("2.1")
                            .Action(new RouteValueDictionary
                            {
                                {"area", "TMinji.Shop"},
                                {"controller", "CustomerAdmin"},
                                {"action", "Index"}
                            })

                            .Add(T("Details"), i => i.Action("Edit", "CustomerAdmin", new { id }).LocalNav())
                            .Add(T("Addresses"), i => i.Action("ListAddresses", "CustomerAdmin", new { id }).LocalNav())
                            .Add(T("Orders"), i => i.Action("ListOrders", "CustomerAdmin", new { id }).LocalNav())
                        )

                        // "Orders"
                        .Add(subItem => subItem
                            .Caption(T("Orders"))
                            .Position("2.2")
                            .Action(new RouteValueDictionary
                            {
                                {"area", "TMinji.Shop"},
                                {"controller", "OrderAdmin"},
                                {"action", "Index"}
                            })
                        )
                    );
            }
        }

    }

    代码中,指示我们需要加两个资源,一个是 menu.webshop.png,一个是 menu.webshop-admin.css,这是需要我们手动添加的,

    Styles/menu.webshop-admin.css:

    .navicon-webshop {
    background-image:url('../images/menu.webshop.png') !important;
    }
    .navicon-webshop:hover {
    background-position:0 -30px !important;
    }

    这个时候,我们的后台,就会变成这样了:

    image

    二:后台控制器

    现在,添加后台的控制器。

    Controllers/CustomerAdminController.cs:

    using Orchard.ContentManagement;
    using Orchard.DisplayManagement;
    using Orchard.Localization;
    using Orchard.Settings;
    using Orchard.UI.Admin;
    using Orchard.UI.Navigation;
    using Orchard.UI.Notify;
    using Orchard.Users.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web.Mvc;
    using TMinji.Shop.Services;
    using TMinji.Shop.ViewModels;
    using TMinji.Shop.Helpers;

    namespace TMinji.Shop.Controllers
    {
        [Admin]
        public class CustomerAdminController : Controller, IUpdateModel
        {
            private dynamic Shape { get; set; }
            private Localizer T { get; set; }
            private readonly ICustomerService _customerService;
            private readonly ISiteService _siteService;
            private readonly IContentManager _contentManager;
            private readonly INotifier _notifier;
            private readonly IOrderService _orderService;

            public CustomerAdminController
            (
                ICustomerService customerService,
                IShapeFactory shapeFactory,
                ISiteService siteService,
                IContentManager contentManager,
                INotifier notifier,
                IOrderService orderService
            )
            {
                Shape = shapeFactory;
                T = NullLocalizer.Instance;
                _customerService = customerService;
                _siteService = siteService;
                _contentManager = contentManager;
                _notifier = notifier;
                _orderService = orderService;
            }

            public ActionResult Index(PagerParameters pagerParameters, CustomersSearchVM search)
            {

                // Create a basic query that selects all customer content items, joined with the UserPartRecord table
                var customerQuery = _customerService.GetCustomers().Join<UserPartRecord>().List();

                // If the user specified a search expression, update the query with a filter
                if (!string.IsNullOrWhiteSpace(search.Expression))
                {

                    var expression = search.Expression.Trim();

                    customerQuery = from customer in customerQuery
                                    where
                                        customer.FirstName.Contains(expression, StringComparison.InvariantCultureIgnoreCase) ||
                                        customer.LastName.Contains(expression, StringComparison.InvariantCultureIgnoreCase) ||
                                        customer.As<UserPart>().Email.Contains(expression)
                                    select customer;
                }

                // Project the query into a list of customer shapes
                var customersProjection = from customer in customerQuery
                                          select Shape.Customer
                                          (
                                            Id: customer.Id,
                                            FirstName: customer.FirstName,
                                            LastName: customer.LastName,
                                            Email: customer.As<UserPart>().Email,
                                            CreatedAt: customer.CreatedAt
                                          );

                // The pager is used to apply paging on the query and to create a PagerShape
                var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters.Page, pagerParameters.PageSize);

                // Apply paging
                var customers = customersProjection.Skip(pager.GetStartIndex()).Take(pager.PageSize);

                // Construct a Pager shape
                var pagerShape = Shape.Pager(pager).TotalItemCount(customerQuery.Count());

                // Create the viewmodel
                var model = new CustomersIndexVM(customers, search, pagerShape);

                return View(model);
            }

            public ActionResult Edit(int id)
            {
                var customer = _customerService.GetCustomer(id);
                var model = _contentManager.BuildEditor(customer);

                // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
                return View((object)model);
            }

            [HttpPost, ActionName("Edit")]
            public ActionResult EditPOST(int id)
            {
                var customer = _customerService.GetCustomer(id);
                var model = _contentManager.UpdateEditor(customer, this);

                if (!ModelState.IsValid)
                    return View(model);

                _notifier.Add(NotifyType.Information, T("Your customer has been saved"));
                return RedirectToAction("Edit", new { id });
            }

            public ActionResult ListAddresses(int id)
            {
                var addresses = _customerService.GetAddresses(id).ToArray();
                return View(addresses);
            }

            public ActionResult ListOrders(int id)
            {
                var orders = _orderService.GetOrders(id).ToArray();
                return View(orders);
            }

            bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties)
            {
                return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
            }

            void IUpdateModel.AddModelError(string key, LocalizedString errorMessage)
            {
                ModelState.AddModelError(key, errorMessage.Text);
            }
        }
    }

    Views/CustomerAdmin/Index.cshtml:

    @model TMinji.Shop.ViewModels.CustomersIndexVM
    @{
        Script.Require("ShapesBase");
        Layout.Title = T("Customers").ToString();
    }

    @using (Html.BeginForm("Index", "CustomerAdmin", FormMethod.Get))
    {
        <fieldset class="bulk-actions">
            <label for="search">@T("Search:")</label>
            @Html.TextBoxFor(m => m.Search.Expression)
            <button type="submit">@T("Search")</button>
            <a href="@Url.Action("Index")">@T("Clear")</a>
        </fieldset>
    }
    <fieldset>
        <table class="items" summary="@T("This is a table of the customers in your application")">
            <colgroup>
                <col id="Col1" />
                <col id="Col2" />
                <col id="Col3" />
                <col id="Col4" />
                <col id="Col5" />
                <col id="Col6" />
            </colgroup>
            <thead>
                <tr>
                    <th scope="col">&nbsp;&darr;</th>
                    <th scope="col">@T("FirstName")</th>
                    <th scope="col">@T("LastName")</th>
                    <th scope="col">@T("Email")</th>
                    <th scope="col">@T("Created")</th>
                    <th scope="col">@T("Actions")</th>
                </tr>
            </thead>
            @foreach (var customer in Model.Customers)
            {
                <tr>
                    <td>@customer.Id</td>
                    <td>@customer.FirstName</td>
                    <td>@customer.LastName</td>
                    <td>@customer.Email</td>
                    <td>@customer.CreatedAt</td>
                    <td>
                        <div>
                            <a href="@Url.Action("Edit", new {customer.Id})" title="@T("Edit")">@T("Edit")</a>@T(" | ")
                            <a href="@Url.Action("List", "AddressAdmin", new {customerId = customer.Id})" title="@T("Addresses")">@T("Addresses")</a>@T(" | ")
                            <a href="@Url.Action("Delete", new {customer.Id, returnUrl = Request.Url.PathAndQuery})">@T("Delete")</a>
                        </div>
                    </td>
                </tr>
            }
        </table>
        @Display(Model.Pager)
    </fieldset>

    Services/ICustomerService.cs:

    public interface ICustomerService : IDependency
    {
        CustomerPart CreateCustomer(string email, string password);
        AddressPart GetAddress(int customerId, string addressType);
        AddressPart CreateAddress(int customerId, string addressType);

        IContentQuery<CustomerPart> GetCustomers();

        CustomerPart GetCustomer(int id);

        IEnumerable<AddressPart> GetAddresses(int customerId);

        AddressPart GetAddress(int id);
    }

    Services/CustomerService.cs:

    using Orchard;
    using Orchard.ContentManagement;
    using Orchard.Security;
    using Orchard.Services;
    using Orchard.Users.Models;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using TMinji.Shop.Models;

    namespace TMinji.Shop.Services
    {
        public class CustomerService : ICustomerService
        {
            private readonly IOrchardServices _orchardServices;
            private readonly IMembershipService _membershipService;
            private readonly IClock _clock;

            public CustomerService(IOrchardServices orchardServices, IMembershipService membershipService, IClock clock)
            {
                _orchardServices = orchardServices;
                _membershipService = membershipService;
                _clock = clock;
            }

            public CustomerPart CreateCustomer(string email, string password)
            {
                // New up a new content item of type "Customer"
                var customer = _orchardServices.ContentManager.New("Customer");

                // Cast the customer to a UserPart
                var userPart = customer.As<UserPart>();

                // Cast the customer to a CustomerPart
                var customerPart = customer.As<CustomerPart>();

                // Set some properties of the customer content item (via UserPart and CustomerPart)
                userPart.UserName = email;
                userPart.Email = email;
                userPart.NormalizedUserName = email.ToLowerInvariant();
                userPart.Record.HashAlgorithm = "SHA1";
                userPart.Record.RegistrationStatus = UserStatus.Approved;
                userPart.Record.EmailStatus = UserStatus.Approved;

                // Use IClock to get the current date instead of using DateTime.Now (see http://skywalkersoftwaredevelopment.net/orchard-development/api/iclock)
                customerPart.CreatedAt = _clock.UtcNow;

                // Use Ochard's MembershipService to set the password of our new user
                _membershipService.SetPassword(userPart, password);

                // Store the new user into the database
                _orchardServices.ContentManager.Create(customer);

                return customerPart;
            }

            public AddressPart GetAddress(int customerId, string addressType)
            {
                return _orchardServices.ContentManager.Query<AddressPart, AddressPartRecord>().Where(x => x.CustomerId == customerId && x.Type == addressType).List().FirstOrDefault();
            }

            public AddressPart CreateAddress(int customerId, string addressType)
            {
                return _orchardServices.ContentManager.Create<AddressPart>("Address", x =>
                {
                    x.Type = addressType;
                    x.CustomerId = customerId;
                });
            }

            public IContentQuery<CustomerPart> GetCustomers()
            {
                return _orchardServices.ContentManager.Query<CustomerPart, CustomerPartRecord>();
            }

            public CustomerPart GetCustomer(int id)
            {
                return _orchardServices.ContentManager.Get<CustomerPart>(id);
            }

            public IEnumerable<AddressPart> GetAddresses(int customerId)
            {
                return _orchardServices.ContentManager.Query<AddressPart, AddressPartRecord>().Where(x => x.CustomerId == customerId).List();
            }

            public AddressPart GetAddress(int id)
            {
                return _orchardServices.ContentManager.Get<AddressPart>(id);
            }
        }

    }

    Helpers/StringExtensions.cs:

    public static class StringExtensions
    {
        public static string TrimSafe(this string s)
        {
            return s == null ? string.Empty : s.Trim();
        }

        public static bool Contains(this string source, string value, StringComparison comparison)
        {
            return source.IndexOf(value, comparison) >= 0;
        }
    }

    ViewModels/CustomersIndexVM.cs:

    public class CustomersIndexVM
    {
        public IList<dynamic> Customers { get; set; }
        public dynamic Pager { get; set; }
        public CustomersSearchVM Search { get; set; }

        public CustomersIndexVM()
        {
            Search = new CustomersSearchVM();
        }

        public CustomersIndexVM(IEnumerable<dynamic> customers, CustomersSearchVM search, dynamic pager)
        {
            Customers = customers.ToArray();
            Search = search;
            Pager = pager;
        }
    }

    ViewModels/CustomersSearchVM.cs:

    public class CustomersSearchVM
    {
        public string Expression { get; set; }
    }

    Views/CustomerAdmin/Edit.cshtml:

    @{
        Layout.Title = "Edit Customer";
    }

    @using (Html.BeginFormAntiForgeryPost())
    {
        @Display(Model)
    }

    Drivers/CustomerDriver.cs:

    protected override DriverResult Editor(CustomerPart part, IUpdateModel updater, dynamic shapeHelper)
    {
        updater.TryUpdateModel(part, Prefix, null, null);

        var user = part.User;
        updater.TryUpdateModel(user, Prefix, new[] { "Email" }, null);

        return Editor(part, shapeHelper);

    }

    Views/EditorTemplates/Parts/Customer.cshtml:

    @using System.Web.Mvc.Html
    @model TMinji.Shop.Models.CustomerPart
    @{
        var user = Model.User;
    }
    <fieldset>
        <div class="editor-label">@Html.LabelFor(x => x.Title)</div>
        <div class="editor-field">@Html.TextBoxFor(x => x.Title, new { @class = "text" })</div>

        <div class="editor-label">@Html.LabelFor(x => x.FirstName)</div>
        <div class="editor-field">
            @Html.TextBoxFor(x => x.FirstName, new { @class = "large text" })
            @Html.ValidationMessageFor(x => x.FirstName)
        </div>

        <div class="editor-label">@Html.LabelFor(x => x.LastName)</div>
        <div class="editor-field">
            @Html.TextBoxFor(x => x.LastName, new { @class = "large text" })
            @Html.ValidationMessageFor(x => x.LastName)
        </div>

        <div class="editor-label">@Html.LabelFor(x => user.Email)</div>
        <div class="editor-field">
            @Html.TextBoxFor(x => user.Email, new { @class = "large text" })
            @Html.ValidationMessageFor(x => user.Email)
        </div>
    </fieldset>

    最终效果:

    image

    image

    image

  • 相关阅读:
    Add Two Numbers
    Reverse Linked List II
    Reverse Linked List
    Remove Duplicates from Sorted List
    Remove Duplicates from Sorted List II
    Partition List
    Intersection of Two Linked Lists
    4Sum
    3Sum
    2Sum
  • 原文地址:https://www.cnblogs.com/luminji/p/3867411.html
Copyright © 2011-2022 走看看