『贴Builder』
最新文章
热门话题
用户问答
lao人言
「搜索」
PasteSpider
一款更加适合开发人员的微服务(容器)发布管理工具

节省资源

极小的运行资源消耗,还支持一拖多运行,运行内存甚至低至100MB!

安全运行

和业务服务没有层级上的关联,哪怕PasteSpider停止运行也不会影响你的业务服务运行

简单易上手

一键安装,图形操作点点点即可完成操作,附属服务的支持原汁原味,简单易上手

环境隔离

支持拆分多环境运行,工厂,测试两不误,还可以根据环境配置适应不一样的配置信息

适用功能一应俱全

从项目角度进行服务容器管理,支持自动升级,扩容,缩减,状态报表,键值配置,自动路由等

支持Git/Svn代码管理

通过配置支持服务环境级别的自动提交构建,一键提交代码后即可自动发布服务和路由等

【PasteForm】最佳CRUD的实现案例项目PasteTemplate解析,包含源码(二)
尘埃 2024-09-22 419 34 0
index.html页面作为PasteForm中的主显示页面,包含了丰富的显示功能!还有一些交互!

表格功能

接之前的(一),我们继续
图片alt

新增编辑删除

如上图,表格的默认菜单有左上方的“新增”,表格中的编辑和删除
其实着3个都是可以配置的,也就是配置关闭!

    ///<summary>
    ///用户信息
    ///</summary>
    [ColumnDataType("disable","add","edit","del")]
    public class UserInfoListDto : EntityDto<int>
    {
        ///<summary>
        ///用户名
        ///</summary>
        public string UserName { get; set; }


    }

如果哪一个要保留,就对应的设置为空,上面的代码时新增,编辑,删除都禁用,也就是都不显示!

数据说明

在新增按钮的后方,我们注意到有2个信息,一个是粗体的,一个是普通的,这个就是当前表的描述,PasteForm中定义,一个对象的文档,按照空格拆分,前面的为名称,后面的为描述(placeholder),数据的说明就是这么拆分而来的!

排序

这个有点特殊,其实就是对应字段添加属性orderby

        ///<summary>
        ///排序
        ///</summary>
        [ColumnDataType("orderby", "Sort","Sort desc")]
        public int Sort { get; set; }

为了把orderby在查询的时候传递给API端,需要在搜索的模型中添加orderby

    ///<summary>
    /// 查询
    ///</summary>
    public class InputQueryRoleInfo:InputSearchBase{

        /// <summary>
        /// 父级ID 基于父级ID查询
        /// </summary>
        [PasteOuter("roleInfo")]
        public int FatherId { get; set; }

        /// <summary>
        /// 角色ID 查询某一个角色拥有多少权限
        /// </summary>
        [ColumnDataType("query","gradeId")]
        public int GradeId { get; set; }

        /// <summary>
        /// 权限类型 基于权限类型查询
        /// </summary>
        [ColumnDataType("select", "[{\"name\":\"全部\",\"value\":-1,\"selected\":true},{\"name\":\"权限\",\"value\":0},{\"name\":\"菜单\",\"value\":1},{\"name\":\"按钮\",\"value\":2}]")]
        public int RoleType { get; set; }

        /// <summary>
        /// 排序 这个字段是隐藏的
        /// </summary>
        [ColumnDataType("hidden")]
        public string orderby { get; set; } = "Id desc";

    }

属性orderby中有2个参数,就是点击这个字段的升序和降序,也就是说你可以在Name中配置基于Id排序,有些时候需要这种功能,比如外表!

switch

表格的快捷操作,我认为一般是bool的模式,如果配置了属性switch,则会显示Switch的模式,否则就是显示true/false!
点击后,会往API中提交信息

        /// <summary>
        /// 更新状态,或者更新绑定
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="PasteCodeException"></exception>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "auth" })]
        public async Task<string> UpdateState(InputQueryUpdateState input)
        {
            if (!int.TryParse(input.id, out var _id))
            {
                throw new PasteCodeException("提供的参数id错误,无法继续执行");
            }
            if (input.search.Contains("model=bind"))
            {
                if(input.name!= "extendBind")
                {
                    throw new PasteCodeException("无效的操作,不支持当前情况下执行此操作!");
                }
                var _gradeid = 0;// 需要写一个扩展,从参数中提取某一个 先假设下,后面补充
                var _querys = input.search.ToQuerys();
                if (_querys != null)
                {
                    if (_querys.ContainsKey("gradeId"))
                    {
                        int.TryParse(_querys["gradeId"], out _gradeid);
                    }
                }
                if (_gradeid == 0)
                {
                    throw new PasteCodeException("参数错误,没有获取到gradeId!");
                }
                var find = await _dbContext.GradeRole.Where(x => x.GradeId == _gradeid && x.RoleId == _id).FirstOrDefaultAsync();
                if (find == null || find == default)
                {
                    if (input.state)
                    {
                        _dbContext.Add(new GradeRole { GradeId = _gradeid, RoleId = _id });
                        await _dbContext.SaveChangesAsync();
                    }
                    else
                    {
                        return "状态一致,不需要变更!";
                    }
                }
                else
                {
                    if (!input.state)
                    {
                        _dbContext.Remove(find);
                        await _dbContext.SaveChangesAsync();
                    }
                    else
                    {
                        return "状态一致,不需要变更!";
                    }
                }
                return $"更改{input.name}绑定状态成功";
            }
            else
            {
                //因为只有一个isenable,直接写
                var find = await _dbContext.RoleInfo.Where(x => x.Id == _id).FirstOrDefaultAsync();
                if (find == null || find == default)
                {
                    throw new PasteCodeException("没有找到对应的操作对象,无法继续执行");
                }
                if (find.IsEnable != input.state)
                {
                    find.IsEnable = input.state;
                    await _dbContext.SaveChangesAsync();
                }
                return $"修改{input.name}状态成功";
            }
        }

这里面要基于实际情况,比如权限判断,是否是设置这个name的状态,还是绑定等!主打的一个就是API修改写法实现功能!

显示外表的字段

有些时候我们要显示一些外表的某一个字段,比如创建者,一般的数据是userid,而显示的时候我们希望显示的是userid对应的user的username字段,这就需要outerdisplay这个属性
ListDto中用于外表的显示,比如有字段cateInfoId,对应的ExtendCateInfo要标记为outerdisplay,args2配置为extendCateInfo?.name || ‘’,否则会显示为[object object]

字段 类型 示例 说明
args1 字符 cateInfoId 表示这个字段的值,一般不显示
args2 字符 extendCateInfo?.name \ \ ‘’ 表示显示的名称,友好名称,需要后端支持,在前端会处理成.display

比如我的

        ///<summary>
        ///父级ID
        ///</summary>
        [ColumnDataType("outerdisplay","","extendFather?.name || ''")]
        public int FatherId { get; set; }

        /// <summary>
        /// 父级信息,为了给上一个字段FatherId显示使用,你也可以把FatherId隐藏,只显示这个字段,或者2个都显示
        /// </summary>
        [ColumnDataType("hidden")]
        public RoleShortModel ExtendFather { get; set; }

操作区按钮

一般的在最后的一列中有些按钮,比如最上图的添加子集等,PasteForm中配置了4种菜单模式,一般菜单,菜单盒子里的菜单,条件菜单,盒子里面的条件菜单

        /// <summary>
        /// 普通菜单
        /// </summary>
        [ColumnDataType("menu", "菜单一", "open_window('查阅用户带参','./index.html?path=userInfo&xxid={{:=item.id}}');", "Hui-iconfont-menu")]
        public string Menu2 { get; set; }

        /// <summary>
        /// 普通条件菜单
        /// </summary>
        [ColumnDataType("ifmenu", "item.age==7", "<a href=\"javascript:;\" onclick=\"open_window(`111`,`./index.html?path=userInfo&goid={{:=item.id}}`)\">条件1</a>", "")]
        public string Menu3 { get; set; }

        /// <summary>
        /// 菜单盒子菜单
        /// </summary>
        [ColumnDataType("menu", "菜单二", "open_window('查阅用户带参','./index.html?path=userInfo&xxid={{:=item.id}}');", "Hui-iconfont-menu","box")]
        public string Menu5 { get; set; }

        /// <summary>
        /// 菜单盒子中的条件菜单
        /// </summary>
        [ColumnDataType("ifmenu", "item.age==8", "<a href=\"javascript:;\" onclick=\"open_window(`222`,`./index.html?path=userInfo&goid={{:=item.id}}`)\">条件2</a>", "box")]
        public string Menu4 { get; set; }

图片alt
如上图就是配置的菜单,所以详情也是使用菜单配置的!

列自定义

有些时候我们希望表格中的列的显示使用自己的模式,比如要多个字段拼接,或者要加其他样式等,这个时候需要使用htmltemplate的属性

        /// <summary>
        /// 重新载入
        /// </summary>
        [ColumnDataType("htmltemplate", "<a href=\"javascript:;\" onclick=\"global_route_reload({{:=item.id}});\" title=\"更新到nginx的文件夹中,并执行nginx -t && nginx -s reload\">重新载入</a>")]
        public int Menu2 { get; set; }

效果图如下
图片alt
看上面的代码,其实就是自定义写Html,基于这个你就可以实现不一样的显示和功能了!

终极自定义

如果说表格和表格的窗体都不满意,你也可以自定义,也就是自己写template,然后在对应的XXXListDto中的Class写入属性template
作为有些表的特殊布局,就是自定义布局表格部分的内容,包括表头和表身2个部分,注意需要实现选择的功能,除非这个表用不到选择这个功能
文件存放于pasteform/template.html,就只有一个template.html页面,里面的都是模板代码

字段 类型 示例 说明
args1 字符 template_user_head 表格的表头部分的script的id
args2 字符 template_user_body 表格的表身部分的模板的script的id

这个其实查看下js的源码就可以知道了,如下

/**
 * 查询模型信息
 **/
function QueryModel() {
    _apiget(`/api/app/${_classPath}/readListModel`, true, (c, o) => {
        if (c == 200) {
            if (o.title) {
                $(".ppbody .st").find(".sn").html(o.title);
                this.document.title = o.title;
            }
            if (o.desc) {
                $(".ppbody .st").find(".idesc").html(o.desc);
            }
            //表头的模板内容
            var _template_head_html = null;

            _globadataProperties = o.properties;
            //模型处理,如何显示外表 比如cate.name 
            HandlerModelColumn(o.properties);
            //class模型的属性列表
            if (o.attributes) {
                _globadataAttributes = o.attributes;
                o.attributes.forEach(_attribute => {
                    if (_attribute.name == 'disable') {
                        if (_attribute.args1) {
                            _config.disable_add = true;
                            $(".btnadd").hide();
                        }
                        if (_attribute.args2) {
                            _config.disable_edit = true;
                        }
                        if (_attribute.args3) {
                            _config.disable_del = true;
                        }
                    }
                    if (_attribute.name == "template") {
                        if (_attribute.args1) {
                            _template_head_html = $(`#${_attribute.args1}`).html();
                        }
                        if (_attribute.args2) {
                            _template_body_html = $(`#${_attribute.args2}`).html();
                        }
                    }
                });
            }

            if (_template_head_html == null) {
                _template_head_html = $("#template_header").html();
            }
            var _modelhtml = template(_template_head_html, { list: o.properties, config: _config });
            //一级模型 转化成 二级模型
            if (_template_body_html == null) {
                var _template_body = $("#template_body").html();
                var _bodyhtml = template(_template_body, { list: o.properties, config: _config });
                _template_body_html = _bodyhtml.replace(/{{/g, '<%').replace(/}}/g, '%>');
            }
            $(".table").find("thead").html(_modelhtml);
            //处理查询项
            if (o.queryProperties) {
                _globdataQueryProperties = o.queryProperties;
                HandlerQueryItem(o.queryProperties);
            } else {
                _readpagedata(1);
            }
            //读取数据
        }
    });
}

注意看上方的_template_head_html和_template_body_html

选择模式

在外表的模式下,或者outer属性的时候,我们需要把某一个表作为可选对象,先看下outer属性说明
表示一个值需要从外表获取,编辑的时候如何显示? 比如fatherId,extendRole

字段 类型 示例 说明
args1 字符 cateInfo 外表的名称,对应模板的path,或者路径,路径一定附带了/字符示例./abc.html
args2 字符 extendCates 表示显示的数据,需要和下面2个配合,是一个当前的扩展,目标数组要配置hidden
args3 字符 id 获取返回对象的属性,一般为id
args4 字符 name id的友好名称显示,这里指的是外表,比如cateId,需要打开catelist页面,选择后,返回cate,则name作为友好显示,id作为实际值

在表格页面中,会发生outer的一半在搜索项中,比如选择父级ID查询子集的,点击后如下
图片alt
表格页面的介绍先到这,我们下一期介绍表单页面!

评论列表
尘埃
34 419 0
快捷注册
最新动态
  • 128.****.220 正在查看 Postgresql的安装 !
  • 82.****.154 正在查看 PasteSpider之项目-服务-环境介绍 !
  • 167.****.137 正在查看 PasteSpider中关于Nginx的配置,安装PasteSpider之后查阅 !
  • 154.****.93 正在查看 PasteSpider中关于Nginx的配置,安装PasteSpider之后查阅 !
  • 53.****.232 正在查看 PasteForm中,表格的不一样的样式的设定? !
  • 210.****.223 正在查看 PasteSpider中如何同步文件到服务器包含PasteSpiderFile的下载 !
  • 219.****.36 正在查看 PasteBuilder的进阶用法 !
  • 150.****.200 正在查看 PasteForm中如何处理批量操作? !
  • 4.****.33 正在查看 PasteSpider的测试环境之在Docker中安装centos7并设定SSH的密码 !
  • 63.****.85 正在查看 在Centos7中安装Nginx !
  • 144.****.129 正在查看 在centos7中安装docker !
欢迎加入QQ讨论群 296245685 更新记录 [PasteSpider]介绍 @2022-2023 PasteCode.cn 版权所有 ICP证 闽ICP备2021013869号-2