消息背景实战:用Admin Blazor管理文章和专栏

[复制链接]
发表于 昨天 20:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前面三篇我们讲了:

  • 第一篇:3分钟搭一个Blazor背景
  • 第二篇:项目目次结构详解
  • 第三篇:几十行代码搞定CRUD
本日来点实战,用一个真实的消息管理模块做案例,把专栏管理和文章管理完备走一遍。看看关联表、罗列、富文本编辑器这些实际项目中肯定会遇到的需求,在EasyAdminBlazor里怎么处理处罚。
一、实体筹划

1. 专栏实体(Classify)
  1. /// <summary>
  2. /// 随笔专栏
  3. /// </summary>
  4. [Table(Name = "blog_classify")]
  5. public class Classify : EntityCreated
  6. {
  7.     /// <summary>
  8.     /// 分类专栏名称
  9.     /// </summary>
  10.     [Column(StringLength = 50)]
  11.     [DisplayName("专栏名称")]
  12.     public string ClassifyName { get; set; } = string.Empty;
  13.     /// <summary>
  14.     /// 封面图
  15.     /// </summary>
  16.     [Column(StringLength = 100)]
  17.     [DisplayName("封面图")]
  18.     public string Thumbnail { get; set; } = string.Empty;
  19.     /// <summary>
  20.     /// 排序
  21.     /// </summary>
  22.     [DisplayName("排序")]
  23.     public int SortCode { get; set; }
  24.     /// <summary>
  25.     /// 文章数量(冗余字段,方便列表展示)
  26.     /// </summary>
  27.     [DisplayName("文章数量")]
  28.     public int ArticleCount { get; set; }
  29. }
复制代码
2. 文章实体(Article)
  1. /// <summary>
  2. /// 随笔
  3. /// </summary>
  4. [Table(Name = "blog_article")]
  5. public class Article : EntityModified
  6. {
  7.     /// <summary>
  8.     /// 所属专栏
  9.     /// </summary>
  10.     [DisplayName("随笔专栏")]
  11.     [Required]
  12.     public long? ClassifyId { get; set; }
  13.     /// <summary>
  14.     /// 导航属性:关联的专栏
  15.     /// </summary>
  16.     [Navigate(nameof(ClassifyId))]
  17.     public Classify Classify { get; set; } = default!;
  18.     /// <summary>
  19.     /// 标题
  20.     /// </summary>
  21.     [Column(StringLength = 200)]
  22.     [DisplayName("标题")]
  23.     [Required]
  24.     public string Title { get; set; } = string.Empty;
  25.     /// <summary>
  26.     /// 关键字
  27.     /// </summary>
  28.     [Column(StringLength = 400)]
  29.     [DisplayName("关键字")]
  30.     public string Keywords { get; set; } = string.Empty;
  31.     /// <summary>
  32.     /// 摘要
  33.     /// </summary>
  34.     [Column(StringLength = 500)]
  35.     [DisplayName("摘要")]
  36.     public string Excerpt { get; set; } = string.Empty;
  37.     /// <summary>
  38.     /// 正文(-2表示长文本,不限长度)
  39.     /// </summary>
  40.     [Column(StringLength = -2)]
  41.     [DisplayName("正文")]
  42.     [Required]
  43.     public string Content { get; set; } = string.Empty;
  44.     /// <summary>
  45.     /// 缩略图
  46.     /// </summary>
  47.     [Column(StringLength = 400)]
  48.     [DisplayName("缩略图")]
  49.     public string Thumbnail { get; set; } = string.Empty;
  50.     /// <summary>
  51.     /// 随笔类型(支持多选)
  52.     /// </summary>
  53.     [DisplayName("随笔类型")]
  54.     public ArticleType ArticleType { get; set; }
  55.     /// <summary>
  56.     /// 浏览量
  57.     /// </summary>
  58.     [DisplayName("浏览量")]
  59.     public int ViewHits { get; set; }
  60.     /// <summary>
  61.     /// 评论数量
  62.     /// </summary>
  63.     [DisplayName("评论数量")]
  64.     public int CommentQuantity { get; set; }
  65.     /// <summary>
  66.     /// 是否审核
  67.     /// </summary>
  68.     [DisplayName("是否审核")]
  69.     public bool IsAudit { get; set; }
  70.     /// <summary>
  71.     /// 是否推荐
  72.     /// </summary>
  73.     [DisplayName("是否推荐")]
  74.     public bool Recommend { get; set; }
  75.     /// <summary>
  76.     /// 是否置顶
  77.     /// </summary>
  78.     [DisplayName("是否置顶")]
  79.     public bool IsStickie { get; set; }
  80.     /// <summary>
  81.     /// 开启评论
  82.     /// </summary>
  83.     [DisplayName("开启评论")]
  84.     public bool Commentable { get; set; } = true;
  85.     /// <summary>
  86.     /// 发布时间
  87.     /// </summary>
  88.     [DisplayName("发布时间")]
  89.     public DateTime? PublishTime { get; set; } = DateTime.Now;
  90. }
  91. /// <summary>
  92. /// 随笔类型(Flags特性支持多选)
  93. /// </summary>
  94. [Flags]
  95. public enum ArticleType
  96. {
  97.     原创 = 1,
  98.     转载 = 2,
  99.     翻译 = 4
  100. }
复制代码
几个关键点:

  • [Navigate] 特性标志导航属性,告诉 FreeSql 这是关联关系
  • [Column(StringLength = -2)] 表现不限长度的文本,恰当存富文本内容
  • [Flags] 罗列支持多选组合,比如可以同时选“原创+翻译”
二、专栏管理页面

专栏相对简单,就是最根本的 CRUD:
  1. @page "/Blog/Classify"
  2.     <TableColumns>
  3.         <TableColumn @bind-Field="context.ClassifyName" Text="专栏名称" Filterable="true" />
  4.         <TableColumn @bind-Field="context.Thumbnail" Text="封面图" />
  5.         <TableColumn @bind-Field="context.SortCode" Text="排序" />
  6.         <TableColumn @bind-Field="context.ArticleCount" Text="文章数量" />
  7.         <TableColumn @bind-Field="context.CreatedTime" Text="创建时间" />
  8.     </TableColumns>
  9. </AdminTable>
  10. @code {
  11.     private void OnBeforeQuery(AdminQueryEventArgs<Classify> e)
  12.     {
  13.         // 如果需要过滤条件,在这里写
  14.     }
  15. }
复制代码
就这么几行,专栏管理的完备 CRUD 就有了:增编削查、分页、搜索、导出 Excel,全主动。
三、文章管理页面(核心)

文章管理轻微复杂一点,涉及三个典范场景:

  • 关联专栏:列表表现专栏名称,筛选用下拉框
  • 罗列多选:文章范例支持多选筛选
  • 富文本编辑:正文必要编辑器
完备代码:
  1. @page "/Blog/Article"
  2. @using EasyAdminBlazorDemo.Entities
  3. @using EasyAdminBlazor.Components.Admin
  4.     <TableColumns>
  5.         
  6.         <TableColumn @bind-Field="context.ClassifyId" Text="随笔专栏" Filterable="true">
  7.             <Template Context="v">
  8.                 @v.Row.Classify?.ClassifyName
  9.             </Template>
  10.             <FilterTemplate>
  11.                 <FilterProvider>
  12.                      x.ClassifyName" />
  13.                 </FilterProvider>
  14.             </FilterTemplate>
  15.         </TableColumn>
  16.         
  17.         <TableColumn @bind-Field="context.Title" Text="标题" Filterable="true" Searchable="true" />
  18.         
  19.         <TableColumn @bind-Field="context.ArticleType" Text="类型"
  20.                      ComponentType="typeof(MultiSelect)"
  21.                      Filterable="true"
  22.                      Searchable="true">
  23.             <FilterTemplate>
  24.                 <FilterProvider ShowMoreButton="false">
  25.                     
  26.                 </FilterProvider>
  27.             </FilterTemplate>
  28.         </TableColumn>
  29.         
  30.         <TableColumn @bind-Field="context.ViewHits" Text="浏览量" />
  31.         
  32.         <TableColumn @bind-Field="context.CommentQuantity" Text="评论数量" />
  33.         
  34.         <TableColumn @bind-Field="context.IsAudit" Text="审核" />
  35.         
  36.         <TableColumn @bind-Field="context.CreatedTime" Text="创建时间" />
  37.     </TableColumns>
  38.    
  39.     <EditTemplate>
  40.         
  41.     </EditTemplate>
  42. </AdminTable>
  43. @code {
  44.     private void OnBeforeQuery(AdminQueryEventArgs e)
  45.     {
  46.         // 预加载关联的专栏数据,避免N+1查询
  47.         e.Select.Include(a => a.Classify);
  48.     }
  49. }
复制代码
几个关键点表明

场景代码阐明列表表现关联字段@v.Row.Classify?.ClassifyName用 Template 表现导航属性的值筛选关联表筛选器主动酿成专栏下拉框罗列多选筛选支持多选的罗列筛选器预加载关联数据e.Select.Include(a => a.Classify)克制循环查询,性能优化四、富文本编辑器组件(ArticleEditTemplate)

方便代码的构造,我们单独抽一个组件出来(单独抽离编辑组件另有个缘故因由就是由于BootstrapBlazor必要在新组件中才气利用交互本事,比如用一个字段控制另一个字段是否是表现/埋伏):
  1. <Tab IsCard>
  2.     <TabItem Text="随笔">
  3.         
  4.             
  5.                  e.ClassifyName" ShowSearch />
  6.             
  7.             
  8.                 <BootstrapInput @bind-Value="Model.Title" type="text" maxlength="200" />
  9.             
  10.             
  11.                 <MultiSelect @bind-Value="Model.ArticleType" />
  12.             
  13.             
  14.                 <BootstrapInput @bind-Value="Model.Keywords" type="text" maxlength="400" />
  15.             
  16.             
  17.                
  18.             
  19.             
  20.                 <Textarea @bind-Value="Model.Excerpt" maxlength="500"></Textarea>
  21.             
  22.             
  23.                
  24.             
  25.             
  26.                 <DateTimePicker @bind-Value="Model.PublishTime" DisplayText="发布时间" IsEditable />
  27.             
  28.             
  29.                
  30.             
  31.         
  32.     </TabItem>
  33.     <TabItem Text="设置">
  34.         
  35.             
  36.                 <BootstrapInput @bind-Value="Model.ViewHits" type="number" />
  37.             
  38.             
  39.                 <BootstrapInput @bind-Value="Model.CommentQuantity" type="number" />
  40.             
  41.             
  42.                 <Switch @bind-Value="Model.IsAudit" OnColor="Color.Success" />
  43.             
  44.             
  45.                 <Switch @bind-Value="Model.Recommend" OnColor="Color.Success" />
  46.             
  47.             
  48.                 <Switch @bind-Value="Model.IsStickie" OnColor="Color.Success" />
  49.             
  50.             
  51.                 <BootstrapInput @bind-Value="Model.WordNumber" type="number" />
  52.             
  53.             
  54.                 <BootstrapInput @bind-Value="Model.ReadingTime" type="number" />
  55.             
  56.             
  57.                 <Switch @bind-Value="Model.Commentable" OnColor="Color.Success" />
  58.             
  59.         
  60.     </TabItem>
  61. </Tab>
  62. @code {
  63.     [Parameter]
  64.     [NotNull]
  65.     public Article? Model { get; set; }
  66. }
复制代码
这个编辑器组件包罗了:

  • 下拉选择(专栏)
  • 文本输入(标题、关键字、择要)
  • 多选罗列(文章范例)
  • 开关按钮(是否稽核、开启批评)
  • 图片上传(缩略图)
  • 富文本编辑器(需用nuget安装并启用EasyAdminBlazor.HtmlEditor扩展)
五、效果总结

做完上面这些,你得到的是一个完备的企业级消息背景:
功能专栏管理文章管理增编削查✅ 主动✅ 主动分页排序✅ 主动✅ 主动搜索筛选✅ 主动✅ 主动关联表筛选-✅ 主动(专栏下拉)罗列多选-✅ 主动富文本编辑-✅ 集成图片上传✅✅Excel导出✅✅你写了多少代码?

  • 实体类:约150行
  • 专栏页面:约30行
  • 文章页面:约60行
  • 编辑器组件:约50行
总计不到300行代码,一个完备的企业级博客背景就出来了。
没有 Controller、没有 Service、没有 DTO、没有 axios、没有前端路由、没有 loading 处理处罚。
这就是 EasyAdminBlazor 的核心代价:让你专注业务逻辑,而不是重复的 CRUD。
下一篇预告

《Admin Blazor 权限体系:从设置到菜单按钮控制》
讲完 CRUD,下一篇文章讲讲权限控制——怎么设置脚色、怎么分配菜单权限、怎么控制按钮表现埋伏。
这些都是背景体系的核心需求,但在 EasyAdminBlazor 里只要点点鼠标即可完成。
🔗 文档:https://easyadmim.wang-zhan.com.cn/doc
🔗 源码:https://gitee.com/gudufy/EasyAdminBlazor
EasyAdminBlazor —— 我本身接单的屠龙刀,如今也给你用。

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表