PasteForm是贴代码推出的 “新一代CRUD” ,基于ABPvNext,目的是通过对Dto的特性的标注,从而实现管理端的统一UI,借助于配套的PasteBuilder代码生成器,你可以快速的为自己的项目构建后台管理端!目前管理端只有Html+js版本的,后续将支持小程序,Vue等
案例源码在
https://gitee.com/pastecode/paste-template
不定期升级
通过引入PasteForm,一个项目哪怕100个数据表,一般的管理页面也才不到10个,除非有非常多的特殊功能,否则都能用PasteForm中的表格和表单来实现!
对于select(option),相信前端的小伙伴肯定熟悉,作为表单中的一个重要组件,PasteForm也对这个组件做了支持!
select:在UI中使用<select><option></option><select>表示,所以只能选择一个
selects:则使用div显示,一般一行一个数据,允许多选
lselect:和selects类似,不过他是横向表示的
字段 | 类型 | 示例 | 说明 |
---|---|---|---|
args1 | 字符 | [{“name”:”大”,”value”:”1”},{“name”:”小”,”value”:”2”}] | 表示单选的可选值,name是显示 value是值,如果为空,则对应字段必须为enum类型,系统会去读取enum的内容 |
args2 | 字符 | , | 如果值类型不是数组,则返回字符串,用这个字符拼接,也就是分割字符,这个要看当前字段是否是string类型 |
args3 | 字符 | -1,0 | 去除某些值的选项,比如去除-1表示的全部等,在enum的时候适用,配置的时候args1为空这个时候,从enum中读取 |
args4 | 字符 | 0 | 可选数量,不填或者0变表示不限 |
这个特性有点特殊,因为必须和select结合使用,他表示select选择其中一项后,组合选中的值,重新向API请求,API在接收到这个信息后,针对性的做一些变更!
在select上适用,比如位置使用select呈现,首页,个人中心,当这个选项变更的时候,我们希望对应的图片的规格变成,则有切换后,去读取reload特性
然后把值回传给API,API居于query参数,把默认值修改和对应的图片规格变更后下发,注意query的key是不能重复的
字段 | 类型 | 示例 | 说明 |
---|---|---|---|
args1 | str | location | 表示query的字段,值为当前选定的值 |
上面的UI中,我们是随便填写点东西后,提交,看到的提交信息如下
这里要注意,如果比如age这个字段没有填写,留空,由于字段类型为int[],则这个时候回传为null,也就是提交的信息中没有age这个字段!
注意看上图的回传的数据类型各不同,这个是由Dto决定的!
/// <summary>
///
/// </summary>
public class SelectDto
{
///<summary>
///单选 一般表示状态,内定的,有点像Enum,关于Enum后续会支持
///</summary>
[ColumnDataType("mark", "test", "datetype")]
[PasteSelect("[{\"name\":\"日类型\",\"value\":0},{\"name\":\"月类型\",\"value\":1},{\"name\":\"年类型\",\"value\":2}]","0")]
public int DateType { get; set; }
/// <summary>
/// 年龄 多个之间使用,隔开
/// </summary>
[ColumnDataType("splitarray")]
public int[] Ages { get; set; }
/// <summary>
/// 复选 多个之间用逗号隔开
/// </summary>
[PasteSelects("[{\"name\":\"日类型\",\"value\":\"day\"},{\"name\":\"月类型\",\"value\":\"month\"},{\"name\":\"年类型\",\"value\":\"year\"}]", ",")]
public string TypeStrs { get; set; }
/// <summary>
/// 复选数组 配置最多选择1项,由args4配置,当前等效于PasteSelects
/// </summary>
[ColumnDataType("selects", "[{\"name\":\"日类型\",\"value\":\"day\"},{\"name\":\"月类型\",\"value\":\"month\"},{\"name\":\"年类型\",\"value\":\"year\"}]","","","1")]
public string[] Types { get; set; }
/// <summary>
/// 分类 多个之间使用,隔开,有默认值1,2,5,前端为字符串输入,用分隔符分割,后端接收到的为int[]
/// </summary>
[ColumnDataType("splitarray")]
public int[] Tabs { get; set; } = new int[] { 1, 2, 5 };
/// <summary>
/// 曾用名 多个之间使用,隔开,表示的是用户用分隔符输入,然后提交给后端的时候变更为对应的数组,比如当前的string[]
/// </summary>
[ColumnDataType("splitarray")]
public string[] Names { get; set; }
/// <summary>
/// 动作类型 这是一个Enum类型
/// </summary>
public ActionEnum ActionType { get; set; }
/// <summary>
/// 横向分类 这是一个Enum类型,而且使用了过滤,过滤掉-1和0的值的选项不返回前端
/// </summary>
[PasteLselect("", "-1,0")]
public ActionEnum ClassType { get; set; }
}
如上所示,字段ActionType和ClassType其实都是ActionEnum,但是在UI中的显示完全不一样,因为ActionType默认为select,而ClassType配置为lselect了,
还有一点,看最上图的UI中,横向分类只有”正常,停止,取消”,那是因为ClassType的lselect特性配置了ignore=-1,0 表示忽略值为-1和0的选项!
我看下Enum的内容
/// <summary>
/// 动作枚举
/// </summary>
public enum ActionEnum
{
/// <summary>
/// 查看所有
/// </summary>
all=-1,
/// <summary>
/// 正常 可以正常使用的
/// </summary>
start = 1,
/// <summary>
/// 停止
/// </summary>
stop = 4,
/// <summary>
/// 取消
/// </summary>
cannel = 5
}
注意 Enum的文件需要存放于XXX.Domian或者XXX.Application.Contracts子项目中!
查看特性参数中的args4,表示限定数量,如上我配置了复选数组这个字段的数量限制为1,则再选择一个的时候就如下
reload源自于特殊的需求,比如贴代码的发帖中有这么限定,就是用户可以选择文章类型是Markdown还是Richtext
如上,这个案例,我们希望用户选择内容格式为HTML的时候内容为Richtext模式,当用户选择内容格式为markdown的时候,内容格式切换为Markdown
如果上图我点击内容格式,选择为Markdown,则页面会刷新以下,然后看到的如下图:
///<summary>
///PageInfo
///</summary>
public class PageInfoAddDto
{
///<summary>
///标题
///</summary>
[MaxLength(64)]
public string Title { get; set; }
/// <summary>
/// 封面图
/// </summary>
[MaxLength(256)]
[ColumnDataType("image", "1", "article", "300*300")]
public string CoverImage { get; set; } = "";
///<summary>
///描述
///</summary>
[MaxLength(128)]
public string Desc { get; set; }
///<summary>
///关键字
///</summary>
[MaxLength(128)]
public string KeyWord { get; set; }
///<summary>
///文章类型
///</summary>
[PasteSelect(PublicString.SelectValueBlogType)]
public int ArticleType { get; set; }
/// <summary>
/// 所属板块
/// </summary>
[ColumnDataType("outers", "cateInfo", "", "id", "name")]
public int[] cateids { get; set; }
///<summary>
///文章正文
///</summary>
[ColumnDataType("richtext","","markdown")]
public string Body { get; set; } = "";
/// <summary>
/// Markdown
/// </summary>
[ColumnDataType("markdown", "", "body")]
public string Markdown { get; set; } = "";
/// <summary>
/// 内容格式 0富文本html模式1md模式
/// </summary>
[PasteSelect(PublicString.SelectValueBlogBodyType)]
[ColumnDataType("reload", "bstyle")]
[ColumnDataType("query","bstyle")]
public int BodyStyle { get; set; } = 0;
}
由于配置reload之后,是在对应的select选择修改后,重新加载,所以有一个载入的动作,所以需要配置query特性,表示从url中获取这个值!
由于这个比较特殊,所以对应的API也要变更,案例中的如下:
/// <summary>
/// 读取AddDto的数据模型
/// </summary>
/// <returns></returns>
[HttpGet]
public PasteBuilderHelper.VoloModelInfo ReadAddModel()
{
var model = new PageInfoAddDto();
if (base._httpContext.Request.Query.ContainsKey("bstyle")) {
int.TryParse(base._httpContext.Request.Query["bstyle"].ToString(),out var bstyle);
model.BodyStyle = bstyle;
}
var _model = PasteBuilderHelper.ReadModelProperty(model);
if (_model != null)
{
if (model.BodyStyle == 0)
{
var _find = _model.Properties.Where(x => x.Name == "markdown").FirstOrDefault();
if (_find != null)
{
if (_find.Attributes == null) { _find.Attributes = new List<PasteBuilderHelper.VoloModelAttribute>(); }
_find.Attributes.Add(new PasteBuilderHelper.VoloModelAttribute { Name = "hidden" });
}
}
else
{
var _find = _model.Properties.Where(x => x.Name == "body").FirstOrDefault();
if (_find != null)
{
if (_find.Attributes == null) { _find.Attributes = new List<PasteBuilderHelper.VoloModelAttribute>(); }
_find.Attributes.Add(new PasteBuilderHelper.VoloModelAttribute { Name = "hidden" });
}
}
}
return _model;
}
上面代码中,就是基于url中的参数bstyle,来动态修改字段和字段的特性,从而达到返回前端不一样的!
我们下期见!