nopcommerce的新闻模块一直都没有新闻类别,但是很多情况下都会使用到类别,怎么办呢,自己动手吧。
1、首先创建新闻类别表,脚本如下:
CREATE TABLE [dbo].[NewsCategory]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](400) NOT NULL, [Description] [nvarchar](max) NOT NULL, [ParentCategoryId] [int] NOT NULL, [Published] [bit] NOT NULL, [Deleted] [bit] NOT NULL, [DisplayOrder] [int] NOT NULL, [CreatedOn] [datetime] NOT NULL, [UpdatedOn] [datetime] NOT NULL, CONSTRAINT [PK_NewsCategory] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO
2、\Libraries\Nop.Core\Domain\News下面增加实体类,代码如下:
using System;
using System.Collections.Generic;
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.News
{
/// <summary>
/// Represents a news category
/// </summary>
public partial class NewsCategory : BaseEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// Gets or sets the description
/// </summary>
public virtual string Description { get; set; }
/// <summary>
/// Gets or sets the parent category identifier
/// </summary>
public virtual int ParentCategoryId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is published
/// </summary>
public virtual bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public virtual bool Deleted { get; set; }
/// <summary>
/// Gets or sets the display order
/// </summary>
public virtual int DisplayOrder { get; set; }
/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public virtual DateTime CreatedOn { get; set; }
/// <summary>
/// Gets or sets the date and time of instance update
/// </summary>
public virtual DateTime UpdatedOn { get; set; }
}
}
3、\Libraries\Nop.Data\Mapping\News下面增加新闻类别映射类,因为nopcommerce使用Entity Framework (EF) Code-First方法,
允许你在nopcommerce代码中定义实体 (所有的核心实体类都在Nop.Core中定义),所以必须在此添加映射类,代码如下:using System.Data.Entity.ModelConfiguration;
using Nop.Core.Domain.News;
namespace Nop.Data.Mapping.News
{
public partial class NewsCategoryMap : EntityTypeConfiguration<NewsCategory>
{
public NewsCategoryMap()
{
this.ToTable("NewsCategory");
this.HasKey(bp => bp.Id);
this.Property(bp => bp.Name).IsRequired().IsMaxLength();
this.Property(bp => bp.Description).IsRequired().IsMaxLength();
}
}
}
4、\Libraries\Nop.Services\News下面的INewsService.cs和NewsService.cs增加新闻类别相关操作。
INewsService.cs整理后代码如下:using System;
using System.Collections.Generic;
using Nop.Core;
using Nop.Core.Domain.News;
namespace Nop.Services.News
{
/// <summary>
/// News service interface
/// </summary>
public partial interface INewsService
{
#region news
/// <summary>
/// Deletes a news
/// </summary>
/// <param name="newsItem">News item</param>
void DeleteNews(NewsItem newsItem);
/// <summary>
/// Gets a news
/// </summary>
/// <param name="newsId">The news identifier</param>
/// <returns>News</returns>
NewsItem GetNewsById(int newsId);
/// <summary>
/// Gets all news
/// </summary>
/// <param name="languageId">Language identifier; 0 if you want to get all records</param>
/// <param name="dateFrom">Filter by created date; null if you want to get all records</param>
/// <param name="dateTo">Filter by created date; null if you want to get all records</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News items</returns>
IPagedList<NewsItem> GetAllNews(int languageId,
DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false);
/// <summary>
/// Inserts a news item
/// </summary>
/// <param name="news">News item</param>
void InsertNews(NewsItem news);
/// <summary>
/// Updates the news item
/// </summary>
/// <param name="news">News item</param>
void UpdateNews(NewsItem news);
#endregion
#region news category
/// <summary>
/// Deletes a news category
/// </summary>
/// <param name="category">News Category item</param>
void DeleteNewsCategory(NewsCategory category);
/// <summary>
/// Gets a news category
/// </summary>
/// <param name="categoryId">The news category identifier</param>
/// <returns>NewsCategory</returns>
NewsCategory GetNewsCategoryById(int categoryId);
/// <summary>
/// Gets all news category
/// </summary>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News Category items</returns>
IPagedList<NewsCategory> GetAllNewsCategory(int pageIndex, int pageSize, bool showHidden = false);
/// <summary>
/// Gets all news category
/// </summary>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News Category items</returns>
IList<NewsCategory> GetAllNewsCategory(bool showHidden = false);
/// <summary>
/// Inserts a news category item
/// </summary>
/// <param name="category">News Category item</param>
void InsertNewsCategory(NewsCategory category);
/// <summary>
/// Updates the news category item
/// </summary>
/// <param name="category">News Category item</param>
void UpdateNewsCategory(NewsCategory category);
#endregion
}
}
NewsService.cs整理后代码如下:using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Data;
using Nop.Core.Domain.News;
using Nop.Core.Events;
namespace Nop.Services.News
{
/// <summary>
/// News service
/// </summary>
public partial class NewsService : INewsService
{
#region Constants
private const string NEWS_BY_ID_KEY = "Nop.news.id-{0}";
private const string NEWS_PATTERN_KEY = "Nop.news.";
private const string NEWSCATEGORY_BY_ID_KEY = "Nop.newscategory.id-{0}";
private const string NEWSCATEGORY_PATTERN_KEY = "Nop.newscategory.";
#endregion
#region Fields
private readonly IRepository<NewsItem> _newsItemRepository;
private readonly IRepository<NewsCategory> _newsCategoryRepository;
private readonly ICacheManager _cacheManager;
private readonly IEventPublisher _eventPublisher;
#endregion
#region Ctor
public NewsService(IRepository<NewsItem> newsItemRepository, IRepository<NewsCategory> newsCategoryRepository, ICacheManager cacheManager, IEventPublisher eventPublisher)
{
_newsItemRepository = newsItemRepository;
_newsCategoryRepository = newsCategoryRepository;
_cacheManager = cacheManager;
_eventPublisher = eventPublisher;
}
#endregion
#region Methods
#region news
/// <summary>
/// Deletes a news
/// </summary>
/// <param name="newsItem">News item</param>
public virtual void DeleteNews(NewsItem newsItem)
{
if (newsItem == null)
throw new ArgumentNullException("newsItem");
_newsItemRepository.Delete(newsItem);
_cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);
//event notification
_eventPublisher.EntityDeleted(newsItem);
}
/// <summary>
/// Gets a news
/// </summary>
/// <param name="newsId">The news identifier</param>
/// <returns>News</returns>
public virtual NewsItem GetNewsById(int newsId)
{
if (newsId == 0)
return null;
string key = string.Format(NEWS_BY_ID_KEY, newsId);
return _cacheManager.Get(key, () =>
{
var n = _newsItemRepository.GetById(newsId);
return n;
});
}
/// <summary>
/// Gets all news
/// </summary>
/// <param name="languageId">Language identifier; 0 if you want to get all records</param>
/// <param name="dateFrom">Filter by created date; null if you want to get all records</param>
/// <param name="dateTo">Filter by created date; null if you want to get all records</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News items</returns>
public virtual IPagedList<NewsItem> GetAllNews(int languageId,
DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false)
{
var query = _newsItemRepository.Table;
if (dateFrom.HasValue)
query = query.Where(n => dateFrom.Value <= n.CreatedOnUtc);
if (dateTo.HasValue)
query = query.Where(n => dateTo.Value >= n.CreatedOnUtc);
if (languageId > 0)
query = query.Where(n => languageId == n.LanguageId);
if (!showHidden)
query = query.Where(n => n.Published);
query = query.OrderByDescending(b => b.CreatedOnUtc);
var news = new PagedList<NewsItem>(query, pageIndex, pageSize);
return news;
}
/// <summary>
/// Inserts a news item
/// </summary>
/// <param name="news">News item</param>
public virtual void InsertNews(NewsItem news)
{
if (news == null)
throw new ArgumentNullException("news");
_newsItemRepository.Insert(news);
_cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);
//event notification
_eventPublisher.EntityInserted(news);
}
/// <summary>
/// Updates the news item
/// </summary>
/// <param name="news">News item</param>
public virtual void UpdateNews(NewsItem news)
{
if (news == null)
throw new ArgumentNullException("news");
_newsItemRepository.Update(news);
_cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);
//event notification
_eventPublisher.EntityUpdated(news);
}
#endregion
#region news category
/// <summary>
/// Deletes a news category
/// </summary>
/// <param name="category">News Category item</param>
public virtual void DeleteNewsCategory(NewsCategory category)
{
if (category == null)
throw new ArgumentNullException("category");
_newsCategoryRepository.Delete(category);
_cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);
//event notification
_eventPublisher.EntityDeleted(category);
}
/// <summary>
/// Gets a news category
/// </summary>
/// <param name="categoryId">The news category identifier</param>
/// <returns>NewsCategory</returns>
public virtual NewsCategory GetNewsCategoryById(int categoryId)
{
if (categoryId == 0)
return null;
string key = string.Format(NEWSCATEGORY_BY_ID_KEY, categoryId);
return _cacheManager.Get(key, () =>
{
var n = _newsCategoryRepository.GetById(categoryId);
return n;
});
}
/// <summary>
/// Gets all news category
/// </summary>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News Category items</returns>
public virtual IPagedList<NewsCategory> GetAllNewsCategory(int pageIndex, int pageSize, bool showHidden = false)
{
var categories = GetAllNewsCategory(showHidden);
return new PagedList<NewsCategory>(categories, pageIndex, pageSize);
}
/// <summary>
/// Gets all news category
/// </summary>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <returns>News Category items</returns>
public virtual IList<NewsCategory> GetAllNewsCategory(bool showHidden = false)
{
var query = _newsCategoryRepository.Table;
if (!showHidden)
query = query.Where(n => n.Published);
query = query.OrderBy(b => b.DisplayOrder);
var unsortedCategories = query.ToList();
//sort categories
var sortedCategories = unsortedCategories.SortCategoriesForTree(0);
return sortedCategories;
}
/// <summary>
/// Inserts a news category item
/// </summary>
/// <param name="category">News Category item</param>
public virtual void InsertNewsCategory(NewsCategory category)
{
if (category == null)
throw new ArgumentNullException("category");
_newsCategoryRepository.Insert(category);
_cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);
//event notification
_eventPublisher.EntityInserted(category);
}
/// <summary>
/// Updates the news category item
/// </summary>
/// <param name="category">News Category item</param>
public virtual void UpdateNewsCategory(NewsCategory category)
{
if (category == null)
throw new ArgumentNullException("category");
_newsCategoryRepository.Update(category);
_cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);
//event notification
_eventPublisher.EntityUpdated(category);
}
#endregion
#endregion
}
}
另外需要增加NewsExtensions.cs,主要用于新闻类别的排序(对无限极分类的排序等等),代码如下:using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core.Domain.News;
namespace Nop.Services.News
{
/// <summary>
/// Extensions
/// </summary>
public static class NewsExtensions
{
/// <summary>
/// Sort news categories for tree representation
/// </summary>
/// <param name="source">Source</param>
/// <param name="parentId">Parent category identifier</param>
/// <returns>Sorted categories</returns>
public static IList<NewsCategory> SortCategoriesForTree(this IList<NewsCategory> source, int parentId)
{
var result = new List<NewsCategory>();
var temp = source.ToList().FindAll(c => c.ParentCategoryId == parentId);
foreach (var cat in temp)
{
result.Add(cat);
result.AddRange(SortCategoriesForTree(source, cat.Id));
}
return result;
}
public static string GetCategoryNameWithPrefix(this NewsCategory category, INewsService newsService)
{
string result = string.Empty;
while (category != null)
{
if (String.IsNullOrEmpty(result))
result = category.Name;
else
result = "--" + result;
category = newsService.GetNewsCategoryById(category.ParentCategoryId);
}
return result;
}
public static string GetCategoryBreadCrumb(this NewsCategory category, INewsService newsService)
{
string result = string.Empty;
while (category != null && !category.Deleted)
{
if (String.IsNullOrEmpty(result))
result = category.Name;
else
result = category.Name + " >> " + result;
category = newsService.GetNewsCategoryById(category.ParentCategoryId);
}
return result;
}
}
}
5、到此底层的数据操作已经基本完成,开始修改后台管理部分。
Nop.Admin\Models\News\增加新闻类别页面所需要的ViewModel,代码如下:using System;
using System.Collections.Generic;
using System.Web.Mvc;
using FluentValidation.Attributes;
using Nop.Admin.Validators.News;
using Nop.Web.Framework;
using Nop.Web.Framework.Mvc;
namespace Nop.Admin.Models.News
{
[Validator(typeof(NewsCategoryValidator))]
public class NewsCategoryModel : BaseNopEntityModel
{
public NewsCategoryModel()
{
AvailableCategories = new List<SelectListItem>();
}
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Name")]
public string Name { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Description")]
[AllowHtml]
public string Description { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.ParentName")]
public int ParentCategoryId { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.ParentName")]
public string ParentCategoryName { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Published")]
public bool Published { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.DisplayOrder")]
public int DisplayOrder { get; set; }
[NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.CreatedOn")]
public DateTime CreatedOn { get; set; }
public IList<SelectListItem> AvailableCategories { get; set; }
}
}
Nop.Admin\Validators\News\增加类别的验证类NewsCategoryValidator.cs,主要用于后台添加时候的非空字数限制等等,代码如下:using FluentValidation;
using Nop.Admin.Models.News;
using Nop.Services.Localization;
namespace Nop.Admin.Validators.News
{
public class NewsCategoryValidator : AbstractValidator<NewsCategoryModel>
{
public NewsCategoryValidator(ILocalizationService localizationService)
{
RuleFor(x => x.Name)
.NotNull()
.WithMessage(localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Fields.Name.Required"));
RuleFor(x => x.Description)
.NotNull()
.WithMessage(localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Fields.Description.Required"));
}
}
}
修改Nop.Admin/MappingExtensions.cs文件,增加新闻类别相关内容,这几个方法主要是NewsCategory和NewsCategoryModel之间的相互转换,代码如下://news category items
public static NewsCategoryModel ToModel(this NewsCategory entity)
{
return Mapper.Map<NewsCategory, NewsCategoryModel>(entity);
}
public static NewsCategory ToEntity(this NewsCategoryModel model)
{
return Mapper.Map<NewsCategoryModel, NewsCategory>(model);
}
public static NewsCategory ToEntity(this NewsCategoryModel model, NewsCategory destination)
{
return Mapper.Map(model, destination);
}
修改Nop.Admin/Infrastructure/AutoMapperStartupTask.cs文件,增加相关映射规则,如果不加的话会出错的哦,
AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DTO,一般用于ViewModel模式和跨服务范畴。
AutoMapper给用户提供了便捷的配置API,就像使用约定来完成自动映射那样。
代码如下:Mapper.CreateMap<NewsCategory, NewsCategoryModel>()
.ForMember(dest => dest.AvailableCategories, mo => mo.Ignore())
.ForMember(dest => dest.ParentCategoryName, mo => mo.Ignore())
.ForMember(dest => dest.CreatedOn, mo => mo.Ignore());
Mapper.CreateMap<NewsCategoryModel, NewsCategory>()
.ForMember(dest => dest.CreatedOn, mo => mo.Ignore());最后修改Nop.Admin\Controllers\NewsController.cs,增加新闻类别的增删改查操作,如下:
#region News category items
public ActionResult CategoryList()
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var news = _newsService.GetAllNewsCategory(0, _adminAreaSettings.GridPageSize, true);
var gridModel = new GridModel<NewsCategoryModel>
{
Data = news.Select(x =>
{
var m = x.ToModel();
m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOn, DateTimeKind.Utc);
m.Name = x.GetCategoryBreadCrumb(_newsService);
m.Published = x.Published;
m.DisplayOrder = x.DisplayOrder;
return m;
}),
Total = news.TotalCount
};
return View(gridModel);
}
[HttpPost, GridAction(EnableCustomBinding = true)]
public ActionResult CategoryList(GridCommand command)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var news = _newsService.GetAllNewsCategory(0, _adminAreaSettings.GridPageSize, true);
var gridModel = new GridModel<NewsCategoryModel>
{
Data = news.Select(x =>
{
var m = x.ToModel();
m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOn, DateTimeKind.Utc);
m.Name = x.GetCategoryBreadCrumb(_newsService);
m.Published = x.Published;
m.DisplayOrder = x.DisplayOrder;
return m;
}),
Total = news.TotalCount
};
return new JsonResult
{
Data = gridModel
};
}
public ActionResult CategoryCreate()
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var model = new NewsCategoryModel();
//default values
model.Published = true;
//categories
model.AvailableCategories.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
foreach (var c in _newsService.GetAllNewsCategory(true))
model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_newsService), Value = c.Id.ToString() });
return View(model);
}
[HttpPost, FormValueExists("save", "save-continue", "continueEditing")]
public ActionResult CategoryCreate(NewsCategoryModel model, bool continueEditing)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
if (ModelState.IsValid)
{
var newsItem = model.ToEntity();
newsItem.CreatedOn = DateTime.UtcNow;
newsItem.UpdatedOn = DateTime.UtcNow;
_newsService.InsertNewsCategory(newsItem);
SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Added"));
return continueEditing ? RedirectToAction("CategoryEdit", new { id = newsItem.Id }) : RedirectToAction("CategoryList");
}
return View(model);
}
public ActionResult CategoryEdit(int id)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var newsItem = _newsService.GetNewsCategoryById(id);
if (newsItem == null)
//No news item found with the specified id
return RedirectToAction("CategoryList");
var model = newsItem.ToModel();
//categories
model.AvailableCategories.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
foreach (var c in _newsService.GetAllNewsCategory(true))
model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_newsService), Value = c.Id.ToString() });
return View(model);
}
[HttpPost, FormValueExists("save", "save-continue", "continueEditing")]
public ActionResult CategoryEdit(NewsCategoryModel model, bool continueEditing)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var newsItem = _newsService.GetNewsCategoryById(model.Id);
if (newsItem == null)
//No news item found with the specified id
return RedirectToAction("CategoryList");
if (ModelState.IsValid)
{
newsItem = model.ToEntity(newsItem);
newsItem.UpdatedOn = DateTime.UtcNow;
_newsService.UpdateNewsCategory(newsItem);
SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Updated"));
return continueEditing ? RedirectToAction("CategoryEdit", new { id = newsItem.Id }) : RedirectToAction("List");
}
return View(model);
}
[HttpPost, ActionName("DeleteCategory")]
public ActionResult DeleteCategoryConfirmed(int id)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
return AccessDeniedView();
var newsItem = _newsService.GetNewsCategoryById(id);
if (newsItem == null)
//No news item found with the specified id
return RedirectToAction("CategoryList");
_newsService.DeleteNewsCategory(newsItem);
SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Deleted"));
return RedirectToAction("CategoryList");
}
#endregion
6、接下来就是页面View了,代码太多,这里不再具体列出,不熟悉MVC机制的可以先补充一下MVC相关知识。
稍后整理提供下载。
分享是一种美。版权所有,转载请注明出处 http://www.nopchina.net/
浙公网安备 33010602011771号