using Azure.Core; using Dapper; using Hangfire; using Magicodes.ExporterAndImporter.Core; using Magicodes.ExporterAndImporter.Core.Extension; using Magicodes.ExporterAndImporter.Excel; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using Omu.ValueInjecter; using SkiaSharp; using System.Collections.Generic; using System.Data; using System.Drawing.Printing; using System.Globalization; using System.Linq.Expressions; using System.Reflection; using System.Security.Policy; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using TaskManager.Contracts.Dtos; using TaskManager.Entity; using TaskManager.EntityFramework; using TaskManager.EntityFramework.Repository; using Wood.Service; using Wood.Util; using Wood.Util.Filters; using static Dapper.SqlMapper; namespace TaskManager.Controllers { public class CheryRecurringJobInputPageExtendController : RecurringJobBaseController where T : CherryWriteBaseEnity, new() where TDTO : class, new() where TLOGS : CherryWriteLogsBaseEnity, new() { protected readonly IRepository _repository; public CheryRecurringJobInputPageExtendController(HttpClient httpClient, JobDbContext jobDbContext, LogController log, IRepository repository) : base(httpClient, jobDbContext, log) { _repository = repository; } /// /// 手工发送调用接口 /// /// 任务名称 /// 请求日期 /// 客户(Chery) /// [HttpGet] public virtual async Task CustomInvokeAsync(string taskName, string client, Guid taskId) { try { var first = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == taskName && p.Client == client); if (first == null) { return; } Url = first.Url; Path = first.Api; TaskName = first.TaskName; Client = client; CPageSize = first.PageSize; List errorlist = new List(); if (first == null) { await _logger.AddError("任务配置不存在,任务设置表(TaskConfigure)是否存在任务对应的表!", taskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); return; } var tableName = first.TableName; string str = $"select count(1) count1 from {tableName} where writeState=0 and readState=1 "; var query = _jobDbContext.Database.GetDbConnection().Query(str); var total = query.FirstOrDefault(); var task = _jobDbContext.TaskSub.FirstOrDefault(p => p.TaskId == taskId); task.DataCount = total; _jobDbContext.Update(task); await _jobDbContext.SaveChangesAsync(); var failedCount = await CustomSyncTaskSubTable(taskName, taskId, total, tableName,Client, errorlist); // await SyncTaskSubTable(TaskName, Client,errorlist); var taskSub = _jobDbContext.TaskSub.FirstOrDefault(p => p.TaskId == taskId); if (failedCount > 0) { taskSub.FailedCount = failedCount; taskSub.WriteState = true; taskSub.FailedInfo = string.Join(",", errorlist); } else { taskSub.WriteState = true; } _jobDbContext.Update(taskSub); await _jobDbContext.SaveChangesAsync(); } catch (Exception ex) { await _logger.AddError(ex.Message, TaskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); } } [NonAction] public async Task SyncTaskSubTable() { } [HttpPost] public async Task> GetLogDataPaged(RequestInputBase input) { var pagingParams = new PagingParams { PageNumber = input.pageNumber, PageSize = input.pageSize, SortBy = input.sortBy, IsAscending = input.isAscending, }; //var json = JsonSerializer.Serialize(input); // 可以在这里构建表达式树过滤条件 Expression> filter = null; var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); return pagedResult; } protected override async Task DoExecutingAsync(string url, string path, string takName, string client, int pagesize) { Url = url; Path = path; TaskName = takName; Client = client; CPageSize = pagesize; await SyncTaskSubTable(TaskName, Client); } private async Task PostPageAsync(PagedRequest t, Guid taskId, string version) { try { string inputjson = string.Empty; if (TaskName == "日物料需求计划风险确认")//格式特殊处理 { inputjson = JsonSerializer.Serialize(t, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) } ); } else { inputjson = JsonSerializer.Serialize(t, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping } ); } // if (TaskName.Contains("供应商共享库存")) // { // inputjson = JsonSerializer.Serialize(t, // new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // new InputCustomDateTimeConverter(), // new InputCustomNullableDateTimeConverter() // }, // WriteIndented = false,// 可选,用于格式化输出 // Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // } // ); // } //if (TaskName.Contains("物料主数据")) //{ // inputjson = JsonSerializer.Serialize(t, // new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // new InputCustomDateTimeConverter(), // new InputCustomNullableDateTimeConverter() // }, // WriteIndented = false,// 可选,用于格式化输出 // Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // } // ); //} //else //{ // inputjson = JsonSerializer.Serialize(t, // new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // }, // WriteIndented = false,// 可选,用于格式化输出 // Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) // } // ); //} //inputjson = RemoveWhitespace(inputjson); var content = await Post(Url, Path, inputjson, taskId, version); if (!string.IsNullOrEmpty(content)) { var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter(), // 枚举转换 new OutCustomDateTimeConverter("yyyy-MM-dd HH:mm:ss") // 日期转换 } }; return JsonSerializer.Deserialize(content, options); } else { await _logger.AddError($"调用接口无返回值{Url}", TaskName, taskId, version); return null; } } catch (Exception ex) { await _logger.AddError($"调用接口无返回值错误{ex.Message}", TaskName, taskId, version); return null; } } public static string GenerateRandomStringWith8EG() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var random = new Random(); var sb = new StringBuilder(32); // 随机生成 "8EG" 的插入位置 (0-29) int position = random.Next(0, 30); // 生成前半部分随机字符串 for (int i = 0; i < position; i++) { sb.Append(chars[random.Next(chars.Length)]); } // 插入 "8EG" sb.Append("8EG"); // 生成后半部分随机字符串,补足32位 int remainingLength = 32 - sb.Length; for (int i = 0; i < remainingLength; i++) { sb.Append(chars[random.Next(chars.Length)]); } return sb.ToString(); } private async Task SyncTaskSubTable(string taskName, string client, List errorList = null) { var task = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == taskName); if (task == null) { await _logger.AddError("任务配置不存在,任务设置表(TaskConfigure)是否存在任务对应的表!", taskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); return; } var tableName = task.TableName; string str = $"select count(1) count1 from {tableName} where writeState=0 and readState=1 "; var query = _jobDbContext.Database.GetDbConnection().Query(str); var total = query.FirstOrDefault(); var version = DateTime.Now.ToString("yyyyMMdd"); var requestDate = DateTime.Now.ToString("yyyy-MM-dd"); var pageSize = 1000; int totalPages = (int)Math.Ceiling((double)total / pageSize); for (int i = 1; i <= totalPages; i++) { var records = _jobDbContext.Database.GetDbConnection().Query($"Select TOP {pageSize} * from {tableName} where writeState=0 and readstate=1 order by uid"); if (records.Any()) { var taskId = Guid.NewGuid(); List dtos = new List(); foreach (var itm in records) { TDTO dto = new TDTO(); dto.InjectFrom(itm); dtos.Add(dto); } PagedRequest pagedRequest = new PagedRequest() { batchNo = GenerateRandomStringWith8EG(), total = pageSize, pageSize = pageSize, list = dtos, pageNum = i }; foreach (var itm in records) { itm.WriteState = true; itm.TaskId = taskId; itm.RequestDate = requestDate; } var result = await PostPageAsync(pagedRequest, taskId, version); if (result.code == 200) { using (var transaction = await _jobDbContext.Database.BeginTransactionAsync()) { var tran = transaction.GetDbTransaction(); await _jobDbContext.BulkUpdateAsync(records, options => { options.UseTableLock = false; }); List logs = new List(); foreach (var itm in records) { TLOGS log = new TLOGS(); log.InjectFrom(itm); log.RequestDate = requestDate; log.TaskId = taskId; log.WriteState = true; log.ReadState = true; logs.Add(log); } await _jobDbContext.BulkInsertAsync(logs); try { var createtask = new TaskSub(); createtask.TaskId = taskId; createtask.TaskName = TaskName; createtask.Subscriber = Client; createtask.TableName = tableName; createtask.DataCount = pageSize; createtask.Domain = "1"; createtask.Site = "1"; createtask.FailedCount = 0; createtask.CreateTime = DateTime.Now; createtask.CreateUser = "admin"; createtask.CreationTime = DateTime.Now; createtask.SyncedPageCount = i; createtask.ReadState = true; createtask.WriteState = true; await _jobDbContext.AddAsync(task); // 提交事务 await transaction.CommitAsync(); await _logger.AddSuccess($"成功同步数据第 {i} 页数据", TaskName, taskId, version); } catch (Exception ex) { string inputjson = ""; if (TaskName == "日物料需求计划风险确认")//格式特殊处理 { inputjson = JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) } ); } else { inputjson = JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping } ); } // else // { // inputjson = JsonSerializer.Serialize(pagedRequest, // new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { //new DecimalTrimConverter(), // }, // WriteIndented = false,// 可选,用于格式化输出 // Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) // } // ); // } await _logger.AddError(ex.Message, TaskName, taskId, version, inputjson); await transaction.RollbackAsync(); } } } else { string inputjson = string.Empty; if (TaskName == "日物料需求计划风险确认")//格式特殊处理 { inputjson = JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) } ); } else { inputjson = JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false,// 可选,用于格式化输出 Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping } ); } //else //{ // inputjson = JsonSerializer.Serialize(pagedRequest, // new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // }, // WriteIndented = false,// 可选,用于格式化输出 // Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) // } // ); //} if (errorList != null) { errorList.Add($"第 {1} 页数据保存失败,请检查数据:{result.message}。"); } await _logger.AddError($"第 {1} 页数据保存失败,请检查数据:{result.message}。", TaskName, taskId, version, inputjson); break; } await Task.Delay(200); } } } private async Task CustomSyncTaskSubTable(string taskName, Guid taskId, int count, string tablename, string client, List errorList = null) { int errorRecordCount = 0; // 新增:错误记录计数器 var version = DateTime.Now.ToString("yyyyMMdd"); var requestDate = DateTime.Now.ToString("yyyy-MM-dd"); var pageSize = CPageSize; int totalPages = (int)Math.Ceiling((double)count / pageSize); for (int i = 1; i <= totalPages; i++) { var records = _jobDbContext.Database.GetDbConnection().Query($"Select TOP {pageSize} * from {tablename} where writeState=0 and readstate=1 order by uid"); if (records.Any()) { List dtos = new List(); foreach (var itm in records) { TDTO dto = new TDTO(); dto.InjectFrom(itm); dtos.Add(dto); } PagedRequest pagedRequest = new PagedRequest() { batchNo = GenerateRandomStringWith8EG(), total = pageSize, pageSize = pageSize, list = dtos, pageNum = i }; foreach (var itm in records) { itm.WriteState = true; itm.TaskId = taskId; itm.RequestDate = requestDate; } var result = await PostPageAsync(pagedRequest, taskId, version); if (result.code == 200) { using (var transaction = await _jobDbContext.Database.BeginTransactionAsync()) { var tran = transaction.GetDbTransaction(); await _jobDbContext.BulkUpdateAsync(records, options => { options.UseTableLock = false; }); List logs = new List(); foreach (var itm in records) { TLOGS log = new TLOGS(); log.InjectFrom(itm); log.RequestDate = requestDate; log.TaskId = taskId; log.WriteState = true; log.ReadState = true; logs.Add(log); } await _jobDbContext.BulkInsertAsync(logs); try { await transaction.CommitAsync(); await _logger.AddSuccess($"成功同步数据第 {i} 页数据", TaskName, taskId, version); } catch (Exception ex) { string inputjson = GetSerializedInputJson(pagedRequest, TaskName); await _logger.AddError(ex.Message, TaskName, taskId, version, inputjson); await transaction.RollbackAsync(); // 新增:记录错误页数和错误记录数 errorRecordCount += records.Count(); if (errorList != null) { errorList.Add($"第 {i} 页数据保存失败,数据库操作异常:{ex.Message}。"); } } } } else { string inputjson = GetSerializedInputJson(pagedRequest, TaskName); // 新增:记录错误页数和错误记录数 errorRecordCount += records.Count(); if (errorList != null) { errorList.Add($"第 {1} 页数据保存失败,请检查数据:{result.message}。"); } await _logger.AddError($"第 {1} 页数据保存失败,请检查数据:{result.message}。", TaskName, taskId, version, inputjson); var firstRecord =_jobDbContext.TaskSub.FirstOrDefault(p => p.TaskId == taskId); firstRecord.FailedCount = errorRecordCount; firstRecord.SyncedPageCount = 1; firstRecord.FailedInfo= $"第 {i} 页数据保存失败,请检查数据:{result.message}"; _jobDbContext.Update(firstRecord); _jobDbContext.SaveChanges(); // 注意:这里保留了原有的break语句,如果需要继续处理后续页数据,请移除这个break break; } await Task.Delay(200); } } return errorRecordCount; // 返回错误记录总数 } // 新增:提取的JSON序列化方法,减少代码重复 private string GetSerializedInputJson(PagedRequest pagedRequest, string taskName) { return taskName == "日物料需求计划风险确认" ? JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), new InputCustomDateTimeConverter(), new InputCustomNullableDateTimeConverter() }, WriteIndented = false, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) }) : JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DecimalTrimConverter(), }, WriteIndented = false, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) }); } [HttpGet] public async Task>> GetAll() { return await _repository.GetAllAsync() as List; } [HttpGet("{id}")] public async Task> GetById(int id) { var entity = await _repository.GetByIdAsync(id); if (entity == null) return NotFound(); return entity; } [HttpPost] public async Task> Create(T entity) { entity.CreationTime = DateTime.Now; var createdEntity = await _repository.AddAsync(entity); return new JsonResult(new { Code = 200, Message = "创建成功!" }); ; } [HttpPut("{id}")] public async Task Update(T entity) { if (entity.UId == 0) { throw new Exception("更新时,实体主键UId不能为空或0"); } var target = await _repository.GetByIdAsync(entity.UId); if (target == null) { throw new Exception($"CheryRecurringJobInputPageController.Update报错:根据UId{entity.UId}没有找到记录"); return new JsonResult(new { Code = 400, Message = "修改失败!" }); } EntityMapper.Trans(entity, target, "UId"); await _repository.UpdateAsync(target); return new JsonResult(new { Code = 200, Message = "修改成功!" }); } [HttpDelete("{id}")] public async Task Delete(int id) { await _repository.DeleteAsync(id); return new JsonResult(new { Code = 200, Message = "删除成功!" }); ; } //[HttpGet] //public async Task GetPaged( //[FromQuery] int pageNumber = 1, //[FromQuery] int pageSize = 10, //[FromQuery] string sortBy = "", //[FromQuery] bool isAscending = true, //[FromQuery] Dictionary filters = null) //{ // var pagingParams = new PagingParams // { // PageNumber = pageNumber, // PageSize = pageSize, // SortBy = sortBy, // IsAscending = isAscending, // Filters = filters // }; // // 可以在这里构建表达式树过滤条件 // Expression> filter = null; // var pagedResult = await _repository.GetPagedAsync(filter, pagingParams); // return Ok(pagedResult); //} /// /// 分页New /// /// /// [HttpPost] public async Task>> GetDataPaged(RequestInputBase input) { var pagingParams = new PagingParams { PageNumber = input.pageNumber, PageSize = input.pageSize, SortBy = input.sortBy, IsAscending = input.isAscending, }; var json = JsonSerializer.Serialize(input); // 可以在这里构建表达式树过滤条件 Expression> filter = null; var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); return Ok(pagedResult); } public async Task> GetTaskDataPaged(RequestInputBase input) { var pagingParams = new PagingParams { PageNumber = input.pageNumber, PageSize = input.pageSize, SortBy = input.sortBy, IsAscending = input.isAscending, }; var json = JsonSerializer.Serialize(input); // 可以在这里构建表达式树过滤条件 Expression> filter = null; var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); return pagedResult; } /// /// 导出New /// /// /// [HttpPost] public async Task ExportData(RequestInputBase input) { var pagingParams = new PagingParams { PageNumber = input.pageNumber, PageSize = input.pageSize, SortBy = input.sortBy, IsAscending = input.isAscending, }; // 可以在这里构建表达式树过滤条件 //Expression> filter = null; var pagedResult = await _repository.GetDataPagedAsync(null, pagingParams, input.Condition); return await ExportFile(pagedResult.Data, Guid.NewGuid().ToString() + ".xlsx"); } // [HttpGet] // public async Task Export([FromQuery] int pageNumber = 1, //[FromQuery] int pageSize = 10, //[FromQuery] string sortBy = "", //[FromQuery] bool isAscending = true, //[FromQuery] Dictionary filters = null) // { // var pagingParams = new PagingParams // { // PageNumber = pageNumber, // PageSize = pageSize, // SortBy = sortBy, // IsAscending = isAscending, // Filters = filters // }; // // 可以在这里构建表达式树过滤条件 // //Expression> filter = null; // var pagedResult = await _repository.GetPagedAsync(null, pagingParams); // return await ExportFile(pagedResult.Data, Guid.NewGuid().ToString() + ".xlsx"); // } protected async Task ExportFile(ICollection dtos, string fileName) { var excelExporter = HttpContext.RequestServices.GetRequiredService(); var res = await excelExporter.ExportAsByteArray(dtos); return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "_" + fileName }; } [HttpGet] public async Task GetImportTemplate() { try { // 创建导入模板生成器 var importer = new ExcelImporter(); // 生成导入模板流(这里假设使用 YourModel 作为导入模型) var bytes = await importer.GenerateTemplateBytes(); //using var stream = new MemoryStream(bytes); //stream.Seek(0, SeekOrigin.Begin); // 设置友好的文件名,例如:"导入模板_20250530.xlsx" var fileName = $"导入模板_{DateTime.Now:yyyyMMdd}.xlsx"; // 返回文件流结果 return new FileStreamResult(new MemoryStream(bytes), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "_" + fileName }; //return File( // fileStream: stream, // contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // fileDownloadName: fileName); } catch (Exception ex) { // 记录异常日志 Console.WriteLine($"生成导入模板时出错: {ex.Message}"); // 返回错误响应 return StatusCode(500, "生成导入模板时发生错误"); } } [HttpPost("Import")] public async virtual Task Import(IFormFile file) { if (file == null || file.Length <= 0) { return NotFound("No file uploaded."); } try { var excelImporter = HttpContext.RequestServices.GetRequiredService(); var importResult = await excelImporter.Import(file.OpenReadStream()); if (importResult.HasError) { StringBuilder sb = new StringBuilder(); foreach (var rowErr in importResult.RowErrors) { string temp = string.Join(";", rowErr.FieldErrors.Select(itm => $"第{rowErr.RowIndex}行:{itm.Key}-{itm.Value}")); sb.AppendLine(temp); } foreach (var templateErr in importResult.TemplateErrors) { string temp = $"列名:{templateErr.RequireColumnName},错误信息:{templateErr.Message}"; sb.AppendLine(temp); } throw new Exception(sb.ToString()); } // 处理导入的数据 List list = importResult.Data.ToList(); await ImportBefore(list); // 校验数据长度 var validationErrors = ValidationHelper.ValidateDataLength(list, _jobDbContext); if (validationErrors.Any()) { throw new Exception("数据校验失败:" + string.Join(", ", validationErrors)); } foreach (var item in list) { item.ReadState = true; item.CreationTime = CommonHelper.CurrentTime; } await _jobDbContext.BulkInsertAsync(list); await ImportAfter(list); return new JsonResult(new { Code = 200, Message = "修改成功!" }); } catch (Exception ex) { //await _logger.AddError(ex.Message, TaskName); return new JsonResult(new { Code = 400, Message = "导入失败:" + ex.Message }); } } /// /// 重写插入前进行操作,如校验等 /// /// /// protected virtual async Task ImportBefore(List p_list) { } /// /// 重写插入后进行操作如 /// /// /// protected virtual async Task ImportAfter(List p_list) { } public class DecimalTrimConverter : JsonConverter { public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.GetDecimal(); } public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) { // 关键步骤:使用 TrimTrailingZeros() 去掉末尾的 0 writer.WriteStringValue(value.ToString("0.########################", CultureInfo.InvariantCulture)); } } /// /// 高级查询字段 /// /// [HttpGet("fields")] public IActionResult GetQueryFields() { // 获取实体类的所有属性 Type entityType = typeof(T); var properties = entityType.GetProperties(); // 构建字段信息列表 var fields = new List(); foreach (var property in properties) { // 获取ExporterHeader特性中的DisplayName var exporterHeader = property.GetCustomAttribute(); string displayName = exporterHeader?.DisplayName ?? property.Name; // 获取属性类型 string dataType = property.PropertyType.Name; // 添加到字段列表 fields.Add(new QueryFieldInfo { FieldName = property.Name, DisplayName = displayName, DataType = dataType }); } return Ok(fields); } } } //using Azure.Core; //using Dapper; //using Hangfire; //using Magicodes.ExporterAndImporter.Core; //using Magicodes.ExporterAndImporter.Core.Extension; //using Magicodes.ExporterAndImporter.Excel; //using Microsoft.AspNetCore.Http; //using Microsoft.AspNetCore.Http.HttpResults; //using Microsoft.AspNetCore.Mvc; //using Microsoft.EntityFrameworkCore; //using Microsoft.EntityFrameworkCore.Storage; //using Microsoft.Extensions.DependencyInjection; //using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; //using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; //using Omu.ValueInjecter; //using SkiaSharp; //using System; //using System.Collections.Generic; //using System.Data; //using System.Drawing.Printing; //using System.Globalization; //using System.Linq; //using System.Linq.Expressions; //using System.Reflection; //using System.Security.Policy; //using System.Text; //using System.Text.Encodings.Web; //using System.Text.Json; //using System.Text.Json.Serialization; //using System.Text.Unicode; //using TaskManager.Contracts.Dtos; //using TaskManager.Entity; //using TaskManager.EntityFramework; //using TaskManager.EntityFramework.Repository; //using Wood.Service; //using Wood.Util; //using Wood.Util.Filters; //using static Dapper.SqlMapper; //namespace TaskManager.Controllers //{ // /// // /// 奇瑞循环任务输入页面扩展控制器 // /// // /// 实体类型 // /// 数据传输对象类型 // /// 日志实体类型 // public class CheryRecurringJobInputPageExtendController : RecurringJobBaseController // where T : CherryWriteBaseEnity, new() // where TDTO : class, new() // where TLOGS : CherryWriteLogsBaseEnity, new() // { // protected readonly IRepository _repository; // protected readonly JobDbContext _jobDbContext; // public CheryRecurringJobInputPageExtendController( // HttpClient httpClient, // JobDbContext jobDbContext, // LogController log, // IRepository repository) // : base(httpClient, jobDbContext, log) // { // _repository = repository; // _jobDbContext = jobDbContext; // } // #region 任务同步相关方法 // /// // /// 手工发送调用接口 // /// // /// 任务名称 // /// 客户(Chery) // /// 任务ID // /// // [HttpGet] // public virtual async Task CustomInvokeAsync(string taskName, string client, Guid taskId) // { // try // { // var taskConfig = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == taskName && p.Client == client); // if (taskConfig == null) // { // await _logger.AddError("任务配置不存在,任务设置表(TaskConfigure)是否存在任务对应的表!", taskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); // return; // } // InitializeTaskSettings(taskConfig); // var total = GetUnprocessedRecordCount(taskConfig.TableName); // UpdateTaskSubDataCount(taskId, total); // var failedCount = await CustomSyncTaskSubTable(taskName, taskId, total, taskConfig.TableName, client); // UpdateTaskSubStatus(taskId, failedCount); // } // catch (Exception ex) // { // await _logger.AddError(ex.Message, taskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); // } // } // /// // /// 同步任务子表数据 // /// // /// 任务名称 // /// 客户 // [NonAction] // public async Task SyncTaskSubTable(string taskName, string client) // { // var taskConfig = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == taskName); // if (taskConfig == null) // { // await _logger.AddError("任务配置不存在,任务设置表(TaskConfigure)是否存在任务对应的表!", taskName, Guid.NewGuid(), DateTime.Now.ToString("yyyyMMdd")); // return; // } // InitializeTaskSettings(taskConfig); // await SyncTaskSubTableInternal(taskName, client); // } // /// // /// 同步任务子表数据内部实现 // /// // private async Task SyncTaskSubTableInternal(string taskName, string client) // { // var taskConfig = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == taskName); // if (taskConfig == null) return; // var total = GetUnprocessedRecordCount(taskConfig.TableName); // await CustomSyncTaskSubTable(taskName, Guid.NewGuid(), total, taskConfig.TableName, client); // } // /// // /// 自定义同步任务子表数据 // /// // private async Task CustomSyncTaskSubTable( // string taskName, // Guid taskId, // int total, // string tableName, // string client, // List errorList = null) // { // int errorRecordCount = 0; // var version = DateTime.Now.ToString("yyyyMMdd"); // var requestDate = DateTime.Now.ToString("yyyy-MM-dd"); // var pageSize = CPageSize; // int totalPages = (int)Math.Ceiling((double)total / pageSize); // for (int i = 1; i <= totalPages; i++) // { // var records = GetPageRecords(tableName, pageSize, i); // if (!records.Any()) break; // var pagedRequest = CreatePagedRequest(records, i, pageSize); // MarkRecordsAsProcessing(records, taskId, requestDate); // var result = await PostPageAsync(pagedRequest, taskId, version); // if (result?.code == 200) // { // await ProcessSuccessfulResponse(records, taskId, requestDate, version); // } // else // { // errorRecordCount += records.Count(); // await ProcessFailedResponse(taskName, taskId, version, result, records, errorList); // // 可选:是否继续处理后续页 // // break; // } // await Task.Delay(200); // } // return errorRecordCount; // } // #endregion // #region API请求处理 // /// // /// 发送API请求并获取页面数据 // /// // private async Task PostPageAsync(PagedRequest pagedRequest, Guid taskId, string version) // { // try // { // var inputJson = SerializePagedRequest(pagedRequest, TaskName); // var content = await Post(Url, Path, inputJson, taskId, version); // if (string.IsNullOrEmpty(content)) // { // await _logger.AddError($"调用接口无返回值{Url}", TaskName, taskId, version); // return null; // } // var options = new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = { // new JsonStringEnumConverter(), // new OutCustomDateTimeConverter("yyyy-MM-dd HH:mm:ss") // } // }; // return JsonSerializer.Deserialize(content, options); // } // catch (Exception ex) // { // await _logger.AddError($"调用接口发生错误{ex.Message}", TaskName, taskId, version); // return null; // } // } // /// // /// 序列化分页请求对象 // /// // private string SerializePagedRequest(PagedRequest pagedRequest, string taskName) // { // if (taskName == "日物料需求计划风险确认") // { // return JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // new InputCustomDateTimeConverter(), // new InputCustomNullableDateTimeConverter() // }, // WriteIndented = false, // Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) // }); // } // else if (taskName.Contains("供应商共享库存")) // { // return JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = // { // new DecimalTrimConverter(), // new InputCustomDateTimeConverter(), // new InputCustomNullableDateTimeConverter() // }, // WriteIndented = false, // Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping // }); // } // else // { // return JsonSerializer.Serialize(pagedRequest, new JsonSerializerOptions // { // PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // Converters = { new DecimalTrimConverter() }, // WriteIndented = false, // Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) // }); // } // } // #endregion // #region 数据处理辅助方法 // /// // /// 初始化任务设置 // /// // private void InitializeTaskSettings(TaskConifgure taskConfig) // { // Url = taskConfig.Url; // Path = taskConfig.Api; // TaskName = taskConfig.TaskName; // Client = taskConfig.Client; // CPageSize = taskConfig.PageSize; // } // /// // /// 获取未处理记录数 // /// // private int GetUnprocessedRecordCount(string tableName) // { // string sql = $"select count(1) count1 from {tableName} where writeState=0 and readState=1"; // return _jobDbContext.Database.GetDbConnection().Query(sql).FirstOrDefault(); // } // /// // /// 更新任务子表数据计数 // /// // private void UpdateTaskSubDataCount(Guid taskId, int total) // { // var task = _jobDbContext.TaskSub.FirstOrDefault(p => p.TaskId == taskId); // if (task != null) // { // task.DataCount = total; // _jobDbContext.Update(task); // _jobDbContext.SaveChangesAsync(); // } // } // /// // /// 更新任务子表状态 // /// // private void UpdateTaskSubStatus(Guid taskId, int failedCount) // { // var taskSub = _jobDbContext.TaskSub.FirstOrDefault(p => p.TaskId == taskId); // if (taskSub != null) // { // taskSub.FailedCount = failedCount; // taskSub.WriteState = failedCount == 0; // _jobDbContext.Update(taskSub); // _jobDbContext.SaveChangesAsync(); // } // } // /// // /// 获取分页记录 // /// // private IEnumerable GetPageRecords(string tableName, int pageSize, int pageNumber) // { // string sql = $"SELECT TOP {pageSize} * FROM {tableName} WHERE writeState=0 AND readstate=1 ORDER BY uid"; // // 注意:实际应该使用分页SQL,这里简化处理 // return _jobDbContext.Database.GetDbConnection().Query(sql); // } // /// // /// 创建分页请求对象 // /// // private PagedRequest CreatePagedRequest(IEnumerable records, int pageNumber, int pageSize) // { // var dtos = records.Select(item => // { // TDTO dto = new TDTO(); // dto.InjectFrom(item); // return dto; // }).ToList(); // return new PagedRequest // { // batchNo = GenerateRandomStringWith8EG(), // total = pageSize, // pageSize = pageSize, // list = dtos, // pageNum = pageNumber // }; // } // /// // /// 标记记录为处理中 // /// // private void MarkRecordsAsProcessing(IEnumerable records, Guid taskId, string requestDate) // { // foreach (var item in records) // { // item.WriteState = true; // item.TaskId = taskId; // item.RequestDate = requestDate; // } // } // /// // /// 处理成功响应 // /// // private async Task ProcessSuccessfulResponse(IEnumerable records, Guid taskId, string requestDate, string version) // { // using (var transaction = await _jobDbContext.Database.BeginTransactionAsync()) // { // try // { // await _jobDbContext.BulkUpdateAsync(records, options => { options.UseTableLock = false; }); // var logs = records.Select(item => // { // TLOGS log = new TLOGS(); // log.InjectFrom(item); // log.RequestDate = requestDate; // log.TaskId = taskId; // log.WriteState = true; // log.ReadState = true; // return log; // }).ToList(); // await _jobDbContext.BulkInsertAsync(logs); // if (!_jobDbContext.TaskSub.Any(p => p.TaskId == taskId)) // { // var taskSub = new TaskSub // { // TaskId = taskId, // TaskName = TaskName, // Subscriber = Client, // TableName = _jobDbContext.TaskConifgure.FirstOrDefault(p => p.TaskName == TaskName)?.TableName, // DataCount = records.Count(), // Domain = "1", // Site = "1", // FailedCount = 0, // CreateTime = DateTime.Now, // CreateUser = "admin", // CreationTime = DateTime.Now, // SyncedPageCount = 1, // ReadState = true, // WriteState = true // }; // await _jobDbContext.AddAsync(taskSub); // } // await transaction.CommitAsync(); // await _logger.AddSuccess($"成功同步数据第 {1} 页数据", TaskName, taskId, version); // } // catch (Exception ex) // { // var inputJson = SerializePagedRequest(CreatePagedRequest(records, 1, records.Count()), TaskName); // await _logger.AddError(ex.Message, TaskName, taskId, version, inputJson); // await transaction.RollbackAsync(); // } // } // } // /// // /// 处理失败响应 // /// // private async Task ProcessFailedResponse( // string taskName, // Guid taskId, // string version, // QRReturnInfo result, // IEnumerable records, // List errorList) // { // var inputJson = SerializePagedRequest(CreatePagedRequest(records, 1, records.Count()), taskName); // await _logger.AddError($"第 {1} 页数据保存失败,请检查数据:{result?.message ?? "未知错误"}。", taskName, taskId, version, inputJson); // if (errorList != null) // { // errorList.Add($"第 {1} 页数据保存失败,请检查数据:{result?.message ?? "未知错误"}。"); // } // } // #endregion // #region 数据查询与CRUD // /// // /// 获取日志数据分页 // /// // [HttpPost] // public async Task> GetLogDataPaged(RequestInputBase input) // { // var pagingParams = new PagingParams // { // PageNumber = input.pageNumber, // PageSize = input.pageSize, // SortBy = input.sortBy, // IsAscending = input.isAscending, // }; // Expression> filter = null; // var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); // return pagedResult; // } // [HttpGet] // public async Task>> GetAll() // { // return await _repository.GetAllAsync() as List; // } // [HttpGet("{id}")] // public async Task> GetById(int id) // { // var entity = await _repository.GetByIdAsync(id); // if (entity == null) return NotFound(); // return entity; // } // [HttpPost] // public async Task> Create(T entity) // { // entity.CreationTime = DateTime.Now; // var createdEntity = await _repository.AddAsync(entity); // return new JsonResult(new { Code = 200, Message = "创建成功!" }); // } // [HttpPut("{id}")] // public async Task Update(T entity) // { // if (entity.UId == 0) // { // throw new Exception("更新时,实体主键UId不能为空或0"); // } // var target = await _repository.GetByIdAsync(entity.UId); // if (target == null) // { // throw new Exception($"CheryRecurringJobInputPageController.Update报错:根据UId{entity.UId}没有找到记录"); // } // EntityMapper.Trans(entity, target, "UId"); // await _repository.UpdateAsync(target); // return new JsonResult(new { Code = 200, Message = "修改成功!" }); // } // [HttpDelete("{id}")] // public async Task Delete(int id) // { // await _repository.DeleteAsync(id); // return new JsonResult(new { Code = 200, Message = "删除成功!" }); // } // [HttpPost] // public async Task>> GetDataPaged(RequestInputBase input) // { // var pagingParams = new PagingParams // { // PageNumber = input.pageNumber, // PageSize = input.pageSize, // SortBy = input.sortBy, // IsAscending = input.isAscending, // }; // Expression> filter = null; // var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); // return Ok(pagedResult); // } // public async Task> GetTaskDataPaged(RequestInputBase input) // { // var pagingParams = new PagingParams // { // PageNumber = input.pageNumber, // PageSize = input.pageSize, // SortBy = input.sortBy, // IsAscending = input.isAscending, // }; // Expression> filter = null; // var pagedResult = await _repository.GetDataPagedAsync(filter, pagingParams, input.Condition); // return pagedResult; // } // #endregion // #region 导入导出功能 // [HttpPost] // public async Task ExportData(RequestInputBase input) // { // var pagingParams = new PagingParams // { // PageNumber = input.pageNumber, // PageSize = input.pageSize, // SortBy = input.sortBy, // IsAscending = input.isAscending, // }; // var pagedResult = await _repository.GetDataPagedAsync(null, pagingParams, input.Condition); // return await ExportFile(pagedResult.Data, Guid.NewGuid().ToString() + ".xlsx"); // } // protected async Task ExportFile(ICollection dtos, string fileName) // { // var excelExporter = HttpContext.RequestServices.GetRequiredService(); // var res = await excelExporter.ExportAsByteArray(dtos); // return new FileStreamResult(new MemoryStream(res), "application/octet-stream") // { // FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "_" + fileName // }; // } // [HttpGet] // public async Task GetImportTemplate() // { // try // { // var importer = new ExcelImporter(); // var bytes = await importer.GenerateTemplateBytes(); // var fileName = $"导入模板_{DateTime.Now:yyyyMMdd}.xlsx"; // return new FileStreamResult(new MemoryStream(bytes), "application/octet-stream") // { // FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "_" + fileName // }; // } // catch (Exception ex) // { // Console.WriteLine($"生成导入模板时出错: {ex.Message}"); // return StatusCode(500, "生成导入模板时发生错误"); // } // } // [HttpPost("Import")] // public async virtual Task Import(IFormFile file) // { // if (file == null || file.Length <= 0) // { // return NotFound("No file uploaded."); // } // try // { // var excelImporter = HttpContext.RequestServices.GetRequiredService(); // var importResult = await excelImporter.Import(file.OpenReadStream()); // if (importResult.HasError) // { // StringBuilder sb = new StringBuilder(); // foreach (var rowErr in importResult.RowErrors) // { // string temp = string.Join(";", rowErr.FieldErrors.Select(itm => $"第{rowErr.RowIndex}行:{itm.Key}-{itm.Value}")); // sb.AppendLine(temp); // } // foreach (var templateErr in importResult.TemplateErrors) // { // string temp = $"列名:{templateErr.RequireColumnName},错误信息:{templateErr.Message}"; // sb.AppendLine(temp); // } // throw new Exception(sb.ToString()); // } // List list = importResult.Data.ToList(); // await ImportBefore(list); // var validationErrors = ValidationHelper.ValidateDataLength(list, _jobDbContext); // if (validationErrors.Any()) // { // throw new Exception("数据校验失败:" + string.Join(", ", validationErrors)); // } // foreach (var item in list) // { // item.ReadState = true; // item.CreationTime = CommonHelper.CurrentTime; // } // await _jobDbContext.BulkInsertAsync(list); // await ImportAfter(list); // return new JsonResult(new { Code = 200, Message = "修改成功!" }); // } // catch (Exception ex) // { // return new JsonResult(new { Code = 400, Message = "导入失败:" + ex.Message }); // } // } // /// // /// 重写插入前进行操作,如校验等 // /// // protected virtual async Task ImportBefore(List p_list) { } // /// // /// 重写插入后进行操作 // /// // protected virtual async Task ImportAfter(List p_list) { } // #endregion // #region 辅助方法 // public static string GenerateRandomStringWith8EG() // { // const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // var random = new Random(); // var sb = new StringBuilder(32); // int position = random.Next(0, 30); // for (int i = 0; i < position; i++) // { // sb.Append(chars[random.Next(chars.Length)]); // } // sb.Append("8EG"); // int remainingLength = 32 - sb.Length; // for (int i = 0; i < remainingLength; i++) // { // sb.Append(chars[random.Next(chars.Length)]); // } // return sb.ToString(); // } // [HttpGet("fields")] // public IActionResult GetQueryFields() // { // Type entityType = typeof(T); // var properties = entityType.GetProperties(); // var fields = new List(); // foreach (var property in properties) // { // var exporterHeader = property.GetCustomAttribute(); // string displayName = exporterHeader?.DisplayName ?? property.Name; // string dataType = property.PropertyType.Name; // fields.Add(new QueryFieldInfo // { // FieldName = property.Name, // DisplayName = displayName, // DataType = dataType // }); // } // return Ok(fields); // } // #endregion // #region 转换器 // public class DecimalTrimConverter : JsonConverter // { // public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) // { // return reader.GetDecimal(); // } // public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) // { // writer.WriteStringValue(value.ToString("0.########################", CultureInfo.InvariantCulture)); // } // } // #endregion // } //}