通过开发一个新闻功能来了解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>← 上一篇: 下一篇: →