程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .Net Core MVC 網站開發(Ninesky) 2.4、添加欄目與異步方法,mvcninesky

.Net Core MVC 網站開發(Ninesky) 2.4、添加欄目與異步方法,mvcninesky

編輯:關於.NET

.Net Core MVC 網站開發(Ninesky) 2.4、添加欄目與異步方法,mvcninesky


在2.3中完成依賴注入後,這次主要實現欄目的添加功能。按照前面思路欄目有三種類型,常規欄目即可以添加子欄目也可以選擇是否添加內容,內容又可以分文章或其他類型,所以還要添加一個模塊功能。這次主要實現欄目的添加,附帶實現模塊列表功能,並將業務邏輯層的功能都實現了異步方法。

先來個完成後的界面吧。

一、業務邏輯層異步方法

.net Core中異步方法很簡單,只需要Task、async、await三個關鍵字就行。比如要實現統計記錄數異步方法,只要給方法添加關鍵字async,然後返回Task類型,並在方法中使用await調用異步方法就可以。

public async Task<int> CountAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbContext.Set<T>().CountAsync(predicate);
        }

一般在異步方法中也是調用異步方法,如果調用同步方法,如果直接調用同步方法也沒問題,但是編譯器會顯示警告,看著警告煩可以Task.FromResult,像下面這樣子。

public virtual async Task<IQueryable<T>> FindListAsync()
        {
            IQueryable<T> result = _dbContext.Set<T>();
            return await Task.FromResult(result);
        }

基本內容都差不多,下面直接貼代碼。

1、異步接口

在Ninesky.InterfaceBase中打開InterfaceBaseService文件。添加接口異步的方法,結果如下:

using Ninesky.Models;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Ninesky.InterfaceBase
{
    /// <summary>
    ///  服務基礎接口
    /// </summary>
    public interface InterfaceBaseService<T> where T:class
    {

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        int Add(T entity, bool isSave = true);

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        Task<int> AddAsync(T entity, bool isSave = true);

        /// <summary>
        /// 添加[批量]
        /// </summary>
        /// <param name="entities">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數</returns>
        int AddRange(T[] entities, bool isSave = true);
        /// <summary>
        /// 添加[批量]
        /// </summary>
        /// <param name="entities">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        Task<int> AddRangeAsync(T[] entities, bool isSave = true);

        /// <summary>
        /// 查詢記錄數
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>記錄數</returns>
        int Count(Expression<Func<T, bool>> predicate);
        
        /// <summary>
        /// 查詢記錄數
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>記錄數</returns>
        Task<int> CountAsync(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢是否存在
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>是否存在</returns>
        bool Exists(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢是否存在
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>是否存在</returns>
        Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="Id">主鍵</param>
        /// <returns></returns>
        T Find(int Id);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="Id">主鍵</param>
        /// <returns></returns>
        Task<T> FindAsync(int Id);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="keyValues">主鍵</param>
        /// <returns></returns>
        T Find(object[] keyValues);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="keyValues">主鍵</param>
        /// <returns></returns>
        Task<T> FindAsync(object[] keyValues);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns></returns>
        T Find(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns></returns>
        Task<T> FindAsync(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <returns>實體列表</returns>
        IQueryable<T> FindList();

        /// <summary>
        /// 查詢
        /// </summary>
        /// <returns>實體列表</returns>
        Task<IQueryable<T>> FindListAsync();

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        IQueryable<T> FindList(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        Task<IQueryable<T>> FindListAsync(Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">返回記錄數</param>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        IQueryable<T> FindList(int number, Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">返回記錄數</param>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        Task<IQueryable<T>> FindListAsync(int number, Expression<Func<T, bool>> predicate);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">顯示數量[小於等於0-不啟用]</param>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">正序</param>
        /// <returns></returns>
        IQueryable<T> FindList<TKey>(int number, Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc);

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">顯示數量[小於等於0-不啟用]</param>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">正序</param>
        /// <returns></returns>
        Task<IQueryable<T>> FindListAsync<TKey>(int number, Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc);

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="paging">分頁數據</param>
        /// <returns></returns>
        Paging<T> FindList<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, Paging<T> paging);

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="paging">分頁數據</param>
        /// <returns></returns>
        Task<Paging<T>> FindListAsync<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, Paging<T> paging);

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="pageIndex">當前頁</param>
        /// <param name="pageSize">每頁記錄數</param>
        /// <returns></returns>
        Paging<T> FindList<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, int pageIndex, int pageSize);

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="pageIndex">當前頁</param>
        /// <param name="pageSize">每頁記錄數</param>
        /// <returns></returns>
        Task<Paging<T>> FindListAsync<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, int pageIndex, int pageSize);

        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否刪除成功[isSave=true時有效]</returns>
        bool Remove(T entity, bool isSave = true);

        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否刪除成功[isSave=true時有效]</returns>
        Task<bool> RemoveAsync(T entity, bool isSave = true);

        /// <summary>
        /// 刪除[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>成功刪除的記錄數[isSave=true時有效]</returns>
        int RemoveRange(T[] entities, bool isSave = true);

        /// <summary>
        /// 刪除[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>成功刪除的記錄數[isSave=true時有效]</returns>
        Task<int> RemoveRangeAsync(T[] entities, bool isSave = true);

        /// <summary>
        ///  保存數據
        /// </summary>
        /// <returns>更改的記錄數</returns>
        int SaveChanges();

        /// <summary>
        ///  保存數據
        /// </summary>
        /// <returns>更改的記錄數</returns>
        Task<int> SaveChangesAsync();

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否保存成功[isSave=true時有效]</returns>
        bool Update(T entity, bool isSave = true);

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否保存成功[isSave=true時有效]</returns>
        Task<bool> UpdateAsync(T entity, bool isSave = true);

        /// <summary>
        /// 更新[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>更新成功的記錄數[isSave=true時有效]</returns>
        int UpdateRange(T[] entities, bool isSave = true);

        /// <summary>
        /// 更新[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>更新成功的記錄數[isSave=true時有效]</returns>
        Task<int> UpdateRangeAsync(T[] entities, bool isSave = true);

    }
}

2、異步接口的實現

在Ninesky.Base中打開BaseService 添加異步接口的實現,代碼如下

using Microsoft.EntityFrameworkCore;
using Ninesky.InterfaceBase;
using Ninesky.Models;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Ninesky.Base
{
    /// <summary>
    /// 服務基類
    /// </summary>
    public class BaseService<T>:InterfaceBaseService<T> where T:class
    {
        protected DbContext _dbContext;
        public BaseService(DbContext dbContext)
        {
            _dbContext = dbContext;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        public virtual int Add(T entity, bool isSave = true)
        {
            _dbContext.Set<T>().Add(entity);
            if (isSave) return _dbContext.SaveChanges();
            else return 0;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        public virtual async Task<int> AddAsync(T entity, bool isSave = true)
        {
            await _dbContext.Set<T>().AddAsync(entity);
            if (isSave) return await _dbContext.SaveChangesAsync();
            else return 0;
        }

        /// <summary>
        /// 添加[批量]
        /// </summary>
        /// <param name="entities">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        public virtual int AddRange(T[] entities, bool isSave = true)
        {
            _dbContext.Set<T>().AddRange(entities);
            if (isSave) return _dbContext.SaveChanges();
            else return 0;
        }

        /// <summary>
        /// 添加[批量]
        /// </summary>
        /// <param name="entities">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>添加的記錄數[isSave=true時有效]</returns>
        public virtual async Task<int> AddRangeAsync(T[] entities, bool isSave = true)
        {
            await _dbContext.Set<T>().AddRangeAsync(entities);
            if (isSave) return await _dbContext.SaveChangesAsync();
            else return 0;
        }

        /// <summary>
        /// 查詢記錄數
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>記錄數</returns>
        public virtual int Count(Expression<Func<T, bool>> predicate)
        {
            return _dbContext.Set<T>().Count(predicate);
        }

        /// <summary>
        /// 查詢記錄數
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>記錄數</returns>
        public virtual async Task<int> CountAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbContext.Set<T>().CountAsync(predicate);
        }

        /// <summary>
        /// 查詢是否存在
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>是否存在</returns>
        public virtual bool Exists(Expression<Func<T, bool>> predicate)
        {
            return _dbContext.Set<T>().Any(predicate);
        }

        /// <summary>
        /// 查詢是否存在
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>是否存在</returns>
        public virtual async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbContext.Set<T>().AnyAsync(predicate);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="Id">主鍵</param>
        /// <returns></returns>
        public virtual T Find(int Id)
        {
            return _dbContext.Set<T>().Find(Id);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="Id">主鍵</param>
        /// <returns></returns>
        public virtual async Task<T> FindAsync(int Id)
        {
            return await _dbContext.Set<T>().FindAsync(Id);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="keyValues">主鍵</param>
        /// <returns></returns>
        public virtual T Find(object[] keyValues)
        {
            return _dbContext.Set<T>().Find(keyValues);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="keyValues">主鍵</param>
        /// <returns></returns>
        public virtual async Task<T> FindAsync(object[] keyValues)
        {
            return await _dbContext.Set<T>().FindAsync(keyValues);
        }

        public virtual T Find(Expression<Func<T, bool>> predicate)
        {
            return _dbContext.Set<T>().SingleOrDefault(predicate);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns></returns>
        public virtual async Task<T> FindAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbContext.Set<T>().SingleOrDefaultAsync(predicate);
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<T> FindList()
        {
            return _dbContext.Set<T>();
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <returns>實體列表</returns>
        public virtual async Task<IQueryable<T>> FindListAsync()
        {
            IQueryable<T> result = _dbContext.Set<T>();
            return await Task.FromResult(result);
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        public virtual IQueryable<T> FindList(Expression<Func<T, bool>> predicate)
        {
            return _dbContext.Set<T>().Where(predicate);
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        public virtual async Task<IQueryable<T>> FindListAsync(Expression<Func<T, bool>> predicate)
        {
            return await Task.FromResult(FindList(predicate));
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">返回記錄數</param>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        public virtual IQueryable<T> FindList(int number, Expression<Func<T, bool>> predicate)
        {
            var entityList = _dbContext.Set<T>().Where(predicate);
            if (number > 0) return entityList.Take(number);
            else return entityList;
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">返回記錄數</param>
        /// <param name="predicate">查詢條件</param>
        /// <returns>實體列表</returns>
        public virtual async Task<IQueryable<T>> FindListAsync(int number, Expression<Func<T, bool>> predicate)
        {
            return await Task.FromResult(FindList(number, predicate));
        }
        
        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">顯示數量[小於等於0-不啟用]</param>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">正序</param>
        /// <returns></returns>
        public virtual IQueryable<T> FindList<TKey>(int number, Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc)
        {
            var entityList = _dbContext.Set<T>().Where(predicate);
            if (isAsc) entityList = entityList.OrderBy(keySelector);
            else entityList.OrderByDescending(keySelector);
            if (number > 0) return entityList.Take(number);
            else return entityList;
        }

        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="number">顯示數量[小於等於0-不啟用]</param>
        /// <typeparam name="TKey">排序字段</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">正序</param>
        /// <returns></returns>
        public virtual async Task<IQueryable<T>> FindListAsync<TKey>(int number, Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc)
        {
            var entityList = _dbContext.Set<T>().Where(predicate);
            if (isAsc) entityList = entityList.OrderBy(keySelector);
            else entityList.OrderByDescending(keySelector);
            if (number > 0) entityList = entityList.Take(number);
            return await Task.FromResult(entityList);
        }

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="paging">分頁數據</param>
        /// <returns></returns>
        public virtual Paging<T> FindList<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, Paging<T> paging)
        {
            var entityList = _dbContext.Set<T>().Where(predicate);
            paging.Total = entityList.Count();
            if (isAsc) entityList = entityList.OrderBy(keySelector);
            else entityList.OrderByDescending(keySelector);
            paging.Entities = entityList.Skip((paging.PageIndex - 1) * paging.PageSize).Take(paging.PageSize).ToList();
            return paging;
        }

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="paging">分頁數據</param>
        /// <returns></returns>
        public virtual async Task<Paging<T>> FindListAsync<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, Paging<T> paging)
        {
            var entityList = _dbContext.Set<T>().Where(predicate);
            paging.Total = await entityList.CountAsync();
            if (isAsc) entityList = entityList.OrderBy(keySelector);
            else entityList.OrderByDescending(keySelector);
            paging.Entities = await entityList.Skip((paging.PageIndex - 1) * paging.PageSize).Take(paging.PageSize).ToListAsync();
            return paging;
        }

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="pageIndex">當前頁</param>
        /// <param name="pageSize">每頁記錄數</param>
        /// <returns></returns>
        public virtual Paging<T> FindList<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, int pageIndex, int pageSize)
        {
            Paging<T> paging = new Paging<T> { PageIndex = pageIndex, PageSize = pageSize };
            return FindList(predicate, keySelector, isAsc, paging);
        }

        /// <summary>
        /// 查詢[分頁]
        /// </summary>
        /// <typeparam name="TKey">排序屬性</typeparam>
        /// <param name="predicate">查詢條件</param>
        /// <param name="keySelector">排序</param>
        /// <param name="isAsc">是否正序</param>
        /// <param name="pageIndex">當前頁</param>
        /// <param name="pageSize">每頁記錄數</param>
        /// <returns></returns>
        public virtual async Task<Paging<T>> FindListAsync<TKey>(Expression<Func<T, bool>> predicate, Expression<Func<T, TKey>> keySelector, bool isAsc, int pageIndex, int pageSize)
        {
            Paging<T> paging = new Paging<T> { PageIndex = pageIndex, PageSize = pageSize };
            return await FindListAsync(predicate, keySelector, isAsc, paging);
        }

        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否刪除成功[isSave=true時有效]</returns>
        public virtual bool Remove(T entity, bool isSave = true)
        {
            _dbContext.Set<T>().Remove(entity);
            if (isSave) return _dbContext.SaveChanges() > 0;
            else return false;
        }

        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否刪除成功[isSave=true時有效]</returns>
        public virtual async Task<bool> RemoveAsync(T entity, bool isSave = true)
        {
            _dbContext.Set<T>().Remove(entity);
            if (isSave) return await _dbContext.SaveChangesAsync() > 0;
            else return false;
        }


        /// <summary>
        /// 刪除[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>成功刪除的記錄數</returns>
        public virtual int RemoveRange(T[] entities, bool isSave = true)
        {
            _dbContext.Set<T>().RemoveRange(entities);
            if (isSave) return _dbContext.SaveChanges();
            else return 0;
        }

        /// <summary>
        /// 刪除[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>成功刪除的記錄數[isSave=true時有效]</returns>
        public virtual async Task<int> RemoveRangeAsync(T[] entities, bool isSave = true)
        {
            _dbContext.Set<T>().RemoveRange(entities);
            if (isSave) return await _dbContext.SaveChangesAsync();
            else return 0;
        }
        
        /// <summary>
        ///  保存數據
        /// </summary>
        /// <returns>更改的記錄數</returns>
        public virtual int SaveChanges()
        {
            return _dbContext.SaveChanges();
        }

        /// <summary>
        ///  保存數據
        /// </summary>
        /// <returns>更改的記錄數</returns>
        public virtual async Task<int> SaveChangesAsync()
        {
            return await _dbContext.SaveChangesAsync();
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否保存成功</returns>
        public virtual bool Update(T entity, bool isSave = true)
        {
            _dbContext.Set<T>().Update(entity);
            if (isSave) return _dbContext.SaveChanges() > 0;
            else return false;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity">實體</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>是否保存成功[isSave=true時有效]</returns>
        public async Task<bool> UpdateAsync(T entity, bool isSave = true)
        {
            _dbContext.Set<T>().Update(entity);
            if (isSave) return await _dbContext.SaveChangesAsync() > 0;
            else return false;
        }

        /// <summary>
        /// 更新[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>更新成功的記錄數</returns>
        public virtual int UpdateRange(T[] entities, bool isSave = true)
        {
            _dbContext.Set<T>().UpdateRange(entities);
            if (isSave) return _dbContext.SaveChanges();
            else return 0;
        }

        /// <summary>
        /// 更新[批量]
        /// </summary>
        /// <param name="entities">實體數組</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>更新成功的記錄數[isSave=true時有效]</returns>
        public virtual async Task<int> UpdateRangeAsync(T[] entities, bool isSave = true)
        {
            _dbContext.Set<T>().UpdateRange(entities);
            if (isSave) return await _dbContext.SaveChangesAsync();
            else return 0;
        }
    }
}

二、模塊功能

按照設想模塊應該可以包含文章模塊、咨詢模塊、產品模塊、圖片模塊等,這裡先實現文章模塊。由於模塊功能是系統預先寫好的功能,所以模塊不用添加、修改、刪除等功能,只需要顯示和啟用(禁用)就好了。

1、添加模塊模型

在Ninesky.Models中添加Module類

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Ninesky.Models
{
    /// <summary>
    /// 模塊模型
    /// </summary>
    public class Module
    {
        [Key]
        public int ModuleId { get; set; }

        /// <summary>
        /// 模塊名稱
        /// </summary>
        [Required(ErrorMessage = "{0}必填")]
        [StringLength(50)]
        [Display(Name = "模塊名稱")]
        public string Name { get; set; }

        /// <summary>
        /// 模塊控制器
        /// </summary>
        [StringLength(50)]
        [Display(Name = "模塊控制器")]
        public string Controller { get; set; }

        /// <summary>
        /// 模塊說明
        /// </summary>
        [DataType(DataType.MultilineText)]
        [StringLength(1000)]
        [Display(Name = "模塊說明")]
        public string Description { get; set; }

        /// <summary>
        /// 是否啟用
        /// </summary>
        [Required(ErrorMessage = "{0}必填")]
        [Display(Name = "啟用")]
        public bool Enabled { get; set; }

        /// <summary>
        /// 排序
        /// </summary>
        public virtual List<ModuleOrder> ModuleOrders { get; set; }
    }
}

類有個導航屬性ModuleOrders類型是ModuleOrder的列表。這個表示模塊支持的排序類型,在添加欄目的時候選擇排序類型,在前台欄目顯示內容列表的時候按功能進行排序。代碼如下:

using System.ComponentModel.DataAnnotations;


namespace Ninesky.Models
{
    /// <summary>
    /// 模塊排序類型
    /// </summary>
    public class ModuleOrder
    {
        [Key]
        public int ModuleOrderId { get; set; }

        /// <summary>
        /// 模塊ID
        /// </summary>
        [Required]
        [Display(Name = "模塊ID")]
        public int ModuleId { get; set; }

        /// <summary>
        /// 名稱
        /// </summary>
        [Required]
        [StringLength(50)]
        [Display(Name = "名稱")]
        public string Name { get; set; }

        /// <summary>
        /// 值
        /// </summary>
        [Required]
        [Display(Name = "值")]
        public int Order { get; set; }

        /// <summary>
        /// 模塊
        /// </summary>
        public virtual Module Module { get; set; }
    }
}

2、模塊接口

在Ninesky.InterfaceBase添加模塊的接口Ninesky.InterfaceBase,繼承自InterfaceBaseService<Module>,並添加兩個新的方法。查找模塊列表和查找模塊支持的排序列表

using Ninesky.Models;
using System.Linq;
using System.Threading.Tasks;

namespace Ninesky.InterfaceBase
{
    public interface InterfaceModuleService:InterfaceBaseService<Module>
    {
        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="enable">啟用</param>
        /// <returns></returns>
        Task<IQueryable<Module>> FindListAsync(bool? enable);
        /// <summary>
        /// 查找排序列表
        /// </summary>
        /// <param name="moduleId">模塊ID</param>
        /// <returns></returns>
        Task<IQueryable<ModuleOrder>> FindOrderListAsync(int moduleId);
    }
}

3、在Ninesky.Base中添加類ModuleService來實現模塊接口

using Microsoft.EntityFrameworkCore;
using Ninesky.InterfaceBase;
using Ninesky.Models;
using System.Linq;
using System.Threading.Tasks;

namespace Ninesky.Base
{
    public class ModuleService:BaseService<Module>,InterfaceModuleService
    {
        public ModuleService(DbContext dbContext) : base(dbContext)
        { }

        public override Module Find(int Id)
        {
            return _dbContext.Set<Module>().Include(m => m.ModuleOrders).SingleOrDefault(m => m.ModuleId == Id);
        }

        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="enable">啟用</param>
        /// <returns></returns>
        public async Task<IQueryable<Module>> FindListAsync(bool? enable)
        {
            if (enable == null) return await FindListAsync();
            else return await FindListAsync(m => m.Enabled == enable);
        }
        /// <summary>
        /// 查找排序列表
        /// </summary>
        /// <param name="moduleId">模塊ID</param>
        /// <returns></returns>
        public async Task<IQueryable<ModuleOrder>> FindOrderListAsync(int moduleId)
        {
            return await Task.FromResult(_dbContext.Set<ModuleOrder>().Where(mo => mo.ModuleId == moduleId));
        }
    }
}

4、模塊控制器

在Ninesky.Web.Areas.System.Controllers中添加模塊控制器ModuleController,控制器有一個幾個功能

  • Index,首頁,返回頁面視圖,在視圖沖通過ajax方式加載模塊列表
  • List,模塊列表,返回json類型數據,方便其他視圖調用。
  • Details,詳細視圖,包含功能信息和排序列表,可以在次視圖中啟用或禁用模塊
  • Enable,啟用或禁用模塊,此Action沒有視圖,通過post提交數據,返回json類型的操作狀態數據
  • OrderList,模塊排序列表,返回json類型數據。

Enable方法返回操作結果時,考慮到不光要返回是否操作成功,可能還要返回消息字符串,所以專門寫個類型統一返回ajax操作的結果。把類型命名為JsonResponse,放到Ninesky.Web.Models下,代碼如下圖:

namespace Ninesky.Web.Models
{
    /// <summary>
    /// 返回Json數據類型
    /// </summary>
    public class JsonResponse
    {
        /// <summary>
        /// 操作是否成功
        /// </summary>
        public bool succeed { get; set; }

        /// <summary>
        /// 操作結果詳細代碼【必要時】
        /// </summary>
        public int code { get; set; }

        /// <summary>
        /// 操作結果消息
        /// </summary>
        public string message { get; set; }

        /// <summary>
        /// 操作產生的數據【必要時】
        /// </summary>
        public dynamic Data { get; set; }

        public JsonResponse()
        {
            succeed = false;
            message = "未知錯誤";
        }
    }
}

整個控制器代碼如下:

using Microsoft.AspNetCore.Mvc;
using Ninesky.InterfaceBase;
using Ninesky.Web.Models;
using System.Linq;
using System.Threading.Tasks;

namespace Ninesky.Web.Areas.System.Controllers
{
    [Area("System")]
    public class ModuleController : Controller
    {
        private InterfaceModuleService _moduleService;

        public ModuleController(InterfaceModuleService moduleService)
        {
            _moduleService = moduleService;
        }

        /// <summary>
        /// 詳細
        /// </summary>
        /// <param name="id">模塊ID</param>
        /// <returns></returns>
        public async Task<IActionResult> Details(int id)
        {
            return View(await _moduleService.FindAsync(id));
        }

        [HttpPost]
        public async Task<IActionResult> Enable (int id, bool enabled)
        {
            JsonResponse jsonResponse = new JsonResponse();
            var module = await _moduleService.FindAsync(id);
            if(module == null)
            {
                jsonResponse.succeed = false;
                jsonResponse.message = "模塊不存在";
            }
            else
            {
                module.Enabled = enabled;
                if(await _moduleService.UpdateAsync(module))
                {
                    jsonResponse.succeed = true;
                    jsonResponse.message = "模塊已" + (enabled ? "啟用" : "禁用");
                }
                else
                {
                    jsonResponse.succeed = false;
                    jsonResponse.message = "保存數據失敗";
                }
            }
            return Json(jsonResponse);
        }

        public IActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 模塊列表
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> List()
        {
            return Json((await _moduleService.FindListAsync()).ToList());
        }

        /// <summary>
        /// 排序列表
        /// </summary>
        /// <param name="id">模塊Id</param>
        /// <returns></returns>
        public async Task<IActionResult> OrderList(int id)
        {
            return Json((await _moduleService.FindOrderListAsync(id)).ToList());
        }

    }
}

5、視圖

在控制器代碼中可以看出只有兩個action返回了視圖,一個是Index,另一個是Details。

模塊首頁視圖

在控制器中index沒有像視圖提供數據,在視圖中通過ajax方式加載。在視圖中使用bootstrapTable組件來顯示視圖列表。改組件可以在項目的依賴項->Bower【右鍵】->管理Bower程序包中搜索bootstrap-Table,並安裝。

視圖代碼:

@{
    ViewData["Title"] = "模塊管理";
}

<ol class="breadcrumb">
    <li><span class="fa fa-home"></span>  <a asp-controller="Home" asp-action="Index">首頁</a></li>
    <li><a asp-controller="System" asp-action="Index">系統配置</a></li>
    <li class="active">模塊管理</li>
</ol>
<table id="moduletable"></table>

@section aside{

    @Html.Partial("SystemAside")
}
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script type="text/javascript">
        $(document).ready(function () {
            $('#moduletable').bootstrapTable({
                url: '@Url.Action("List")',
                columns: [{
                    field: 'moduleId',
                    title: '序號'
                }, {
                    field: 'name',
                    title: '名稱',
                    formatter: function (value, row, index) {
                        return '<a href="@Url.Action("Details")/' + row.moduleId + '">' + value + '</a>';
                    }
                }, {
                    field: 'controller',
                    title: '控制器'
                }, {
                    field: 'description',
                    title: '說明'
                }, {
                    field: 'enabled',
                    title: '狀態',
                    formatter:function(value,row,index)
                    {
                        return value ? '<i class="fa fa-check" aria-hidden="true"></i>' : '<i class="fa fa-ban" aria-hidden="true"></i>';
                    }
                }]
            });
        });
    </script>
}

完成的效果圖

詳細信息視圖

Details中使用了tabs,一個標簽顯示基本信息,另一個標簽顯示排序列表。基本信息的啟用屬性使用checkbox,點擊可以啟用/禁用模塊。排序列表繼續使用bootstrapTable組件顯示列表。

@model Ninesky.Models.Module
@{
    ViewData["Title"] = Model.Name;
}

<ol class="breadcrumb">
    <li><span class="fa fa-home"></span>  <a asp-controller="Home" asp-action="Index">首頁</a></li>
    <li><a asp-controller="System" asp-action="Index">系統配置</a></li>
    <li><a asp-controller="Module" asp-action="Index">模塊管理</a></li>
    <li class="active">@Model.Name</li>
</ol>


@section aside{

    @Html.Partial("SystemAside")
}
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#base" role="tab" data-toggle="tab">基本信息</a></li>
    <li role="presentation"><a href="#order" role="tab" data-toggle="tab">排序方式</a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="base">
        <input type="hidden" asp-for="ModuleId" />
        <dl class="dl-horizontal">
            <dt>
                <label asp-for="Name"></label>
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Name)
            </dd>
            <dt>
                <label asp-for="Controller"></label>
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Controller)
            </dd>
            <dt>
                <label asp-for="Description"></label>
            </dt>
            <dd>
                @Html.DisplayFor(model => model.Description)
            </dd>
            <dt>
                <label asp-for="Enabled"></label>
            </dt>
            <dd>
                <input type="checkbox" asp-for="Enabled" />
            </dd>
        </dl>
    </div>
    <div role="tabpanel" class="tab-pane" id="order"><table id="moduleordertable"></table></div>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script type="text/javascript">
        $(document).ready(function () {
            $('#moduleordertable').bootstrapTable({
                url: '@Url.Action("OrderList",new{
            id=Model.ModuleId})',
                columns: [{
                    field: 'moduleOrderId',
                    title: '序號'
                }, {
                    field: 'name',
                    title: '名稱',
                }, {
                    field: 'order',
                    title: '值'
                }]
            });
            $('#Enabled').click(function () {
                $.post('@Url.Action("Enable", "Module")', { id: $('#ModuleId').val(), enabled: $('#Enabled').prop('checked') }, function (response) { 
                    if(response.succeed)
                    {
                        BootstrapDialog.alert({
                            title:'消息',
                            message: response.message,
                            buttonLabel: '確定'
                        });

                    }
                }, 'json');
            });
        });
    </script>
}

界面顯示如下:

 

三、欄目

1、欄目接口

通常會用樹形菜單的形式顯示欄目結構,需要添加欄目的樹形菜單數據,需要添加一個方法,另外顯示子欄目也需要添加一個方法。

在欄目接口中添加方法。

using Ninesky.Models;
using System.Linq;
using System.Threading.Tasks;

namespace Ninesky.InterfaceBase
{
    /// <summary>
    /// 欄目服務接口
    /// </summary>
    public interface InterfaceCategoryService:InterfaceBaseService<Category>
    {
        /// <summary>
        /// 查找樹形菜單
        /// </summary>
        /// <param name="categoryType">欄目類型,可以為空</param>
        /// <returns></returns>
        Task<IQueryable<Category>> FindTreeAsync(CategoryType? categoryType);

        /// <summary>
        /// 查找子欄目
        /// </summary>
        /// <param name="id">欄目ID</param>
        /// <returns></returns>
        IQueryable<Category> FindChildren(int id);

        /// <summary>
        /// 查找子欄目
        /// </summary>
        /// <param name="id">欄目ID</param>
        /// <returns></returns>
        Task<IQueryable<Category>> FindChildrenAsync(int id);
    }
}

2、接口的實現。

  • 在基類中的方法只返回欄目實體並沒有返回外鍵,所以實現類中需要重寫查找欄目的方法將三種欄目類型的導航屬性都加載進來。
  • 查找子欄目的方法直接返回結果就行。
  • 查找欄目樹稍微麻煩點,在添加欄目的時候需要選擇父欄目,父欄目的類型只能是常規欄目,所以方法要有欄目類型參數:在參數為null時返回所有欄目列表;欄目不為空時,先在數據庫中查找所有此類型的欄目,然後根據ParentPath來取出所有的父欄目(重復的剔除)。計劃在前台使用ztree組件顯示樹,該組件有個簡單數據類型,根據pid自動生成樹,這裡就不用在組織成樹形接口直接返回列表就可以了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ninesky.Models;
using Ninesky.InterfaceBase;

namespace Ninesky.Base
{
    /// <summary>
    /// 欄目服務類
    /// </summary>
    public class CategoryService:BaseService<Category>,InterfaceCategoryService
    {
        public CategoryService(DbContext dbContext):base(dbContext)
        {
        }
        /// <summary>
        /// 查找
        /// </summary>
        /// <param name="Id">欄目ID</param>
        /// <returns></returns>
        public override Category Find(int Id)
        {
            return _dbContext.Set<Category>().Include("General").Include("Page").Include("Link").SingleOrDefault(c => c.CategoryId == Id);
        }

        /// <summary>
        /// 查找子欄目
        /// </summary>
        /// <param name="id">欄目ID</param>
        /// <returns></returns>
        public IQueryable<Category> FindChildren(int id)
        {
            return FindList(0, c => c.ParentId == id, c => c.Order, true);
        }

        /// <summary>
        /// 查找子欄目
        /// </summary>
        /// <param name="id">欄目ID</param>
        /// <returns></returns>
        public async Task<IQueryable<Category>> FindChildrenAsync(int id)
        {
            return await FindListAsync(0, c => c.ParentId == id, c => c.Order, true);
        }

        /// <summary>
        /// 查找樹形菜單
        /// </summary>
        /// <param name="categoryType">欄目類型,可以為空</param>
        /// <returns></returns>
        public async Task<IQueryable<Category>> FindTreeAsync(CategoryType? categoryType)
        {
            var categories = await FindListAsync();
            //根據欄目類型分類處理
            switch (categoryType)
            {
                case null:
                    break;
                case CategoryType.General:
                    categories = categories.Where(c => c.Type == categoryType);
                    break;
                    //默認-Page或Link類型
                default:
                    //Id數組-含本欄目及父欄目
                    List<int> idArray = new List<int>();
                    //查找欄目id及父欄目路徑
                    var categoryArray = categories.Where(c => c.Type == categoryType).Select(c => new { CategoryId = c.CategoryId, ParentPath = c.ParentPath });
                    if(categoryArray != null)
                    {
                        //添加欄目ID到
                        idArray.AddRange(categoryArray.Select(c => c.CategoryId));
                        foreach (var parentPath in categoryArray.Select(c=>c.ParentPath))
                        {
                            var parentIdArray = parentPath.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            if (parentIdArray != null)
                            {
                                int parseId = 0;
                                foreach(var parentId in parentIdArray)
                                {
                                    if (int.TryParse(parentId, out parseId)) idArray.Add(parseId);
                                }
                            }
                        }
                    }
                    categories = categories.Where(c => idArray.Contains(c.CategoryId));
                    break;
            }
            return categories.OrderBy(c => c.ParentPath).ThenBy(C => C.Order);
        }
    }
}

3、欄目控制器。

欄目控制器有一下幾個action

  • Index,首頁,返回頁面視圖
  • Add,添加欄目,一個有兩個action,一個用於顯示,另一個接受post過來的數據進行處理。
  • Tree,全部欄目數據,返回json類型數據用於顯示側欄顯示。
  • ParentTree,常規欄目數據,返回json類型的常規欄目及其父欄目數據,用於選擇父欄目時控件。

在顯示樹形菜單時使用的ztree組件,是一個功能非常強大的國產組件,需要的朋友可以去看看http://www.treejs.cn/v3/api.php

控制器中只有Add方法麻煩一點,添加時需要對其父欄目和導航屬性進行判斷和處理。代碼如下:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Ninesky.InterfaceBase;
using Ninesky.Models;
using Ninesky.Web.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Ninesky.Web.Areas.System.Controllers
{
    /// <summary>
    /// 欄目控制器
    /// </summary>
    [Area("System")]
    public class CategoryController : Controller
    {
        private InterfaceCategoryService _categoryService;
        public CategoryController(InterfaceCategoryService categoryService)
        {
            _categoryService = categoryService;
        }

        public async Task<IActionResult> Add([FromServices]InterfaceModuleService moduleService, CategoryType? categoryType)
        {

            var modules = await moduleService.FindListAsync(true);
            var modeleArry = modules.Select(m => new SelectListItem { Text = m.Name, Value = m.ModuleId.ToString() }).ToList();
            modeleArry.Insert(0, new SelectListItem() { Text = "無", Value = "0", Selected = true });
            ViewData["Modules"] = modeleArry;
            return View(new Category() { Type = CategoryType.General, ParentId = 0, View="Index", Order = 0, Target = LinkTarget._self, General = new CategoryGeneral() { ContentView = "Index" } });
        }

        [HttpPost]
        public async Task<IActionResult>  Add([FromServices]InterfaceModuleService moduleService,Category category)
        {
            if(ModelState.IsValid)
            {
                //檢查父欄目
                if (category.ParentId > 0)
                {
                    var parentCategory = await _categoryService.FindAsync(category.ParentId);
                    if (parentCategory == null) ModelState.AddModelError("ParentId", "父欄目不存在");
                    else if (parentCategory.Type != CategoryType.General) ModelState.AddModelError("ParentId", "父欄目不能添加子欄目");
                    else category.ParentPath = parentCategory.ParentPath + "," + parentCategory.CategoryId;
                }
                else category.ParentPath = "0";
                //檢查欄目類型
                switch (category.Type)
                {
                    case CategoryType.General:
                        if (category.General == null) ModelState.AddModelError("General.Type", "請填寫常規欄目內容");
                        else
                        {
                            if (category.General.ModuleId > 0)
                            {
                                if (string.IsNullOrEmpty(category.General.ContentView)) ModelState.AddModelError("General.ContentView", "請填寫欄目視圖");
                                if (category.General.ContentOrder == null) ModelState.AddModelError("General.ContentOrder", "請選擇內容排序方式");
                            }
                            else
                            {
                                if (category.Page != null) category.Page = null;
                                if (category.Link != null) category.Link = null;
                            }
                        }
                        break;
                    case CategoryType.Page:
                        //檢查
                        if (category.Page == null) ModelState.AddModelError("General.Type", "請填寫單頁欄目內容");
                        else
                        {
                            if (string.IsNullOrEmpty(category.Page.Content)) ModelState.AddModelError("Page.Content", "請輸入單頁欄目內容");
                            else
                            {
                                if (category.General != null) category.General = null;
                                if (category.Link != null) category.Link = null;
                            }
                        }
                        break;
                    case CategoryType.Link:
                        //檢查
                        if (category.Link == null) ModelState.AddModelError("General.Type", "請填寫連接欄目內容");
                        else
                        {
                            if (string.IsNullOrEmpty(category.Link.Url)) ModelState.AddModelError("Link.Url", "請選擇輸入鏈接地址");
                            else
                            {
                                if (category.General != null) category.General = null;
                                if (category.General != null) category.General = null;
                            }
                        }
                        break;
                }
                
                //保存到數據庫
                if(ModelState.IsValid)
                {
                    if (await _categoryService.AddAsync(category) > 0) return View("AddSucceed", category);
                    else ModelState.AddModelError("", "保存數據失敗");
                }
            }
            var modules = await moduleService.FindListAsync(true);
            var modeleArry = modules.Select(m => new SelectListItem { Text = m.Name, Value = m.ModuleId.ToString() }).ToList();
            modeleArry.Insert(0, new SelectListItem() { Text = "無", Value = "0", Selected = true });
            ViewData["Modules"] = modeleArry;
            return View(category);
        }

        /// <summary>
        /// 欄目首頁
        /// </summary>
        /// <returns></returns>
        public IActionResult Index()
        {
            return View("Index");
        }

        /// <summary>
        /// 父欄目樹
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> ParentTree()
        {
            var categories = await _categoryService.FindTreeAsync(CategoryType.General);
            return Json(categories.Select(c => new zTreeNode { id = c.CategoryId, name = c.Name, pId = c.ParentId, iconSkin="fa fa-folder" }));
        }

        /// <summary>
        /// 欄目樹
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> Tree()
        {
            List<zTreeNode> nodes;
            var categories = await _categoryService.FindTreeAsync(null);
            if (categories != null)
            {
                nodes = new List<zTreeNode>(categories.Count());
                foreach(var category in categories)
                {
                    var node = new zTreeNode() { id = category.CategoryId, pId= category.ParentId, name = category.Name, url = Url.Action("Details", "Category", new { id = category.CategoryId }) };
                    switch(category.Type)
                    {
                        case CategoryType.General:
                            node.iconSkin = "fa fa-folder";
                            node.iconOpen = "fa fa-folder-open";
                            node.iconClose = "fa fa-folder";
                            break;
                        case CategoryType.Page:
                            node.iconSkin = "fa fa-file";
                            break;
                        case CategoryType.Link:
                            node.iconSkin = "fa fa-link";
                            break;
                    }
                    nodes.Add(node);
                }
            }
            else nodes = new List<zTreeNode>();
            return Json(nodes);
        }
    }
}
 

4、視圖

左側導航欄視圖

視圖名Aside,視圖中采用ztree加載欄目樹

<div class="panel panel-default">
    <div class="panel-heading">
        <h5 class="panel-title"><span class="fa fa-list"></span> 欄目列表</h5>
    </div>
    <div class="panel-body">
        <ul id="categoryTree" data-url="@Url.Action("Tree", "Category")" class="ztree"></ul>
    </div>
</div>

添加欄目視圖

html、js都混在一起了代碼很亂,湊活看吧。

@model Ninesky.Models.Category
@{
    ViewData["Title"] = "添加欄目";
}

<ol class="breadcrumb">
    <li><span class="fa fa-home"></span>  <a asp-controller="Home" asp-action="Index">首頁</a></li>
    <li><a asp-controller="Category" asp-action="Index">欄目管理</a></li>
    <li class="active">添加常規欄目</li>
</ol>

<div class="panel panel-default">
    <div class="panel-body">
        <form asp-action="Add">
            <div class="form-horizontal">
                <div asp-validation-summary="All" class="text-danger"></div>
                <ul class="nav nav-tabs" role="tablist">
                    <li role="presentation" class="active"><a href="#base" role="tab" data-toggle="tab">基本信息</a></li>
                    <li role="presentation"><a href="#general" role="tab" data-toggle="tab">常規欄目</a></li>
                    <li role="presentation"><a href="#page" role="tab" data-toggle="tab">單頁欄目</a></li>
                    <li role="presentation"><a href="#link" role="tab" data-toggle="tab">鏈接欄目</a></li>
                </ul>

                <!-- Tab panes -->
                <div class="tab-content">
                    <div role="tabpanel" class="tab-pane active" id="base">
                        <div class="form-group">
                            <label asp-for="ParentId" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <div class="input-group" >
                                    <input id="ParentId-text" type="text" class="form-control" readonly value="無" />
                                    <ul id="ParentId-dropdown" class="dropdown-menu dropdown-menu-left ztree"></ul>
                                    <div class="input-group-btn">
                                        <button id="ParentId-btn" type="button" class="btn btn-default"><span class="caret"></span></button>
                                    </div>
                                    <input asp-for="ParentId" class="form-control"  />
                                </div>
                                <span asp-validation-for="ParentId" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="Type" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <select asp-for="Type" asp-items="Html.GetEnumSelectList<Ninesky.Models.CategoryType>()" class="selectpicker form-control" data-></select>
                                <span asp-validation-for="Type" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="Name" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <input asp-for="Name" class="form-control" />
                                <span asp-validation-for="Name" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="View" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <input asp-for="View" class="form-control" />
                                <span asp-validation-for="View" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="Order" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <input asp-for="Order" class="form-control" />
                                <span asp-validation-for="Order" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="Target" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <select asp-for="Target" asp-items="Html.GetEnumSelectList<Ninesky.Models.LinkTarget>()" class="selectpicker form-control" data-></select>
                                <span asp-validation-for="Target" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="Description" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <textarea asp-for="Description" class="form-control"></textarea>
                                <span asp-validation-for="Description" class="text-danger"></span>
                            </div>
                        </div>

                    </div>
                    <div role="tabpanel" class="tab-pane" id="general">
                        <div class="form-group">
                            <label asp-for="General.ModuleId" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <select asp-for="General.ModuleId" asp-items="@ViewData["Modules"] as List<SelectListItem>" class="selectpicker form-control" data-></select>
                                <span asp-validation-for="General.ModuleId" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="General.ContentView" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <input asp-for="General.ContentView" class="form-control" />
                                <span asp-validation-for="General.ContentView" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label asp-for="General.ContentOrder" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <select asp-for="General.ContentOrder" class="form-control"></select>
                                <span asp-validation-for="General.ContentOrder" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <div role="tabpanel" class="tab-pane" id="page">
                        <div class="form-group">
                            <label asp-for="Page.Content" class="control-label"></label>
                            
                                <textarea asp-for="Page.Content" ></textarea>
                                <span asp-validation-for="Page.Content" class="text-danger"></span>
                            
                        </div>
                    </div>
                    <div role="tabpanel" class="tab-pane" id="link">
                        <div class="form-group">
                            <label asp-for="Link.Url" class="col-md-2 control-label"></label>
                            <div class="col-md-10">
                                <input asp-for="Link.Url" class="form-control" />
                                <span asp-validation-for="Link.Url" class="text-danger"></span>
                            </div>
                        </div>
                    </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>
        </form>
    </div>
</div>
@section aside{

    @Html.Partial("Aside")
}
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script src="~/lib/ueditor/ueditor.config.js"></script>
    <script src="~/lib/ueditor/ueditor.all.min.js"></script>
    <script type="text/javascript">
        var dropdownCategoryTree;
        var setting = {
            data: {
                simpleData: {
                    enable: true,
                    idKey: "id",
                    pIdKey: "pId",
                    rootPId: 0
                }
            },
            async: {
                enable: true,
                url: "@Url.Action("ParentTree", "Category")"
            },
            callback: {
                onClick: function (event, treeId, treeNode) {
                    $("#ParentId").val(treeNode.id);
                    $("#ParentId-text").val(treeNode.name);
                    $("#ParentId-dropdown").hide();
                }
            }
        };
        function toggleContent() {
            if ($("#General_ModuleId").selectpicker('val') == "") {
                $("#General_ContentOrder").empty();
            }
            else {
                $.post("@Url.Action("OrderList","Module")", { id: $('#General_ModuleId').val() }, function (data) {
                    if (data != undefined) {
                        $.each(data, function (ndex, element) {
                            $("#General_ContentOrder").append("<option value='" + element.order + "'>" + element.name + "</option>");
                        })
                    }
                }, 'json');

            }
        }
        // zTree 的參數配置,深入使用請參考 API 文檔(setting 配置詳解)
        $(document).ready(function () {
            dropdownCategoryTree = $.fn.zTree.init($("#ParentId-dropdown"), setting);
            dropdownCategoryTree.addNodes(null, { id: 0, name: "無" });
            $("#ParentId-text").click(function () {
                $("#ParentId-dropdown").show();
            });
            $("#ParentId-btn").click(function () {
                $("#ParentId-dropdown").show();
            });
            toggleContent();
            $('#General_ModuleId').on('changed.bs.select', function (e) {
                toggleContent();
            });
            //富文本編輯器
            var ue = UE.getEditor('Page_Content');
        });
    </script>
}

添加成功的視圖

@model Ninesky.Models.Category
@{
    ViewData["Title"] = "添加欄目";
}

<ol class="breadcrumb">
    <li><span class="fa fa-home"></span>  <a asp-controller="Home" asp-action="Index">首頁</a></li>
    <li><a asp-controller="Category" asp-action="Index">欄目管理</a></li>
    <li class="active">添加欄目</li>
</ol>

<div class="alert alert-success fade in" role="alert">
    <h4><i class="fa fa-check"></i> 添加成功 </h4>
    <p>您已成功添加欄目【@Model.Name】</p>
    <p>
        <a href="@Url.Action("Add")" class="btn btn-default">添加欄目</a>
        <a href="@Url.Action("Details","Category",new {id=Model.CategoryId })" class="btn btn-default">修改欄目</a>
    </p>
</div>
@section aside{

    @Html.Partial("Aside")
}

四、其他

 

代碼托管地址:https://git.oschina.net/ninesky/Ninesky

文章發布地址:http://www.ninesky.cn

                 http://mzwhj.cnblogs.com/

代碼包下載:Ninesky2.4.rar

 

返回目錄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved