|
@ -11,6 +11,8 @@ using System.Reflection; |
|
|
using System.Text.Json; |
|
|
using System.Text.Json; |
|
|
using System.Threading.Tasks; |
|
|
using System.Threading.Tasks; |
|
|
using ClosedXML.Excel; |
|
|
using ClosedXML.Excel; |
|
|
|
|
|
using DocumentFormat.OpenXml; |
|
|
|
|
|
using LinqToDB.Data; |
|
|
using LinqToDB.EntityFrameworkCore; |
|
|
using LinqToDB.EntityFrameworkCore; |
|
|
using Magicodes.ExporterAndImporter.Core; |
|
|
using Magicodes.ExporterAndImporter.Core; |
|
|
using Magicodes.ExporterAndImporter.Core.Extension; |
|
|
using Magicodes.ExporterAndImporter.Core.Extension; |
|
@ -21,6 +23,7 @@ using Microsoft.AspNetCore.SignalR; |
|
|
using Microsoft.EntityFrameworkCore; |
|
|
using Microsoft.EntityFrameworkCore; |
|
|
using Microsoft.Extensions.Configuration; |
|
|
using Microsoft.Extensions.Configuration; |
|
|
using Microsoft.Extensions.DependencyInjection; |
|
|
using Microsoft.Extensions.DependencyInjection; |
|
|
|
|
|
using Microsoft.Extensions.Logging; |
|
|
using RestSharp.Extensions; |
|
|
using RestSharp.Extensions; |
|
|
using SettleAccount.Job.SignalR; |
|
|
using SettleAccount.Job.SignalR; |
|
|
using SqlSugar; |
|
|
using SqlSugar; |
|
@ -53,6 +56,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
private readonly IBlobContainer<MyFileContainer> _fileContainer; |
|
|
private readonly IBlobContainer<MyFileContainer> _fileContainer; |
|
|
private readonly IHubContext<PageHub> _hubContext; |
|
|
private readonly IHubContext<PageHub> _hubContext; |
|
|
private readonly ICurrentUser _currentUser; |
|
|
private readonly ICurrentUser _currentUser; |
|
|
|
|
|
private readonly ILogger<VmiAppService> _logger; |
|
|
|
|
|
|
|
|
public VmiAppService(IConfiguration cfg, |
|
|
public VmiAppService(IConfiguration cfg, |
|
|
IServiceProvider serviceProvider, |
|
|
IServiceProvider serviceProvider, |
|
@ -61,7 +65,8 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
INormalEfCoreRepository<VmiLog, Guid> logRepository, |
|
|
INormalEfCoreRepository<VmiLog, Guid> logRepository, |
|
|
IBlobContainer<MyFileContainer> fileContainer, |
|
|
IBlobContainer<MyFileContainer> fileContainer, |
|
|
IHubContext<PageHub> hubContext, |
|
|
IHubContext<PageHub> hubContext, |
|
|
ICurrentUser currentUser) |
|
|
ICurrentUser currentUser, |
|
|
|
|
|
ILogger<VmiAppService> logger) |
|
|
{ |
|
|
{ |
|
|
this._cfg = cfg; |
|
|
this._cfg = cfg; |
|
|
this._guidGenerator = guidGenerator; |
|
|
this._guidGenerator = guidGenerator; |
|
@ -71,6 +76,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
this._fileContainer = fileContainer; |
|
|
this._fileContainer = fileContainer; |
|
|
this._hubContext = hubContext; |
|
|
this._hubContext = hubContext; |
|
|
this._currentUser = currentUser; |
|
|
this._currentUser = currentUser; |
|
|
|
|
|
this._logger = logger; |
|
|
LinqToDBForEFTools.Initialize(); |
|
|
LinqToDBForEFTools.Initialize(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -260,7 +266,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
Debug.WriteLine($"{tableName}不存在"); |
|
|
this._logger.LogInformation($"{tableName}不存在"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -270,8 +276,12 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
if (tables.Any()) |
|
|
if (tables.Any()) |
|
|
{ |
|
|
{ |
|
|
//生成 union all 的 SQL使用 FromSqlRaw 查询,如果没有分表则使用原始表
|
|
|
//生成 union all 的 SQL使用 FromSqlRaw 查询,如果没有分表则使用原始表
|
|
|
sql = $"select * from {tables.First()}"; |
|
|
sql = $"select * from {tables.First()} WITH(NOLOCK)"; |
|
|
tables.Skip(1).ForEach(o => sql += $" union all select * from ${o}"); |
|
|
tables.Skip(1).ForEach(o => sql += $" union all select * from ${o} WITH(NOLOCK)"); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
sql = "select * from Set_VmiLog WITH(NOLOCK)"; |
|
|
} |
|
|
} |
|
|
var query = string.IsNullOrEmpty(sql) ? db.Set<VmiLog>().AsQueryable() : db.Set<VmiLog>().FromSqlRaw(sql); |
|
|
var query = string.IsNullOrEmpty(sql) ? db.Set<VmiLog>().AsQueryable() : db.Set<VmiLog>().FromSqlRaw(sql); |
|
|
var filters = input.Filters.ToLambda<VmiLog>(); |
|
|
var filters = input.Filters.ToLambda<VmiLog>(); |
|
@ -333,21 +343,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
var options = new DbContextOptionsBuilder<SettleAccountDbContext>().UseSqlServer(connection).Options; |
|
|
var options = new DbContextOptionsBuilder<SettleAccountDbContext>().UseSqlServer(connection).Options; |
|
|
using var context = new SettleAccountDbContext(options); |
|
|
using var context = new SettleAccountDbContext(options); |
|
|
context.Database.UseTransaction(transaction); |
|
|
context.Database.UseTransaction(transaction); |
|
|
log.ChangedTime = log.Id.ToDateTime().Value; |
|
|
Update(log); |
|
|
if (log.ChangedQty >= decimal.Zero) |
|
|
|
|
|
{ |
|
|
|
|
|
log.Qty = log.ChangedQty; |
|
|
|
|
|
log.LogType = VmiLogType.Type500; |
|
|
|
|
|
log.ChangedType = VmiType.In; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
log.Qty = -log.Qty; |
|
|
|
|
|
log.LogType = VmiLogType.Type600; |
|
|
|
|
|
log.ChangedType = VmiType.Out; |
|
|
|
|
|
} |
|
|
|
|
|
log.ChangedBy = this._currentUser.UserName; |
|
|
|
|
|
log.ChangedTime = DateTime.Now; |
|
|
|
|
|
context.Set<VmiLog>().Add(log); |
|
|
context.Set<VmiLog>().Add(log); |
|
|
context.Set<VmiMessage>().Add(new VmiMessage { Message = JsonSerializer.Serialize(log) }); |
|
|
context.Set<VmiMessage>().Add(new VmiMessage { Message = JsonSerializer.Serialize(log) }); |
|
|
context.SaveChanges(); |
|
|
context.SaveChanges(); |
|
@ -357,11 +353,29 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
catch (Exception ex) |
|
|
catch (Exception ex) |
|
|
{ |
|
|
{ |
|
|
transaction.Rollback(); |
|
|
transaction.Rollback(); |
|
|
Console.WriteLine(ex.ToString()); |
|
|
this._logger.LogError(ex.ToString()); |
|
|
return new JsonResult(new { code = 400, data = ex.ToString(), message = ex.Message }); ; |
|
|
return new JsonResult(new { code = 400, data = ex.ToString(), message = ex.Message }); ; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void Update(VmiLog log) |
|
|
|
|
|
{ |
|
|
|
|
|
log.ChangedTime = log.Id.ToDateTime().Value; |
|
|
|
|
|
if (log.ChangedQty >= decimal.Zero) |
|
|
|
|
|
{ |
|
|
|
|
|
log.Qty = log.ChangedQty; |
|
|
|
|
|
log.LogType = VmiLogType.Type500; |
|
|
|
|
|
log.ChangedType = VmiType.In; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
log.Qty = -log.Qty; |
|
|
|
|
|
log.LogType = VmiLogType.Type600; |
|
|
|
|
|
log.ChangedType = VmiType.Out; |
|
|
|
|
|
} |
|
|
|
|
|
log.ChangedBy = this._currentUser.UserName; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 库存调整导入
|
|
|
/// 库存调整导入
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
@ -369,6 +383,8 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
[HttpPost] |
|
|
[HttpPost] |
|
|
public async Task<IActionResult> Import(List<IFormFile> files) |
|
|
public async Task<IActionResult> Import(List<IFormFile> files) |
|
|
{ |
|
|
{ |
|
|
|
|
|
var connectionString = this._serviceProvider.GetRequiredService<IConfiguration>().GetConnectionString("SettleAccountService"); |
|
|
|
|
|
using var connection = new SqlConnection(connectionString); |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
using var ms = new MemoryStream(); |
|
|
using var ms = new MemoryStream(); |
|
@ -381,11 +397,11 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
using var workbook = new XLWorkbook(new MemoryStream(data)); |
|
|
using var workbook = new XLWorkbook(new MemoryStream(data)); |
|
|
var ws = workbook.Worksheets.FirstOrDefault(); |
|
|
var ws = workbook.Worksheets.FirstOrDefault(); |
|
|
var header = ws.Row(1); |
|
|
var header = ws.Row(1); |
|
|
var errorIndex = ws.ColumnsUsed().Count(); |
|
|
var errorIndex = ws.ColumnsUsed().Count() + 1; |
|
|
header.Cell(errorIndex).Value = "提示信息"; |
|
|
header.Cell(errorIndex).Value = "提示信息"; |
|
|
for (int i = 2; i < ws.RowsUsed().Count(); i++) |
|
|
for (int i = 0; i < ws.RowsUsed().Count() - 1; i++) |
|
|
{ |
|
|
{ |
|
|
ws.Row(2).Cell(errorIndex).Value = string.Join(',', validationResults[i - 2].Select(o => o.ErrorMessage)); |
|
|
ws.Row(i + 2).Cell(errorIndex).Value = string.Join(',', validationResults[i].Select(o => o.ErrorMessage)); |
|
|
} |
|
|
} |
|
|
SetStyle(ws); |
|
|
SetStyle(ws); |
|
|
using var stream = new MemoryStream(); |
|
|
using var stream = new MemoryStream(); |
|
@ -395,16 +411,26 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
await this._fileContainer.SaveAsync(fileName, stream, true).ConfigureAwait(false); |
|
|
await this._fileContainer.SaveAsync(fileName, stream, true).ConfigureAwait(false); |
|
|
return new JsonResult(new { code = 400, message = "输入异常", fileName }); |
|
|
return new JsonResult(new { code = 400, message = "输入异常", fileName }); |
|
|
} |
|
|
} |
|
|
foreach (var item in list) |
|
|
var options = new DbContextOptionsBuilder<SettleAccountDbContext>().UseSqlServer(connection).Options; |
|
|
{ |
|
|
using var context = new SettleAccountDbContext(options); |
|
|
Adjust(item); |
|
|
list.ForEach(Update); |
|
|
} |
|
|
var messageList = list.Select(log => new VmiMessage { Message = JsonSerializer.Serialize(log) }); |
|
|
|
|
|
using var dc = context.CreateLinqToDBConnection(); |
|
|
|
|
|
dc.BeginTransaction(); |
|
|
|
|
|
var st = new Stopwatch(); |
|
|
|
|
|
st.Start(); |
|
|
|
|
|
this._logger.LogInformation("事务开始"); |
|
|
|
|
|
await dc.BulkCopyAsync(new BulkCopyOptions { TableName = "Set_VmiLog", MaxBatchSize = 1000 }, list).ConfigureAwait(false); |
|
|
|
|
|
await dc.BulkCopyAsync(new BulkCopyOptions { TableName = "Set_VmiMessage", MaxBatchSize = 1000 }, messageList).ConfigureAwait(false); |
|
|
|
|
|
dc.CommitTransaction(); |
|
|
|
|
|
st.Stop(); |
|
|
|
|
|
this._logger.LogInformation($"事务结束,耗时 ${st.ElapsedMilliseconds / 1000 / 60}分钟"); |
|
|
return new JsonResult(new { code = 200, message = "ok" }); |
|
|
return new JsonResult(new { code = 200, message = "ok" }); |
|
|
} |
|
|
} |
|
|
catch (Exception ex) |
|
|
catch (Exception ex) |
|
|
{ |
|
|
{ |
|
|
Console.WriteLine(ex.ToString()); |
|
|
this._logger.LogError(ex.ToString()); |
|
|
throw; |
|
|
return new JsonResult(new { code = 500, data = ex.ToString(), message = ex.Message }); ; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -416,8 +442,8 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
{ |
|
|
{ |
|
|
using var workbook = new XLWorkbook(new MemoryStream(data)); |
|
|
using var workbook = new XLWorkbook(new MemoryStream(data)); |
|
|
var properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty) |
|
|
var properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty) |
|
|
.Where(o => o.GetAttributes<ImporterHeaderAttribute>().Any()) |
|
|
.Where(o => o.GetAttributes<ImporterHeaderAttribute>().Any() || o.GetAttributes<DisplayAttribute>().Any()) |
|
|
.ToDictionary(o => o.GetAttribute<ImporterHeaderAttribute>().Name, o => o); |
|
|
.ToDictionary(o => o.GetAttribute<ImporterHeaderAttribute>()?.Name ?? o.GetAttribute<DisplayAttribute>()?.Name, o => o); |
|
|
var ws = workbook.Worksheets.FirstOrDefault(); |
|
|
var ws = workbook.Worksheets.FirstOrDefault(); |
|
|
|
|
|
|
|
|
for (int rowIndex = 2; rowIndex <= ws.RowsUsed().Count(); rowIndex++) |
|
|
for (int rowIndex = 2; rowIndex <= ws.RowsUsed().Count(); rowIndex++) |
|
@ -430,10 +456,38 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim(); |
|
|
var headerName = ws.Cell(1, columnIndex).Value.ToString().Trim(); |
|
|
if (properties.TryGetValue(headerName, out var property)) |
|
|
if (properties.TryGetValue(headerName, out var property)) |
|
|
{ |
|
|
{ |
|
|
|
|
|
var propertyType = property.PropertyType; |
|
|
var value = cell.Value.ToString(); |
|
|
var value = cell.Value.ToString(); |
|
|
if (!string.IsNullOrEmpty(value)) |
|
|
if (!string.IsNullOrEmpty(value)) |
|
|
{ |
|
|
{//值非空
|
|
|
property.SetValue(model, Convert.ChangeType(value, property.PropertyType)); |
|
|
if (propertyType.IsValueType()) |
|
|
|
|
|
{//值类型
|
|
|
|
|
|
if (propertyType.IsGenericType() && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) |
|
|
|
|
|
{//可空值类型
|
|
|
|
|
|
propertyType = propertyType.GetGenericArguments()[0];//取原始类型
|
|
|
|
|
|
} |
|
|
|
|
|
if (propertyType.IsEnum) |
|
|
|
|
|
{//枚举
|
|
|
|
|
|
var enumValue = Enum.GetNames(propertyType) |
|
|
|
|
|
.Select(o => new KeyValuePair<string, Enum>(o, (Enum)Enum.Parse(propertyType, o))) |
|
|
|
|
|
.Where(o => o.Value.GetDisplayName() == value.ToString()) |
|
|
|
|
|
.Select(o => o.Value) |
|
|
|
|
|
.FirstOrDefault(); |
|
|
|
|
|
property.SetValue(model, enumValue); |
|
|
|
|
|
} |
|
|
|
|
|
else if (propertyType == typeof(DateTime)) |
|
|
|
|
|
{ |
|
|
|
|
|
property.SetValue(model, DateTime.Parse(value)); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
property.SetValue(model, Convert.ChangeType(value, property.PropertyType)); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{//引用类型
|
|
|
|
|
|
property.SetValue(model, Convert.ChangeType(value, property.PropertyType)); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -446,7 +500,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran |
|
|
} |
|
|
} |
|
|
catch (Exception ex) |
|
|
catch (Exception ex) |
|
|
{ |
|
|
{ |
|
|
Console.WriteLine(ex.ToString()); |
|
|
this._logger.LogError(ex.ToString()); |
|
|
throw; |
|
|
throw; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|