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值
///
///