diff --git a/NewLife.CubeNC/Areas/Admin/Views/Department/_List_Toolbar_Batch.cshtml b/NewLife.CubeNC/Areas/Admin/Views/Department/_List_Toolbar_Batch.cshtml new file mode 100644 index 00000000..b0a355db --- /dev/null +++ b/NewLife.CubeNC/Areas/Admin/Views/Department/_List_Toolbar_Batch.cshtml @@ -0,0 +1,15 @@ +@using NewLife.Common; +@using NewLife.Cube +@using XCode +@{ + var user = ViewBag.User as IUser ?? User.Identity as IUser; + var fact = ViewBag.Factory as IEntityFactory; + var set = ViewBag.PageSetting as PageSetting ?? PageSetting.Global; +} +@if (set.EnableSelect) +{ + 下载模版 +
+ +
+} \ No newline at end of file diff --git a/NewLife.CubeNC/Common/EntityController.cs b/NewLife.CubeNC/Common/EntityController.cs index 6d1fd4b6..6d82201e 100644 --- a/NewLife.CubeNC/Common/EntityController.cs +++ b/NewLife.CubeNC/Common/EntityController.cs @@ -1,16 +1,19 @@ using System.ComponentModel; using System.Diagnostics; +using System.Text; using Microsoft.AspNetCore.Mvc; using NewLife.Cube.Common; using NewLife.Cube.Extensions; using NewLife.Cube.ViewModels; using NewLife.Data; +using NewLife.IO; using NewLife.Log; using NewLife.Reflection; using NewLife.Remoting; using NewLife.Serialization; using NewLife.Web; using XCode; +using XCode.Configuration; using XCode.Membership; namespace NewLife.Cube; @@ -312,18 +315,12 @@ public override async Task Develop(String act) public virtual ActionResult ImportXml() => throw new NotImplementedException(); /// 导入Json + /// 当前采用前端解析的excel,表头第一行数据无效,从第二行开始处理 /// [EntityAuthorize(PermissionFlags.Insert)] [DisplayName("导入")] [HttpPost] - public virtual ActionResult ImportJson() => throw new NotImplementedException(); - - /// 导入Excel - /// 当前采用前端解析的excel,表头第一行数据无效,从第二行开始处理 - /// - [EntityAuthorize(PermissionFlags.Insert)] - [DisplayName("导入Excel")] - public virtual ActionResult ImportExcel(String data) + public virtual ActionResult ImportJson(String data) { if (String.IsNullOrWhiteSpace(data)) return Json(500, null, $"“{nameof(data)}”不能为 null 或空白。"); try @@ -401,6 +398,116 @@ public virtual ActionResult ImportExcel(String data) } } + /// 导入Excel + /// + [EntityAuthorize(PermissionFlags.Insert)] + [DisplayName("导入Excel")] + public virtual ActionResult ImportExcel(IFormFile file) + { + try + { + var fact = Factory; + + using var reader = new ExcelReader(file.OpenReadStream(), Encoding.UTF8); + var rows = reader.ReadRows().ToList(); + + // 读取标题行,找到对应字段 + var fields = new List(); + foreach (var item in rows[0]) + { + // 找到对应字段,可能为空 + var field = Factory.Fields.FirstOrDefault(e => (item + "").EqualIgnoreCase(e.Name, e.DisplayName)); + fields.Add(field); + } + + var list = new List(); + foreach (var row in rows.Skip(1)) + { + // 实例化实体对象,读取一行,逐个字段赋值 + var entity = fact.Create() as TEntity; + for (var i = 0; i < row.Length; i++) + { + var field = fields[i]; + if (field != null) entity.SetItem(field.Name, row[i].ChangeType(field.Type)); + } + + if ((entity as IEntity).HasDirty) list.Add(entity); + } + + // 保存数据 + var rs = OnImport(list, fields); + + var msg = $"导入[{file.FileName}],共[{rows.Count - 1}]行,成功[{rs}]行!"; + base.WriteLog("导入Excel", true, msg); + + return JsonRefresh(msg, 2); + } + catch (Exception ex) + { + XTrace.WriteException(ex); + + WriteLog("导入Excel", false, ex.GetMessage()); + + return Json(500, ex.GetMessage(), ex); + } + } + + /// 导入数据,保存落库 + /// + /// 此时得到的实体列表,都是全新创建,用于接收上传数据。 + /// 业务上,还需要考虑跟旧数据进行合并,已存在更新,不存在则新增。 + /// + /// 导入实体列表 + /// 导入字段 + /// + protected virtual Int32 OnImport(IList list, IList fields) + { + // 如果存在主键或者唯一索引,先查找是否存在,如果存在则更新,否则新增 + var names = fields.Select(e => e.Name).ToList(); + var uk = Factory.Unique; + if (fields.Any(e => e.Name == uk.Name)) + { + for (var i = 0; i < list.Count; i++) + { + var entity = list[i]; + var old = Factory.FindByKey(entity[uk.Name]) as TEntity; + if (old != null) list[i] = CopyFrom(old, entity, fields); + } + } + else + { + // 唯一索引 + var di = Factory.Table.DataTable.Indexes.FirstOrDefault(e => e.Unique && !e.Columns.Except(names).Any()); + if (di != null) + { + var fs = fields.Where(e => di.Columns.Contains(e.Name)).ToList(); + for (var i = 0; i < list.Count; i++) + { + var entity = list[i]; + var exp = new WhereExpression(); + foreach (var fi in fs) + { + exp &= fi.Equal(entity[fi.Name]); + } + var old = Factory.Find(exp) as TEntity; + if (old != null) list[i] = CopyFrom(old, entity, fields); + } + } + } + + return list.Save(); + } + + TEntity CopyFrom(TEntity entity, IModel source, IList fields) + { + foreach (var fi in fields) + { + entity.SetItem(fi.Name, source[fi.Name]); + } + + return entity; + } + /// 修改bool值 /// ///