|
|
@ -1,24 +1,34 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.ComponentModel.DataAnnotations; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Globalization; |
|
|
|
using System.IO; |
|
|
|
using System.Linq; |
|
|
|
using System.Linq.Dynamic.Core; |
|
|
|
using System.Reflection; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using ClosedXML.Excel; |
|
|
|
using InfluxDB.LineProtocol.Client; |
|
|
|
using Magicodes.ExporterAndImporter.Core.Extension; |
|
|
|
using Microsoft.AspNetCore.Authorization; |
|
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
|
using Microsoft.EntityFrameworkCore; |
|
|
|
using Microsoft.EntityFrameworkCore.Infrastructure; |
|
|
|
using Microsoft.EntityFrameworkCore.Storage; |
|
|
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; |
|
|
|
using Microsoft.Extensions.Configuration; |
|
|
|
using Microsoft.OpenApi.Extensions; |
|
|
|
using Volo.Abp.Application.Dtos; |
|
|
|
using Volo.Abp.Application.Services; |
|
|
|
using Volo.Abp.AspNetCore.Uow; |
|
|
|
using Volo.Abp.BlobStoring; |
|
|
|
using Volo.Abp.DependencyInjection; |
|
|
|
using Win.Sfs.BaseData.ImportExcelCommon; |
|
|
|
using Win.Sfs.SettleAccount.Entities.BQ.Dtos; |
|
|
|
using Win.Sfs.SettleAccount.Entities.BQ.Vmi; |
|
|
|
using Win.Sfs.SettleAccount.EntityFrameworkCore; |
|
|
|
using Win.Sfs.SettleAccount.influxdb; |
|
|
|
using Win.Sfs.Shared.Filter; |
|
|
|
using Win.Sfs.Shared.RepositoryBase; |
|
|
|
using static Microsoft.EntityFrameworkCore.DbLoggerCategory; |
|
|
|
|
|
|
|
namespace Win.Sfs.SettleAccount.Entities.BQ; |
|
|
|
|
|
|
@ -35,17 +45,22 @@ public interface IVmiService : IApplicationService, ITransientDependency, IJobSe |
|
|
|
[Route("api/settleaccount/[controller]/[action]")]
|
|
|
|
public class VmiAppService : ApplicationService, IVmiService, IJobService, ITransientDependency |
|
|
|
{ |
|
|
|
private readonly IConfiguration _cfg; |
|
|
|
private readonly INormalEfCoreRepository<VmiBalance, Guid> _balanceRepository; |
|
|
|
private readonly INormalEfCoreRepository<VmiLog, Guid> _logRepository; |
|
|
|
private readonly INormalEfCoreRepository<VmiSnapshot, Guid> _snapshotRepository; |
|
|
|
private readonly IBlobContainer<MyFileContainer> _fileContainer; |
|
|
|
|
|
|
|
public VmiAppService(INormalEfCoreRepository<VmiBalance, Guid> balanceRepository, |
|
|
|
public VmiAppService(IConfiguration cfg, INormalEfCoreRepository<VmiBalance, Guid> balanceRepository, |
|
|
|
INormalEfCoreRepository<VmiLog, Guid> logRepository, |
|
|
|
INormalEfCoreRepository<VmiSnapshot, Guid> snapshotRepository) |
|
|
|
INormalEfCoreRepository<VmiSnapshot, Guid> snapshotRepository, |
|
|
|
IBlobContainer<MyFileContainer> fileContainer) |
|
|
|
{ |
|
|
|
this._cfg = cfg; |
|
|
|
this._balanceRepository = balanceRepository; |
|
|
|
this._logRepository = logRepository; |
|
|
|
this._snapshotRepository = snapshotRepository; |
|
|
|
this._fileContainer = fileContainer; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
@ -60,15 +75,16 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran |
|
|
|
using var dbContext = new VmiSqliteContext(connectionString); |
|
|
|
if (!dbContext.GetService<IRelationalDatabaseCreator>().Exists() && dbContext.Database.EnsureCreated()) |
|
|
|
{ |
|
|
|
this._balanceRepository.AsNoTracking().ForEachAsync(o => |
|
|
|
var list = this._balanceRepository.AsNoTracking().ToList(); |
|
|
|
foreach (var item in list) |
|
|
|
{ |
|
|
|
dbContext.Set<VmiBalance>().Add(o); |
|
|
|
}); |
|
|
|
dbContext.Set<VmiBalance>().Add(item); |
|
|
|
} |
|
|
|
dbContext.SaveChanges(); |
|
|
|
var snapshot = new VmiSnapshot { Name = date, Path = connectionString }; |
|
|
|
this._snapshotRepository.InsertAsync(snapshot).Wait(); |
|
|
|
} |
|
|
|
Console.WriteLine($"{nameof(VmiAppService)}:{DateTime.Now}"); |
|
|
|
Debug.WriteLine($"{nameof(VmiAppService)}:{DateTime.Now}"); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
@ -107,10 +123,23 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran |
|
|
|
{ |
|
|
|
var entities = await _balanceRepository.GetListByFilterAsync(input.Filters, input.Sorting, input.MaxResultCount, input.SkipCount, true).ConfigureAwait(false); |
|
|
|
var totalCount = await _balanceRepository.GetCountByFilterAsync(input.Filters).ConfigureAwait(false); |
|
|
|
//var dtos = ObjectMapper.Map<List<CodeSetting>, List<CodeSettingDto>>(entities);
|
|
|
|
return new PagedResultDto<VmiBalance>(totalCount, entities); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 库存余额导出
|
|
|
|
/// </summary>
|
|
|
|
[HttpPost] |
|
|
|
public async Task<string> BalanceExport(RequestDto input) |
|
|
|
{ |
|
|
|
var entities = await _balanceRepository.WhereIf(input.Filters?.Count != 0, input.Filters.ToLambda<VmiBalance>()) |
|
|
|
.ToListAsync().ConfigureAwait(false); |
|
|
|
var fileName = $"库存余额_{DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss")}.xlsx"; |
|
|
|
var content = this.GetContent<VmiBalance>(entities, "库存备份"); |
|
|
|
await _fileContainer.SaveAsync(fileName, content, true).ConfigureAwait(false); |
|
|
|
return fileName; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 库存事务查询
|
|
|
|
/// </summary>
|
|
|
@ -119,27 +148,230 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran |
|
|
|
[HttpPost] |
|
|
|
public async Task<PagedResultDto<VmiLog>> Log(RequestDto input) |
|
|
|
{ |
|
|
|
var entities = await _logRepository.GetListByFilterAsync(input.Filters, input.Sorting, input.MaxResultCount, input.SkipCount, true).ConfigureAwait(false); |
|
|
|
var totalCount = await _logRepository.GetCountByFilterAsync(input.Filters).ConfigureAwait(false); |
|
|
|
//var dtos = ObjectMapper.Map<List<CodeSetting>, List<CodeSettingDto>>(entities);
|
|
|
|
return new PagedResultDto<VmiLog>(totalCount, entities); |
|
|
|
var type = typeof(VmiLog); |
|
|
|
var querySql = $"select * from {typeof(VmiLog).Name} where 1=1"; |
|
|
|
var countSql = $"select count(*) from {typeof(VmiLog).Name} where 1=1"; |
|
|
|
var where = ""; |
|
|
|
if (input.Filters.Any()) |
|
|
|
{ |
|
|
|
foreach (var item in input.Filters) |
|
|
|
{ |
|
|
|
var property = type.GetProperties().FirstOrDefault(p => p.Name.ToLowerInvariant() == item.Column.ToLowerInvariant()); |
|
|
|
if (property != null) |
|
|
|
{ |
|
|
|
var @operator = GetOperator(item.Action); |
|
|
|
var value = GetValue(property, item.Value); |
|
|
|
where += $" and {property.Name}{string.Format(GetOperator(item.Action), item.Value)}"; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
var herlper = new InfluxHelper(_cfg); |
|
|
|
var countResult = await herlper.Query(countSql + where).ConfigureAwait(false); |
|
|
|
var count = Convert.ToInt32(countResult.results.FirstOrDefault().series.FirstOrDefault().values.FirstOrDefault().LastOrDefault()); |
|
|
|
var result = await herlper.Query(querySql + where).ConfigureAwait(false); |
|
|
|
var entities = new List<VmiLog>(); |
|
|
|
result.results.FirstOrDefault().series.FirstOrDefault().values.ForEach(v => |
|
|
|
{ |
|
|
|
var entity = Activator.CreateInstance<VmiLog>(); |
|
|
|
entities.Add(entity); |
|
|
|
var i = 0; |
|
|
|
result.results.FirstOrDefault().series.FirstOrDefault().columns.ForEach(c => |
|
|
|
{ |
|
|
|
var property = type.GetProperty(c); |
|
|
|
if (property != null) |
|
|
|
{ |
|
|
|
this.SetPropertyValue(property, entity, v[i]); |
|
|
|
i++; |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
return new PagedResultDto<VmiLog>(count, entities); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 快照列表
|
|
|
|
/// </summary>
|
|
|
|
[HttpPost] |
|
|
|
public async Task<ListResultDto<VmiSnapshot>> Snapshot() |
|
|
|
{ |
|
|
|
var list = await _snapshotRepository.GetListAsync().ConfigureAwait(false); |
|
|
|
return new ListResultDto<VmiSnapshot>(list); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 时点库存查询
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="name">备份名称</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
[HttpPost("{name}")] |
|
|
|
public async Task<PagedResultDto<VmiBalance>> Backup(string name, RequestDto input) |
|
|
|
[HttpPost] |
|
|
|
public async Task<PagedResultDto<VmiBalance>> Backup(BackupListRequest input) |
|
|
|
{ |
|
|
|
var connectionString = $"Data Source=wwwroot/files/vmi/{name}.db"; |
|
|
|
var connectionString = $"Data Source=wwwroot/files/vmi/{input.Name}.db"; |
|
|
|
using var dbContext = new VmiSqliteContext(connectionString); |
|
|
|
var repo = dbContext.Set<VmiBalance>(); |
|
|
|
var filters = input.Filters.ToLambda<VmiBalance>(); |
|
|
|
var query = (input.Filters.Count > 0 ? repo.Where(input.Filters.ToLambda<VmiBalance>()) : repo); |
|
|
|
var totalCount = query.Count(); |
|
|
|
var entities = await query.PageBy(input.SkipCount, input.MaxResultCount).ToListAsync(); |
|
|
|
query = string.IsNullOrEmpty(input.Sorting) ? query : DynamicQueryableExtensions.OrderBy(query, input.Sorting); |
|
|
|
var entities = await query.PageBy(input.SkipCount, input.MaxResultCount).ToListAsync().ConfigureAwait(false); |
|
|
|
return new PagedResultDto<VmiBalance>(totalCount, entities); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 时点库存导出
|
|
|
|
/// </summary>
|
|
|
|
[HttpPost] |
|
|
|
public async Task<string> BackupExport(BackupListRequest input) |
|
|
|
{ |
|
|
|
var connectionString = $"Data Source=wwwroot/files/vmi/{input.Name}.db"; |
|
|
|
using var dbContext = new VmiSqliteContext(connectionString); |
|
|
|
var repo = dbContext.Set<VmiBalance>(); |
|
|
|
var filters = input.Filters.ToLambda<VmiBalance>(); |
|
|
|
var query = (input.Filters.Count > 0 ? repo.Where(input.Filters.ToLambda<VmiBalance>()) : repo); |
|
|
|
query = string.IsNullOrEmpty(input.Sorting) ? query : DynamicQueryableExtensions.OrderBy(query, input.Sorting); |
|
|
|
var entities = await query.ToListAsync().ConfigureAwait(false); |
|
|
|
var fileName = $"库存备份_{input.Name}.xlsx"; |
|
|
|
var content = this.GetContent(entities, "库存备份"); |
|
|
|
await _fileContainer.SaveAsync(fileName, content, true).ConfigureAwait(false); |
|
|
|
return fileName; |
|
|
|
} |
|
|
|
|
|
|
|
private byte[] GetContent<TExport>(List<TExport> entities, string name = "sheet1") |
|
|
|
{ |
|
|
|
using var workbook = new XLWorkbook(); |
|
|
|
var ws = workbook.Worksheets.Add(name); |
|
|
|
var type = typeof(TExport); |
|
|
|
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty) |
|
|
|
.Where(o => o.GetAttributes<DisplayAttribute>().Any()) |
|
|
|
.ToList(); |
|
|
|
var rowIndex = 1; |
|
|
|
for (var i = 0; i < properties.Count; i++) |
|
|
|
{ |
|
|
|
var property = properties[i]; |
|
|
|
var columnIndex = i + 1; |
|
|
|
var cell = ws.Cell(1, columnIndex); |
|
|
|
cell.Value = property.GetAttributes<DisplayAttribute>().Any() ? property.GetAttribute<DisplayAttribute>().Name : property.Name; |
|
|
|
} |
|
|
|
foreach (var item in entities) |
|
|
|
{ |
|
|
|
rowIndex++; |
|
|
|
for (var i = 0; i < properties.Count; i++) |
|
|
|
{ |
|
|
|
var property = properties[i]; |
|
|
|
var columnIndex = i + 1; |
|
|
|
var cell = ws.Cell(rowIndex, columnIndex); |
|
|
|
SetCell(item, cell, property); |
|
|
|
} |
|
|
|
} |
|
|
|
ws.RangeUsed().Style.Border.TopBorder = |
|
|
|
ws.RangeUsed().Style.Border.RightBorder = |
|
|
|
ws.RangeUsed().Style.Border.BottomBorder = |
|
|
|
ws.RangeUsed().Style.Border.LeftBorder = XLBorderStyleValues.Thin; |
|
|
|
ws.RangeUsed().Style.Border.TopBorderColor = |
|
|
|
ws.RangeUsed().Style.Border.RightBorderColor = |
|
|
|
ws.RangeUsed().Style.Border.BottomBorderColor = |
|
|
|
ws.RangeUsed().Style.Border.LeftBorderColor = XLColor.Black; |
|
|
|
ws.RangeUsed().SetAutoFilter(); |
|
|
|
ws.ColumnsUsed().AdjustToContents(); |
|
|
|
ws.RowsUsed().AdjustToContents(); |
|
|
|
using var stream = new MemoryStream(); |
|
|
|
workbook.SaveAs(stream); |
|
|
|
stream.Seek(0, SeekOrigin.Begin); |
|
|
|
return stream.ToArray(); |
|
|
|
} |
|
|
|
|
|
|
|
[HttpGet] |
|
|
|
public async Task<InfluxQueryResult> InfluxQueryTest(string q) |
|
|
|
{ |
|
|
|
return await new InfluxHelper(_cfg).Query(q).ConfigureAwait(false); |
|
|
|
} |
|
|
|
|
|
|
|
[HttpGet] |
|
|
|
public List<VmiLog> InfluxQueryTest2() |
|
|
|
{ |
|
|
|
var sql = this._logRepository.Where(o => o.Category == null || o.Category == "").ToQueryString(); |
|
|
|
return new InfluxHelper(_cfg).Query<VmiLog>(out long total, 1, 10, o => o.Category == null || o.Category == ""); |
|
|
|
} |
|
|
|
|
|
|
|
[HttpGet] |
|
|
|
public async Task<LineProtocolWriteResult> InfluxInsertTest(string q) |
|
|
|
{ |
|
|
|
return await new InfluxHelper(_cfg).Insert(new VmiLog()).ConfigureAwait(false); |
|
|
|
} |
|
|
|
|
|
|
|
private static void SetCell<TExportModel>(TExportModel? model, IXLCell cell, PropertyInfo property) |
|
|
|
{ |
|
|
|
var propertyType = property.PropertyType; |
|
|
|
var value = property.GetValue(model)?.ToString()?.Trim(); |
|
|
|
if (string.IsNullOrEmpty(value)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
if (propertyType == typeof(bool)) |
|
|
|
{ |
|
|
|
cell.Value = (bool)property.GetValue(model)! ? "是" : "否"; |
|
|
|
} |
|
|
|
else if (propertyType.IsEnum) |
|
|
|
{ |
|
|
|
cell.Value = (Enum.Parse(propertyType, value) as Enum)?.GetDisplayName(); |
|
|
|
} |
|
|
|
else if (propertyType == typeof(DateTime)) |
|
|
|
{ |
|
|
|
cell.Value = ((DateTime)property.GetValue(model)!).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
cell.Value = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void SetPropertyValue(PropertyInfo property, VmiLog entity, string value) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
object propertyValue = null; |
|
|
|
if (!string.IsNullOrEmpty(value)) |
|
|
|
{ |
|
|
|
propertyValue = Convert.ChangeType(value, property.PropertyType); |
|
|
|
} |
|
|
|
property.SetValue(entity, propertyValue, null); |
|
|
|
} |
|
|
|
catch (Exception) |
|
|
|
{ |
|
|
|
throw; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private string GetOperator(EnumFilterAction action) |
|
|
|
{ |
|
|
|
var dictonary = new Dictionary<EnumFilterAction, string>() { |
|
|
|
{EnumFilterAction.Equal,"={0}"}, |
|
|
|
{EnumFilterAction.NotEqual,"!={0}"}, |
|
|
|
{EnumFilterAction.SmallThanOrEqual,"<={0}"}, |
|
|
|
{EnumFilterAction.Like,"~/{0}/"}, |
|
|
|
{EnumFilterAction.NotLike,"!~/{0}/"}, |
|
|
|
{EnumFilterAction.BiggerThan,">{0}"}, |
|
|
|
{EnumFilterAction.BiggerThanOrEqual,">={0}"}, |
|
|
|
{EnumFilterAction.SmallThan,"<{0}"}, |
|
|
|
}; |
|
|
|
return dictonary[action]; |
|
|
|
} |
|
|
|
|
|
|
|
private object GetValue(PropertyInfo property, string value) |
|
|
|
{ |
|
|
|
if (property.PropertyType == typeof(int) || |
|
|
|
property.PropertyType == typeof(long) || |
|
|
|
property.PropertyType == typeof(float) || |
|
|
|
property.PropertyType == typeof(double) || |
|
|
|
property.PropertyType == typeof(decimal) || |
|
|
|
property.PropertyType == typeof(bool)) |
|
|
|
{ |
|
|
|
return value; |
|
|
|
} |
|
|
|
return $"'{value}'"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class BackupListRequest : RequestDto |
|
|
|
{ |
|
|
|
[Required] |
|
|
|
public string Name { get; set; } |
|
|
|
} |
|
|
|