diff --git a/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/BaseServiceHostModule.cs b/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/BaseServiceHostModule.cs index 38f03882..478eac50 100644 --- a/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/BaseServiceHostModule.cs +++ b/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/BaseServiceHostModule.cs @@ -217,7 +217,7 @@ namespace BaseService .ConventionalControllers .Create(typeof(BaseServiceApplicationModule).Assembly, opts => - { opts.RootPath = "base"; }) + { opts.RootPath = "base"; }) ; }); } diff --git a/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/Program.cs b/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/Program.cs index d6b6b052..a0ab119f 100644 --- a/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/Program.cs +++ b/code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/Program.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; -using Serilog.Settings.Configuration; namespace Win.Sfs.SettleAccount; @@ -13,21 +12,13 @@ public class Program { var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true) - .Build(); - //try - //{ - // new InfluxHelper(configuration).Start(); - //} - //catch (Exception ex) - //{ - // Console.Write("时序数据库启动失败"); - // Console.Write(ex.ToString()); - // //throw; - //} + .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration, ConfigurationAssemblySource.AlwaysScanDllFiles) + .WriteTo.Async(c => c.File("Logs/logs.txt" + , rollingInterval: RollingInterval.Day + , rollOnFileSizeLimit: true + , fileSizeLimitBytes: 30 * 1024 * 1024)) .WriteTo.Async(c => c.Console()) .CreateLogger(); diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs index 0ec32ee1..7058e6b4 100644 --- a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs @@ -11,6 +11,8 @@ using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using ClosedXML.Excel; +using DocumentFormat.OpenXml; +using LinqToDB.Data; using LinqToDB.EntityFrameworkCore; using Magicodes.ExporterAndImporter.Core; using Magicodes.ExporterAndImporter.Core.Extension; @@ -21,6 +23,7 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using RestSharp.Extensions; using SettleAccount.Job.SignalR; using SqlSugar; @@ -53,6 +56,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran private readonly IBlobContainer _fileContainer; private readonly IHubContext _hubContext; private readonly ICurrentUser _currentUser; + private readonly ILogger _logger; public VmiAppService(IConfiguration cfg, IServiceProvider serviceProvider, @@ -61,7 +65,8 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran INormalEfCoreRepository logRepository, IBlobContainer fileContainer, IHubContext hubContext, - ICurrentUser currentUser) + ICurrentUser currentUser, + ILogger logger) { this._cfg = cfg; this._guidGenerator = guidGenerator; @@ -71,6 +76,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran this._fileContainer = fileContainer; this._hubContext = hubContext; this._currentUser = currentUser; + this._logger = logger; LinqToDBForEFTools.Initialize(); } @@ -260,7 +266,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran } else { - Debug.WriteLine($"{tableName}不存在"); + this._logger.LogInformation($"{tableName}不存在"); } } } @@ -270,8 +276,12 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran if (tables.Any()) { //生成 union all 的 SQL使用 FromSqlRaw 查询,如果没有分表则使用原始表 - sql = $"select * from {tables.First()}"; - tables.Skip(1).ForEach(o => sql += $" union all select * from ${o}"); + sql = $"select * from {tables.First()} WITH(NOLOCK)"; + 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().AsQueryable() : db.Set().FromSqlRaw(sql); var filters = input.Filters.ToLambda(); @@ -333,21 +343,7 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran var options = new DbContextOptionsBuilder().UseSqlServer(connection).Options; using var context = new SettleAccountDbContext(options); context.Database.UseTransaction(transaction); - 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; - log.ChangedTime = DateTime.Now; + Update(log); context.Set().Add(log); context.Set().Add(new VmiMessage { Message = JsonSerializer.Serialize(log) }); context.SaveChanges(); @@ -357,11 +353,29 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran catch (Exception ex) { transaction.Rollback(); - Console.WriteLine(ex.ToString()); + this._logger.LogError(ex.ToString()); 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; + } + /// /// 库存调整导入 /// @@ -369,6 +383,8 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran [HttpPost] public async Task Import(List files) { + var connectionString = this._serviceProvider.GetRequiredService().GetConnectionString("SettleAccountService"); + using var connection = new SqlConnection(connectionString); try { using var ms = new MemoryStream(); @@ -381,11 +397,11 @@ public class VmiAppService : Controller, IApplicationService, IJobService, ITran using var workbook = new XLWorkbook(new MemoryStream(data)); var ws = workbook.Worksheets.FirstOrDefault(); var header = ws.Row(1); - var errorIndex = ws.ColumnsUsed().Count(); + var errorIndex = ws.ColumnsUsed().Count() + 1; 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); 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); return new JsonResult(new { code = 400, message = "输入异常", fileName }); } - foreach (var item in list) - { - Adjust(item); - } + var options = new DbContextOptionsBuilder().UseSqlServer(connection).Options; + using var context = new SettleAccountDbContext(options); + 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" }); } catch (Exception ex) { - Console.WriteLine(ex.ToString()); - throw; + this._logger.LogError(ex.ToString()); + 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)); var properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty) - .Where(o => o.GetAttributes().Any()) - .ToDictionary(o => o.GetAttribute().Name, o => o); + .Where(o => o.GetAttributes().Any() || o.GetAttributes().Any()) + .ToDictionary(o => o.GetAttribute()?.Name ?? o.GetAttribute()?.Name, o => o); var ws = workbook.Worksheets.FirstOrDefault(); 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(); if (properties.TryGetValue(headerName, out var property)) { + var propertyType = property.PropertyType; var value = cell.Value.ToString(); 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(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) { - Console.WriteLine(ex.ToString()); + this._logger.LogError(ex.ToString()); throw; } } diff --git a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAsyncBalanceService.cs b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAsyncBalanceService.cs index f5509225..84b04f46 100644 --- a/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAsyncBalanceService.cs +++ b/code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAsyncBalanceService.cs @@ -1,13 +1,16 @@ using System; using System.Data.SqlClient; +using System.Diagnostics; using System.Linq; using System.Linq.Dynamic.Core; using System.Text.Json; using System.Threading.Tasks; using Magicodes.ExporterAndImporter.Core.Extension; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Omu.ValueInjecter; using Volo.Abp.Application.Services; using Volo.Abp.DependencyInjection; @@ -19,19 +22,37 @@ namespace Win.Sfs.SettleAccount.Entities.BQ; /// /// 异步更新库存 /// -public class VmiAsyncBalanceService : ApplicationService, IJobService, ITransientDependency +[Route("[controller]/[action]")] +public class VmiAsyncBalanceService : Controller, IApplicationService, IJobService, ITransientDependency { private readonly IServiceProvider _serviceProvider; + private readonly ILogger _logger; - public VmiAsyncBalanceService(IServiceProvider serviceProvider) + public VmiAsyncBalanceService(IServiceProvider serviceProvider, ILogger logger) { this._serviceProvider = serviceProvider; + this._logger = logger; } + /// + /// 异步更新库存,手动测试 + /// + /// + [HttpPost] + public async Task Test() + { + var now = DateTime.Now; + await Invoke(_serviceProvider).ConfigureAwait(false); + return (DateTime.Now - now).TotalMinutes; + } + + [NonAction] public async Task Invoke(IServiceProvider serviceProvider) { for (var i = 0; i < 100; i++) { + var sw = new Stopwatch(); + sw.Start(); var connectionString = serviceProvider.GetRequiredService().GetConnectionString("SettleAccountService"); using var connection = new SqlConnection(connectionString); connection.Open(); @@ -130,14 +151,15 @@ public class VmiAsyncBalanceService : ApplicationService, IJobService, ITransien } catch (Exception ex) { - Console.WriteLine(ex.ToString()); + this._logger.LogError(ex.ToString()); transaction.Rollback(); throw; } + finally + { + sw.Stop(); + this._logger.LogInformation($"结束,耗时 ${sw.ElapsedMilliseconds / 1000 / 60}分钟"); + } } } - - public async Task InvokeInternal(IServiceProvider serviceProvider) - { - } }