WTM+LayUI 子表批量上传文件

目录

一、需求分析

二、解决思路

三、代码实现

步骤一、后台封装Upload组件

步骤二、通过Setformat方法将组件内容传递到前端

步骤三、批量新增VM

步骤四、设置单元格为Upload组件

步骤五、后台接受方法

说明


一、需求分析

         一个带有附件的Model,实现批量新增。这就需要在DetailList中添加上传按钮,但由于DetailList不支持附件的上传,故需要通过SetFormat方法来自定义实现。

二、解决思路

         将上传控件封装,并通过Setformat方法回传到前端的DetailList中。当上传完文件之后,将文件名赋值给当前列,将FileAttachmentId赋值给另外的列当后台接受到FileAttachmentId后,就像操作普通的字段一样操作即可

三、代码实现

步骤一、后台封装Upload组件

        /// <summary>
        /// 表格里面Upload组件
        /// </summary>
        /// <param name="name">名称,名称必须要要和接受的VM里面的实体一致</param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string MakeUpload(string name,string value=null)
        {
            var id = (name == null ? "" : Utils.GetIdByName(name));
            StringBuilder js=new StringBuilder();
            js.Append("<div style='display:flex'>");//将输入框和选择按钮放到同一行
            js.Append($@"<input class='layui-input'  style='height:28px;'  name='{name ?? ""}' id='{id}' value='{value ?? ""}'   onclick='SetGridCellUpload(""{id}"")'  />  ");// disabled='' class='layui-disabled'
            js.Append($@"<button id='{id}button' name='{name}button' class=""layui-btn layui-btn-sm"" type=""button"" lay-filter='{id}buttonfilter' style=""display: none;"" >选择</button><input class=""layui-upload-file"" type='file' accept='' name=""file"" > ");
            js.Append("</div>");
            return js.ToString();
        }

说明: 

1、此代码参考系统生成的前端上传控件,略有删除。

2、在外面封装一层Div是为了让input框和选择按钮在同一行,否则选择按钮将在第二行,从而不会显示。

3、将选择button设置为不显示,原因是防止一开始上传组件还没有layui.use初始化的时候,点击此按钮。由于没有初始化话为上传控件,此时是无法通过点击按钮上传文件的。

步骤二、通过Setformat方法将组件内容传递到前端

protected override IEnumerable<IGridColumn<CNCFileCreateDetailList_View>> InitGridHeader()
        {
            int fileIndex = 0;
            return new List<GridColumn<CNCFileCreateDetailList_View>>{
                this.MakeGridHeader(x => x.CNCFileCreateDetailList_Name).SetTitle(@Localizer["_Model._CNCFileManage._Name"].Value)
                .SetEditType(EditTypeEnum.TextBox),
                this.MakeGridHeader(x => x.CNCFileCreateDetailList_NCFileType).SetTitle(@Localizer["_Model._CNCFileManage._NCFileType"].Value)
                .SetEditType(EditTypeEnum.ComboBox,listitems:typeof(NCFileTypeEnum).ToListItems()),//ToListItems()方法将枚举转化成下拉列表
                this.MakeGridHeader(x => x.CNCFileCreateDetailList_FileId).SetTitle("CNCFileCreateDetailList_FileId").SetEditType(editType:EditTypeEnum.TextBox,readOnly:true).SetHide(),
                this.MakeGridHeader(x => x.CNCFileCreateDetailList_File).SetTitle(Localizer["_Model._CNCFileManage._NCFile"].Value)
                .SetFormat((e, f) =>
                {
                    string name = $"DetailList.EntityList[{fileIndex}].CNCFileCreateDetailList_File";//这个名称必须提交接受的实体一致
                      if(e.ID!=Guid.Empty)
                    {
                        fileIndex++;
                    }
                    string js=WTMHelper.MakeUpload(name);
                    return js;
                }),
                //this.MakeGridHeader(x => x.CNCFileCreateDetailList_IsNeedCheck).SetTitle(Localizer["_Model._CNCFileManage._IsNeedCheck"].Value).SetEditType(editType:EditTypeEnum.CheckBox),
                this.MakeGridHeader(x => x.CNCFileCreateDetailList_Remark).SetTitle(Localizer["_Model._CNCFileManage._Remark"].Value).SetEditType(editType:EditTypeEnum.TextBox),
                this.MakeGridHeaderAction(width: 200)
            };
        }

    public class CNCFileCreateDetailList_View : BasePoco
    {
        public string CNCFileCreateDetailList_Name { get; set; }
        public NCFileTypeEnum? CNCFileCreateDetailList_NCFileType { get; set; }
        /// <summary>
        /// 此字段是用来放FileName
        /// </summary>
        public string CNCFileCreateDetailList_File { get; set; }
        public string CNCFileCreateDetailList_FileId { get; set; }
        //public bool CNCFileCreateDetailList_IsNeedCheck { get; set; }
        public string CNCFileCreateDetailList_Remark { get; set; }

    }

 说明: 

1、上传控件的Name必须和提交接受的VM实体一致,否则将接受不到所需的数据。本例中DetailList.EntityList来接受

2、CNCFileCreateDetailList_FileId此列为存放FileAttachmentId的列,此列的命名必须是上传控件列的列名加Id,后面给此列赋值的时候会用到。

步骤三、批量新增VM

  /// <summary>
    /// 批量新增
    /// </summary>
    public  class CNCFileCreateBatchCreateVM : BaseVM
    {
        public Guid? ProductId { get; set; }
        [Required]
        [Display(Name ="_Model._CNCFileManage._WorkProcess")]
        public Guid? WorkProcessId { get; set; }
        public bool IsNeedCheck { get; set; }
        /// <summary>
        /// 新增的DetailList
        /// </summary>
        public CNCFileCreateDetailListVM DetailList { get; set; }
        

        public CNCFileCreateBatchCreateVM()
        {

            DetailList=new CNCFileCreateDetailListVM ();
            DetailList.DetailGridPrix = "DetailList.EntityList";//必须和前台传过来的名字一样

        }


        protected override void InitVM()
        {
          

        }
        public override void Validate()
        {
            //验证程序名称不能为空
            if (DetailList.EntityList.Any(x => string.IsNullOrEmpty(x.CNCFileCreateDetailList_Name)))
            {
                MSD.AddModelError("CNCFileCreateBatchCreate_Exist_Name_IsNull", Localizer["CNCFileCreateBatchCreate_Exist_Name_IsNull"].Value);
                return;
            }
            //验证程序文件不能为空
            if (DetailList.EntityList.Any(x => string.IsNullOrEmpty(x.CNCFileCreateDetailList_FileId)))
            {
                MSD.AddModelError("CNCFileCreateBatchCreate_Exist_FileId_IsNull", Localizer["CNCFileCreateBatchCreate_Exist_FileId_IsNull"].Value);
                return;
            }
            //验证Name和FileType的唯一性   按 x.CNCFileCreateDetailList_Name, x.CNCFileCreateDetailList_NCFileType分组后 是否组里面项大于1的
            if (DetailList.EntityList.GroupBy(x=>new { x.CNCFileCreateDetailList_Name, x.CNCFileCreateDetailList_NCFileType }).Any(g=>g.Count()>1))
            {
                MSD.AddModelError("CNCFileCreateBatchCreate_Exist_NameType_Unique", Localizer["CNCFileCreateBatchCreate_Exist_NameType_Unique"].Value);
                return;
            }

            base.Validate();
        }

       
    }

步骤四、设置单元格为Upload组件

//设置单元格为Upload
function SetGridCellUpload(id) {

    //将input标签设置为disabled ,如果不将input标签disable就可以再次点击,又会调用到SetGridCellUpload方法
    $(`#${id}`).prop('disabled', true);
    $(`#${id}button`).show();//显示选择按钮,如果需要更改文件可以通过此按钮点击

    layui.use(['upload'], function () {
        var uploadInst = layui.upload.render({
            elem: `#${id}button`
            , url: '/_Framework/Upload?1=1&_DONOT_USE_CS=&'
            , size: 0
            , accept: 'file'
            , xhr: xhrOnProgress
            , progress: function (value) {
                $('.layui-progress .layui-progress-bar').css(
                    'width',
                    value + '%'
                );
            }
            , before: function (obj) {
                index = layui.layer.load(2);

            }
            , done: function (res) {
                layui.layer.close(index);
                debugger;
                if (res.Data.Id == '') {
                    //$(`#${id}label`).html('');
                    layui.layer.msg('上传失败');
                }
                else {
                   /* $(`#${id}label`).html('');*/
                    document.getElementById(id).value = res.Data.Name;//将接口返回的文件名称赋值给input标签
                    document.getElementById(id).onchange();//调用此方法将标签的值赋值给Table 这个要一定要调用,否则新增之后将把之前的内容清空
                    document.getElementById(id + "Id").value = res.Data.Id;//将接口返回的文件FileId赋值给 Id的标签  
                    document.getElementById(id + "Id").onchange();

                }
            }
            , error: function () {

                layui.layer.close(index);
            }
        });
    })

    //按上传按钮
    $(`#${id}button`).click();
}

说明 :

1、当点击单元格的时候,调用前端的此方法。首先将input标签设置为disabled ,如果不将input标签disable就可以再次点击,又会调用到SetGridCellUpload方法,重新初始化layui上传标签。

2、将上传按钮显示出来,通过点击此按钮可以更改上传文件。

3、将值赋值给控件之后,一定要调用onchange方法,此方法会将标签的值赋值给Table。

步骤五、后台接受方法

  [HttpPost]
        [ActionDescription("Sys.DoBatchCreate")]
        public async Task<ActionResult> DoBatchCreate(CNCFileCreateBatchCreateVM vm)
        {

            if (!ModelState.IsValid)
            {
                return FFResult().Alert(Wtm.MSD.GetFirstError());
                //return PartialView(vm.FromView, vm);//由于刷新赋值不好弄就直接返回提示,且不关闭Dialog
            }
            else
            {
                foreach (var entity in vm.DetailList.EntityList)
                {
                   var subvm= Wtm.CreateVM<CNCFileCreateVM>();
                    subvm.CopyContext(vm);
                    subvm.Entity.Name = entity.CNCFileCreateDetailList_Name;
                    subvm.Entity.IsNeedCheck = vm.IsNeedCheck;
                    subvm.Entity.NCFileId =string.IsNullOrEmpty(entity.CNCFileCreateDetailList_FileId)?null:new Guid( entity.CNCFileCreateDetailList_FileId);
                    subvm.Entity.NCFileType = entity.CNCFileCreateDetailList_NCFileType;
                    subvm.Entity.WorkProcessId = vm.WorkProcessId;
                    subvm.Entity.CheckStatus = NCFileCheckStatusEnum.ToCheck;
                    subvm.Entity.Remark=entity.CNCFileCreateDetailList_Remark;
                    subvm.Validate();
                    if (!ModelState.IsValid)
                    {
                        return PartialView(vm.FromView, vm);
                    }
                    await subvm.DoAddAsync();
                }
                if (!ModelState.IsValid)
                {
                    return FFResult().Alert(Wtm.MSD.GetFirstError());
                    //vm.DoReInit();
                    //return PartialView("../CNCFileCreate/BatchCreate", vm);
                }
                else
                {

                    return FFResult().CloseDialog().RefreshGrid();
                }
            }
        }

说明:

 1、这里面有个偷懒的做法,就是当验证失败后,没有将vm返回给前端,而是返回了Alert的提示框。原因是验证失败返回VM的话,DetailList赋值有点麻烦,这也算是一个待优化的点吧。

说明

本人专注机床的数据采集和程序传输,致力于机械加工行业的数字化系统开发

以下是自己开发的所支持的机床数据采集源代码类库(部分),

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值