Browse Source

新增 世运会费用表 实体类(Grp_GamesBudgetMaster)及excel导入

Lyyyi 1 week ago
parent
commit
eb81dc602a

+ 2 - 1
OASystem/EntitySync/Program.cs

@@ -172,6 +172,7 @@ db.CodeFirst.SetStringDefaultLength(50).BackupTable().InitTables(new Type[]
     //typeof(Sys_AuditTemplate),//审核模板表 
     //typeof(Sys_AuditTemplateNode),//审核模板节点表 
     //typeof(Sys_AuditTemplateNodeUser),//审核模板节点人员表 
-    typeof(Fin_ApplicationLinkGoods),//日服申请单物品关联表 
+    //typeof(Fin_ApplicationLinkGoods),//日服申请单物品关联表 
+    typeof(Grp_GamesBudgetMaster‌),//世运会成本预算明细 
 }); 
 Console.WriteLine("数据库结构同步完成!");

+ 129 - 0
OASystem/OASystem.Api/Controllers/SystemController.cs

@@ -3531,6 +3531,135 @@ And u.UId = {0} And u.FId = 1 ", dto.UserId);
             }
             return Ok(JsonView(false, "excel导入失败!"));
         }
+
+        /// <summary>
+        /// excel导入 世运会成本预算明细Excel
+        /// </summary>
+        /// <param name="file"></param>
+        /// <param name="currUserId">录入人userId</param>
+        /// <returns></returns>
+        [HttpPost]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> ExcelImportGamesBudgetDataSouce(IFormFile file, [FromQuery] int currUserId = 208)
+        {
+            // 检查文件是否为空
+            if (file == null || file.Length == 0)
+            {
+                return Ok(JsonView(false, "请选择文件!"));
+            }
+
+            // 文件签名验证
+            var perExtensions = new[] { ".xls", ".xlsx" };
+            Dictionary<string, List<byte[]>> fileSignature = CommonFun.FileSignature;
+            fileSignature = fileSignature.Where(pair => perExtensions.Contains(pair.Key)).ToDictionary(pair => pair.Key, pair => pair.Value);
+
+            // 文件扩展名验证
+            var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
+            if (string.IsNullOrEmpty(ext) || !fileSignature.ContainsKey(ext))
+            {
+                return Ok(JsonView(false, "不支持的文件类型!"));
+            }
+
+            using (var memoryStream = new MemoryStream())
+            {
+                await file.CopyToAsync(memoryStream);
+
+                // 检查文件签名
+                var fileData = memoryStream.ToArray();
+                var signatures = fileSignature[ext];
+                bool signatureValid = signatures.Any(signature =>
+                    fileData.Take(signature.Length).SequenceEqual(signature));
+
+                if (!signatureValid)
+                {
+                    return Ok(JsonView(false, "文件内容与类型不匹配!"));
+                }
+            }
+
+            // 保存文件到服务器
+            var uploadsFolder = @$"D:\FTP\File\OA2023\Office\Excel\CarDataSouceImportFile";
+            if (!Directory.Exists(uploadsFolder))
+            {
+                Directory.CreateDirectory(uploadsFolder);
+            }
+
+            var fileName = CommonFun.ValidFileName(file.Name);
+
+            var filePath = Path.Combine(uploadsFolder, fileName);
+            using (var stream = new FileStream(filePath, FileMode.Create))
+            {
+                await file.CopyToAsync(stream);
+            }
+
+            Workbook workbook = new Workbook(filePath);
+
+            // 获取第一个工作表
+            Worksheet worksheet = workbook.Worksheets[0];
+
+            // 获取表头(第一行作为列名)
+            int headerRowIndex = 0;
+            Row headerRow = worksheet.Cells.Rows[headerRowIndex];
+            int colCount = worksheet.Cells.MaxDataColumn + 1;
+
+            // 动态存储列名
+            var datas = new List<Grp_GamesBudgetMaster>();
+
+            // 遍历数据行(从第3行开始)
+            int rowCount = worksheet.Cells.MaxDataRow + 1;
+            var msgs = new StringBuilder();
+            for (int row = headerRowIndex + 2; row < rowCount; row++)
+            {
+                var cellVal0 = worksheet.Cells[row, 0].Value;    //直属父级
+                var cellVal1 = worksheet.Cells[row, 1].Value;    //工作项目
+                var cellVal2 = worksheet.Cells[row, 2].Value;    //测算内容
+                var cellVal3 = worksheet.Cells[row, 3].Value;    //数量
+                var cellVal4 = worksheet.Cells[row, 4].Value;    //单位
+                var cellVal5 = worksheet.Cells[row, 5].Value;    //单价(元)
+                var cellVal6 = worksheet.Cells[row, 6].Value;    //周期-时间
+                var cellVal7 = worksheet.Cells[row, 7].Value;    //周期-单位
+                var cellVal8 = worksheet.Cells[row, 8].Value;    //项费用合计
+                var cellVal9 = worksheet.Cells[row, 9].Value;    //说明
+                var cellVal10 = worksheet.Cells[row, 10].Value;    //备注
+
+                var dtTimeNoew = DateTime.Now;
+
+                decimal.TryParse(cellVal3?.ToString(), out decimal quantity);
+                decimal.TryParse(cellVal5?.ToString(), out decimal unitPrice);
+                decimal.TryParse(cellVal8?.ToString(), out decimal itemTotal);
+                int.TryParse(cellVal6?.ToString(), out int cycleTime);
+
+                var rowData = new Grp_GamesBudgetMaster()
+                {
+                    T0 = cellVal0?.ToString() ?? "",
+                    ProjectWork = cellVal1?.ToString() ?? "",
+                    CalculationContent = cellVal2?.ToString() ?? "",
+                    Quantity = quantity,
+                    Unit = cellVal4?.ToString() ?? "",
+                    UnitPrice = unitPrice,
+                    CycleTime = cycleTime,
+                    CycleUnit = cellVal7?.ToString() ?? "",
+                    ItemTotal = itemTotal,
+                    Specification = cellVal9?.ToString() ?? "",
+                    LastUpdateTime = dtTimeNoew.ToString("yyyy-MM-dd HH:mm:ss"),
+                    LastUpdateUserId = currUserId,
+                    CreateTime = dtTimeNoew,
+                    CreateUserId = currUserId,
+                    Remark = cellVal10?.ToString() ?? ""
+                };
+
+                datas.Add(rowData);
+            }
+
+            if (datas.Any())
+            {
+                var insert = await _sqlSugar.Insertable(datas).ExecuteCommandAsync();
+                if (insert > 0)
+                {
+                    return Ok(JsonView(true, $"导入成功!count:{insert} warningMsg:{msgs.ToString()}"));
+                }
+            }
+            return Ok(JsonView(false, "excel导入失败!"));
+        }
         #endregion
 
     }

+ 69 - 37
OASystem/OASystem.Api/Middlewares/ExceptionHandlingMiddleware.cs

@@ -1,4 +1,6 @@
 
+using Microsoft.Data.SqlClient;
+
 namespace OASystem.API.Middlewares
 {
     /// <summary>
@@ -8,22 +10,26 @@ namespace OASystem.API.Middlewares
     {
         private readonly RequestDelegate _next;  // 用来处理上下文请求
         private readonly ILogger<ExceptionHandlingMiddleware> _logger;
+        private readonly SqlSugarClient _db;
 
         /// <summary>
         /// 初始化
         /// </summary>
         /// <param name="next"></param>
         /// <param name="logger"></param>
-        public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
+        /// <param name="db"></param>
+        public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger, SqlSugarClient db)
         {
             _next = next;
             _logger = logger;
+            _db = db;
         }
 
         /// <summary>
         /// 执行中间件
         /// </summary>
         /// <param name="httpContext"></param>
+        /// <param name="db"></param>
         /// <returns></returns>
         public async Task InvokeAsync(HttpContext httpContext, SqlSugarClient db)
         {
@@ -38,57 +44,83 @@ namespace OASystem.API.Middlewares
         }
 
         /// <summary>
-        /// 异步处理异常
+        /// 自定义全局异常处理方法
         /// </summary>
         /// <param name="context"></param>
         /// <param name="exception"></param>
+        /// <param name="db"></param>
         /// <returns></returns>
         private async Task HandleExceptionAsync(HttpContext context, Exception exception, SqlSugarClient db)
         {
             if (db.Ado != null && db.Ado.Transaction != null)
             {
-                db.Ado.RollbackTran();
+                try
+                {
+                    db.Ado.RollbackTran();
+                }
+                catch (Exception ex)
+                {
+                    _logger.LogError("Error rolling back transaction: {ErrorMessage}", ex.Message);
+                }
             }
 
-            context.Response.ContentType = "application/json";  // 返回json 类型
-            var response = context.Response;
-            var errorResponse = new JsonView
-            {
-                Code = StatusCodes.Status500InternalServerError,
-                Data = ""
-            };  
-            
-            // 自定义的异常错误信息类型
-            switch (exception)
+            // 检查响应是否已开始
+            if (!context.Response.HasStarted)
             {
-                case ApplicationException ex:
-                    if (ex.Message.Contains("Invalid token"))
-                    {
+                context.Response.ContentType = "application/json"; // 设置响应内容类型为 JSON
+                var response = context.Response;
+                var errorResponse = new JsonView
+                {
+                    Code = StatusCodes.Status500InternalServerError,
+                    Data = ""
+                };
+
+                // 根据异常类型设置不同的响应状态码和消息
+                switch (exception)
+                {
+                    case SqlException sqlEx when sqlEx.Number == -2:
+                        response.StatusCode = StatusCodes.Status503ServiceUnavailable;
+                        errorResponse.Msg = "数据库连接超时,请稍后重试。";
+                        break;
+                    case SqlException sqlEx when sqlEx.Number == -4:
+                        response.StatusCode = StatusCodes.Status503ServiceUnavailable;
+                        errorResponse.Msg = "数据库连接池耗尽,请稍后重试。";
+                        break;
+                    case ApplicationException ex when ex.Message.Contains("Invalid token"):
                         response.StatusCode = StatusCodes.Status403Forbidden;
                         errorResponse.Msg = ex.Message;
                         break;
-                    }
-                    response.StatusCode = StatusCodes.Status400BadRequest;
-                    errorResponse.Msg = ex.Message;
-                    break;
-                case KeyNotFoundException ex:
-                    response.StatusCode = StatusCodes.Status404NotFound;
-                    errorResponse.Msg = ex.Message;
-                    break;
-                case SqlSugarException ex:
-                    response.StatusCode = StatusCodes.Status204NoContent;
-                    if (ex.Message.Contains("timeout")) errorResponse.Msg = $"数据库连接超时,请稍后重试。";
-                    else errorResponse.Msg = ex.Message;
-                    break;
-                default:
-                    response.StatusCode = StatusCodes.Status500InternalServerError;
-                    errorResponse.Msg = exception.Message;
-                    break;
-            }
+                    case ApplicationException ex:
+                        response.StatusCode = StatusCodes.Status400BadRequest;
+                        errorResponse.Msg = ex.Message;
+                        break;
+                    case KeyNotFoundException ex:
+                        response.StatusCode = StatusCodes.Status404NotFound;
+                        errorResponse.Msg = ex.Message;
+                        break;
+                    case SqlSugarException ex:
+                        response.StatusCode = ex.Message.Contains("timeout")
+                            ? StatusCodes.Status503ServiceUnavailable
+                            : StatusCodes.Status500InternalServerError;
+                        errorResponse.Msg = ex.Message.Contains("timeout")
+                            ? "数据库连接超时,请稍后重试。"
+                            : ex.Message;
+                        break;
+                    default:
+                        response.StatusCode = StatusCodes.Status500InternalServerError;
+                        errorResponse.Msg = "服务器内部错误"; // 不直接暴露异常详细信息
+                        break;
+                }
 
-            _logger.LogError(exception.Message);
-            var result = JsonConvert.SerializeObject(errorResponse);
-            await context.Response.WriteAsync(result);
+                _logger.LogError(exception, "An exception occurred."); // 记录异常详细信息
+                var result = JsonConvert.SerializeObject(errorResponse);
+                await context.Response.WriteAsync(result); // 将错误响应写入客户端
+            }
+            else
+            {
+                // 如果响应已开始,记录日志但不做进一步处理
+                _logger.LogError(exception, "An exception occurred after response started.");
+            }
         }
     }
 }

+ 5 - 1
OASystem/OASystem.Api/Program.cs

@@ -437,6 +437,11 @@ builder.Services.TryAddSingleton(typeof(CommonService));
 
 var app = builder.Build();
 
+//自定义异常中间件
+app.UseMiddleware<ExceptionHandlingMiddleware>();
+
+
+
 //serilog日志 请求中间管道
 app.UseSerilogRequestLogging(options =>
 {
@@ -495,7 +500,6 @@ app.UseRouting();
 app.UseCors("Cors");  //Cors
 
 //app.UseMiddleware<FixedPromptMiddleware>();
-app.UseMiddleware<ExceptionHandlingMiddleware>();
 
 // 定义允许API的访问时间段
 //var startTime = DateTime.Parse(_config["ApiAccessTime:StartTime"]);

+ 80 - 0
OASystem/OASystem.Domain/Entities/Groups/Grp_GamesBudgetMaster‌.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OASystem.Domain.Entities.Groups
+{
+    /// <summary>
+    /// 世运会成本预算明细‌
+    /// </summary>
+    [SugarTable(tableName: "Grp_GamesBudgetMaster‌", tableDescription: "世运会成本预算明细")]
+    public class Grp_GamesBudgetMaster‌ : EntityBase
+    {
+        /// <summary>
+        /// 直属父级
+        /// </summary>
+        [SugarColumn(ColumnName = "T0", ColumnDescription = "直属父级", IsNullable = true, ColumnDataType = "varchar(200)")]
+        public string T0 { get; set; }
+
+        /// <summary>
+        /// 工作项目
+        /// </summary>
+        [SugarColumn(ColumnName = "ProjectWork", ColumnDescription = "工作项目", IsNullable = true, ColumnDataType = "varchar(200)")]
+        public string ProjectWork { get; set; }
+        /// <summary>
+        /// 测算内容
+        /// </summary>
+        [SugarColumn(ColumnName = "CalculationContent", ColumnDescription = "测算内容", IsNullable = true, ColumnDataType = "varchar(200)")]
+        public string CalculationContent { get; set; }
+        /// <summary>
+        /// 数量
+        /// </summary>
+        [SugarColumn(ColumnName = "Quantity", ColumnDescription = "数量", IsNullable = true, ColumnDataType = "decimal(10,2)")]
+        public decimal Quantity { get; set; }
+        /// <summary>
+        /// 单位
+        /// </summary>
+        [SugarColumn(ColumnName = "Unit", ColumnDescription = "测算内容", IsNullable = true, ColumnDataType = "varchar(50)")]
+        public string Unit { get; set; }
+        /// <summary>
+        /// 单价
+        /// </summary>
+        [SugarColumn(ColumnName = "UnitPrice", ColumnDescription = "单价", IsNullable = true, ColumnDataType = "decimal(10,2)")]
+        public decimal UnitPrice { get; set; }
+
+        /// <summary>
+        /// 周期-时间
+        /// </summary>
+        [SugarColumn(ColumnName = "CycleTime", ColumnDescription = "周期-单位", IsNullable = true, ColumnDataType = "int")]
+        public int CycleTime { get; set; }
+        /// <summary>
+        /// 周期-单位
+        /// </summary>
+        [SugarColumn(ColumnName = "CycleUnit", ColumnDescription = "周期-单位", IsNullable = true, ColumnDataType = "varchar(50)")]
+        public string CycleUnit { get; set; }
+
+        /// <summary>
+        /// 项总金额
+        /// </summary>
+        [SugarColumn(ColumnName = "ItemTotal", ColumnDescription = "项总金额", IsNullable = true, ColumnDataType = "decimal(10,2)")]
+        public decimal ItemTotal { get; set; }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        [SugarColumn(ColumnName = "Specification", ColumnDescription = "周期-单位", IsNullable = true, ColumnDataType = "varchar(500)")]
+        public string Specification { get; set; }
+        /// <summary>
+        /// 最后更新人
+        /// </summary>
+        [SugarColumn(ColumnName = "LastUpdateUserId", ColumnDescription = "最后更新人", IsNullable = true, ColumnDataType = "int")]
+        public int LastUpdateUserId { get; set; }
+        /// <summary>
+        /// 最后更新时间
+        /// </summary>
+        [SugarColumn(ColumnName = "LastUpdateTime", ColumnDescription = "最后更新时间", IsNullable = true, ColumnDataType = "varchar(30)")]
+        public string LastUpdateTime { get; set; }
+    }
+}