通过开发一个新闻功能来了解UrShop
第一步:在Urs.Data 创建Domain与Mapping
using System; using Urs.Core; namespace Urs.Data.Domain.News { /// <summary> /// 资讯 /// </summary> public partial class NewsItem : BaseEntity { /// <summary> /// 标题 /// </summary> public virtual string Title { get; set; } /// <summary> /// 简介 /// </summary> public virtual string Short { get; set; } /// <summary> /// 内容 /// </summary> public virtual string Full { get; set; } /// <summary> /// 发布 /// </summary> public virtual bool Published { get; set; } /// <summary> /// 创建时间 /// </summary> public virtual DateTime CreateTime { get; set; } } }
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Urs.Data.Domain.News; namespace Urs.Data.Mapping.News { public partial class NewsItemMap : UrsEntityTypeConfiguration<NewsItem> { public override void Configure(EntityTypeBuilder<NewsItem> builder) { builder.ToTable("news"); builder.HasKey(bp => bp.Id); base.Configure(builder); } } }
第二步:Urs.Services编写接口与接口实现
这里面用到了缓存;缓存接口为ICacheManager 封装了基础方法
缓存基础教程请看《Cache缓存基础教程》
using Urs.Core; using Urs.Data.Domain.News; namespace Urs.Services.News { public partial interface INewsService { void DeleteNews(NewsItem newsItem); NewsItem GetNewsById(int newsId); IPagedList<NewsItem> GetAllNews(int pageIndex, int pageSize, bool showHidden = false); void InsertNews(NewsItem news); void UpdateNews(NewsItem news); } }
using System; using System.Linq; using Urs.Core; using Urs.Core.Caching; using Urs.Core.Data; using Urs.Data.Domain.News; namespace Urs.Services.News { public partial class NewsService : INewsService { #region Constants private const string NEWS_BY_ID_KEY = "Urs.news.id-{0}"; private const string NEWS_PATTERN_KEY = "Urs.news."; #endregion #region Fields private readonly IRepository<NewsItem> _newsItemRepository; private readonly ICacheManager _cacheManager; #endregion #region Ctor public NewsService(IRepository<NewsItem> newsItemRepository, ICacheManager cacheManager) { _newsItemRepository = newsItemRepository; _cacheManager = cacheManager; } #endregion #region NewsItem public virtual void DeleteNews(NewsItem newsItem) { if (newsItem == null) throw new ArgumentNullException("newsItem"); _newsItemRepository.Delete(newsItem); _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY); } 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; }); } public virtual IPagedList<NewsItem> GetAllNews(int pageIndex, int pageSize, bool showHidden = false) { var query = _newsItemRepository.Table; if (!showHidden) { var utcNow = DateTime.Now; query = query.Where(n => n.Published); } query = query.OrderByDescending(b => b.CreateTime); var news = new PagedList<NewsItem>(query, pageIndex, pageSize); return news; } public virtual void InsertNews(NewsItem news) { if (news == null) throw new ArgumentNullException("news"); _newsItemRepository.Insert(news); _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY); } public virtual void UpdateNews(NewsItem news) { if (news == null) throw new ArgumentNullException("news"); _newsItemRepository.Update(news); _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY); } #endregion } }
第三步:后端功能开发,创建NewsController,并添加增删改查功能;
通过 _permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel) 方法判断是否有权限;如果要给新闻模块独立权限需要在StandardPermissionProvider做配置;权限不足返回:HttpUnauthorized();
如果需要用到DTO的话需要在Models创建一个Models,命名以[名称]+Model;DTO采用了AutoMapper;
AutoMapper基础教程请看《AutoMapper基础学习教程》
AdminAuthorize 请看《AdminAuthorize后端权限说明》
using Microsoft.AspNetCore.Mvc; using System; using System.Linq; using Urs.Admin.Models.News; using Urs.Data.Domain.News; using Urs.Framework.Controllers; using Urs.Framework.Extensions; using Urs.Framework.Kendoui; using Urs.Services.News; using Urs.Services.Security; namespace Urs.Admin.Controllers { [AdminAuthorize] public partial class NewsController : BaseAdminController { #region Fields private readonly INewsService _newsService; private readonly IPermissionService _permissionService; #endregion #region Constructors public NewsController(INewsService newsService, IPermissionService permissionService) { this._newsService = newsService; this._permissionService = permissionService; } #endregion #region News items public IActionResult List() { if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel)) return HttpUnauthorized(); return View(); } [HttpPost] public IActionResult List(PageRequest command) { if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel)) return HttpUnauthorized(); var news = _newsService.GetAllNews(command.Page - 1, command.Limit, true); var gridModel = new ResponseResult { data = news.Select(x => { var m = x.ToModel<NewsItemModel>(); m.CreateTime = x.CreateTime; return m; }), count = news.TotalCount }; return Json(gridModel); } public IActionResult Edit(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel)) return HttpUnauthorized(); var newsItem = _newsService.GetNewsById(id); if (newsItem == null) { var model = new NewsItemModel(); return View(model); } else { var model = newsItem.ToModel<NewsItemModel>(); return View(model); } } [HttpPost] public IActionResult Edit(NewsItemModel model, bool continueEditing) { if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel)) return HttpUnauthorized(); var newsItem = _newsService.GetNewsById(model.Id); if (newsItem == null) { var newsItems = model.ToEntity<NewsItem>(); newsItems.CreateTime = DateTime.Now; _newsService.InsertNews(newsItems); } else { if (ModelState.IsValid) { newsItem = model.ToEntity(newsItem); _newsService.UpdateNews(newsItem); } } return Json(new { success = 1 }); } [HttpPost] public IActionResult Delete(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel)) return HttpUnauthorized(); var newsItem = _newsService.GetNewsById(id); if (newsItem == null) return Json(new { error = 1 }); _newsService.DeleteNews(newsItem); return Json(new { success = 1 }); } #endregion } }
前端实现:
<div class="layui-fluid"> <div class="layui-card"> <div class="layui-card-header layuiadmin-card-header-auto"> <button class="layui-btn layui-btn-normal layuiadmin-btn-tags" data-type="add">添加</button> </div> <div class="layui-card-body"> <table id="LAY-topic-list" lay-filter="LAY-topic-list"></table> <script type="text/html" id="layuiadmin-app-cont-tagsbar"> <a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a> </script> </div> </div> </div> <script src="../../../layuiadmin/layui/layui.js"></script> <script type="text/html" id="publishedTpl"> {{# if(d.Published){ }} <button class="layui-btn layui-btn-xs">已上架</button> {{# } else { }} <button class="layui-btn layui-btn-primary layui-btn-xs">已下架</button> {{# } }} </script> <script> layui.config({ base: '../../../layuiadmin/' //静态资源所在路径 }).extend({ index: 'lib/index' //主入口模块 }).use(['index','table'], function () { var index = layer.load(2, { shade: false }); var table = layui.table; //分类管理 table.render({ elem: '#LAY-topic-list' , url: '@Html.Raw(Url.Action("List", "News"))' //模拟接口 ,method:'post' , page: true //开启分页 , even: true , limit: 15 , limits: [15,30,50,100] , cols: [[ { type: 'numbers', fixed: 'left' } , { field: 'Id', width: 100, title: 'ID' } , { field: 'Title', title: '标题', minWidth: 100 } , { field: 'StartDate', title: '开始时间', minWidth: 150 } , { field: 'EndDate', title: '结束时间', minWidth: 150 } , { field: 'CreatedOn', title: '创建时间', minWidth: 150 } , { field: 'Published', title: '是否上架', templet: '#publishedTpl', minWidth: 80, align: 'center' } , { title: '操作', width: 150, align: 'center', fixed: 'right', toolbar: '#layuiadmin-app-cont-tagsbar' } ]] , text: { none: '一条数据也没有^_^' } , done: function () { layer.close(index); } }); //监听工具条 table.on('tool(LAY-topic-list)', function (obj) { var data = obj.data; if (obj.event === 'del') { layer.confirm('确定删除?', function (index) { obj.del(); $.post('@Url.Action("Delete")', { id: obj.data.Id }); layer.close(index); }); } else if (obj.event === 'edit') { var tr = $(obj.tr); window.location.href = '@Url.Action("Edit")?id=' + data.Id; } }); var $ = layui.$, active = { add: function () { window.location.href = '@Url.Action("Edit")'; } } $('.layui-btn.layuiadmin-btn-tags').on('click', function () { var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); }); </script>
@model Urs.Admin.Models.News.NewsItemModel <div class="layui-fluid"> <div class="layui-row layui-col-space15"> <div class="layui-col-md12"> <div class="layui-card"> <div class="layui-card-header">新闻 <a href="javascript:;" layadmin-event="back">返回</a></div> <div class="layui-card-body"> <div class="layui-form" wid100 lay-filter=""> <input asp-for="Id" type="hidden" /> <div class="layui-form-item"> <div class="col-md-2"> <nop-label asp-for="Title" /> </div> <div class="layui-input-inline" style="width:800px;"> <nop-editor asp-for="Title" /> <span asp-validation-for="Title"></span> </div> </div> <div class="layui-form-item"> <div class="col-md-2"> <nop-label asp-for="Short" /> </div> <div class="layui-input-inline" style="width:800px;"> <nop-textarea asp-for="Short"></nop-textarea> <span asp-validation-for="Short"></span> </div> </div> <div class="layui-form-item"> <nop-label asp-for="Full" /> <div class="layui-input-inline" style="width:800px;height:420px"> <nop-editor asp-for="Full" asp-template="UEditor" /> <span asp-validation-for="Full"></span> </div> </div> <div class="layui-form-item"> <div class="col-md-2"> <nop-label asp-for="Published" /> </div> <div class="layui-input-inline"> <nop-bool asp-for="Published" /> <span asp-validation-for="Published"></span> </div> </div> <div class="layui-form-item"> <div class="layui-input-block"> <button class="layui-btn" lay-submit lay-filter="set_system_email">确认保存</button> </div> </div> </div> <div style="padding-top: 30px;"> <a href="javascript:;" layadmin-event="back" class="layui-btn layui-btn-primary layui-btn-sm">返回上级</a> </div> </div> </div> </div> </div> </div> <script> layui.config({ base: '../../../layuiadmin/' //静态资源所在路径 }).extend({ index: 'lib/index' //主入口模块 }).use(['index', 'set'], function () { var $ = layui.$ , form = layui.form ,active = {} form.on('submit(set_system_email)', function (obj) { var index = layer.load(2, { shade: false }); var field = obj.field; //获取提交的字段 field.Full = ue.getContent(); //layer.msg(JSON.stringify(obj.field)); //提交 Ajax 成功后,关闭当前弹层并重载表格 $.post('@Url.Action("Edit")', field, function (rep) { if (rep.success == 1) { layer.close(index); layer.msg("保存成功,即将自动关闭", { time: 2 * 1000 }, function () { var iframe_index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引 console.log("当前iframe层的索引:" + iframe_index + "==window.name:" + window.name); parent.layer.close(iframe_index); //再执行关闭 window.parent.location.reload(); }); } }); return false; }); $('.layui-btn.layuiadmin-btn-tags').on('click', function () { var type = $(this).data('type'); active[type] ? active[type].call(this) : ''; }); }); </script>
← 上一篇: 下一篇: →