diff --git a/FrontendWebApi/ApiControllers/OperationLogController.cs b/FrontendWebApi/ApiControllers/OperationLogController.cs index 603ec78..d493ee5 100644 --- a/FrontendWebApi/ApiControllers/OperationLogController.cs +++ b/FrontendWebApi/ApiControllers/OperationLogController.cs @@ -24,6 +24,8 @@ using System.Threading.Tasks; using Image = System.Drawing.Image; using System.IdentityModel.Tokens.Jwt; using System.Net; +using NPOI.POIFS.Crypt.Dsig; +using System.Text; namespace FrontendWebApi.ApiControllers { @@ -32,230 +34,386 @@ namespace FrontendWebApi.ApiControllers public class OperationLogController : MyBaseApiController { private readonly IBackendRepository backendRepository; + private readonly IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository; private string operationFileSaveAsPath = ""; - public OperationLogController(IBackendRepository backendRepository) + public OperationLogController(IBackendRepository backendRepository, IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository) { this.backendRepository = backendRepository; operationFileSaveAsPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "upload", "operation"); + this.backgroundServiceMsSqlRepository = backgroundServiceMsSqlRepository; } - + /// + /// 巨蛋操作紀錄api 1:系統紀錄;2:登入紀錄;3:燈控排程紀錄 + /// + /// + /// [HttpPost] - [Route("api/OperationLog/GetList")] - public async Task>>> GetList([FromBody] PageResult pageResult) + [Route("api/OperationLog/GetLogList")] + public async Task>>> GetLogList([FromBody] PageResult pageResult) { - ApiResult> apiResult = new ApiResult>(jwt_str); - if (!jwtlife) - { - apiResult.Code = "5000"; - return BadRequest(apiResult); - } + ApiResult>> apiResult = new ApiResult>>(); + List logList = new List(); + int total = 0; + string start_time = DateTime.Parse(pageResult.data?.start_time).ToString("yyyy-MM-dd"); + string end_time = DateTime.Parse(pageResult.data?.end_time).ToString("yyyy-MM-dd"); ; + string mark = pageResult.isEnable ? ";" : "\n"; try { - string pageQuery = pageResult.isEnable ? " LIMIT @pageSize OFFSET @skip" : ""; - // 取得資料 - var logList = await backendRepository.GetAllAsync($@" - select ui.full_name as 'user_name' ,ol.* from operation_log ol - LEFT JOIN userinfo ui on ui.userinfo_guid COLLATE utf8mb4_unicode_ci = ol.user_guid - WHERE ol.operation_type = @operation_type AND ol.building_tag = @building_tag AND - ol.created_at >= @start_time AND ol.created_at <= @end_time - {pageQuery}", - new { - pageSize = pageResult.pageSize , - skip = (pageResult.currentPage - 1) * pageResult.pageSize, - operation_type = pageResult.data?.operation_type, - building_tag = pageResult.data?.building_tag, - start_time = pageResult.data?.start_time, - end_time = pageResult.data?.end_time, - }); + if (pageResult.data.type == 1 || pageResult.data.type == 2) + { + string building_tag = pageResult.data?.building_tag; + string tableName = (building_tag == "D2" || building_tag == "D3") ? "D2_Pri" : $"{building_tag}"; + string sWhere = pageResult.data.type == 1 ? "OPERATION ='Invoked'" : "(OPERATION = 'Login' or OPERATION = 'Logout (Timeout)')"; + string sWhere2 = pageResult.data.type == 1 ? ((building_tag == "D2" || building_tag == "D3") ? + "and (TARGET like '/Arena/D2%' or target like '/Arena/D3%')" : $"and TARGET like '/Arena/{building_tag}%'") : ""; + string pageQuery = pageResult.isEnable ? "" : @"ORDER BY [TIMESTAMP] DESC -- 必須提供 ORDER BY 子句 + OFFSET @skip ROWS + FETCH NEXT @pageSize ROWS ONLY;"; - // 設定呈現紀錄內容 - foreach (var log in logList) { - if (log.parameter == null) { - continue; - } - switch (log.operation_type) { - case 1: - var chaName = JsonConvert.DeserializeObject(log.parameter); - if (chaName == null) continue; - log.content = chaName.TagName + ":" + chaName.ChangeN; - break; - case 2: - var schedule = JsonConvert.DeserializeObject(log.parameter); - if (schedule == null) continue; - var contentArr = new List() { + string sql = $@"SELECT DISTINCT + [TIMESTAMP] created_at + ,[OPERATION] action_name + ,[TARGET] parameter + ,[SLOTNAME] + ,[OLDVALUE] + ,[VALUE] + ,[USERNAME] user_name + FROM [taipei_dome].[dbo].[ARENA_{tableName}_AUDITHISTORY] + WHERE {sWhere} + AND TIMESTAMP >= @start_time AND TIMESTAMP < DATEADD(day, 1, @end_time) + {sWhere2} + {pageQuery}"; + // 取得資料 + logList = await backgroundServiceMsSqlRepository.GetAllAsync(sql, + new + { + pageSize = pageResult.pageSize, + skip = (pageResult.currentPage - 1) * pageResult.pageSize, + operation_type = pageResult.data?.operation_type, + start_time = start_time, + end_time = end_time, + }); + sql = @$"SELECT COUNT(*) AS TotalCount + FROM ( + SELECT DISTINCT + [TIMESTAMP] created_at, + [OPERATION] action_name, + [TARGET] parameter, + [SLOTNAME], + [OLDVALUE], + [VALUE], + [USERNAME] user_name + FROM [taipei_dome].[dbo].[ARENA_{tableName}_AUDITHISTORY] + WHERE {sWhere} + AND TIMESTAMP >= @start_time AND TIMESTAMP < DATEADD(day, 1, @end_time) + {sWhere2} + ) AS subquery;"; + total = await backgroundServiceMsSqlRepository.GetOneAsync(sql, + new + { + start_time = start_time, + end_time = end_time, + }); + logList.ForEach(log => log.content = $"Target:{log.parameter}{mark}Value:{log.value}"); + } + else if (pageResult.data.type == 3) + { + string pageQuery = pageResult.isEnable ? "" : "LIMIT @pageSize OFFSET @skip"; + + var sql = $@"SELECT ui.full_name AS user_name, ol.* + FROM operation_log ol + LEFT JOIN userinfo ui ON ui.userinfo_guid COLLATE utf8mb4_unicode_ci = ol.user_guid + WHERE ol.operation_type = @operation_type + AND ol.building_tag = @building_tag + AND ol.created_at >= @start_time + AND ol.created_at <= @end_time + {pageQuery}"; + // 取得資料 + logList = await backendRepository.GetAllAsync(sql, + new + { + pageSize = pageResult.pageSize, + skip = (pageResult.currentPage - 1) * pageResult.pageSize, + operation_type = pageResult.data?.operation_type, + building_tag = pageResult.data?.building_tag, + start_time = start_time, + end_time = end_time, + }); + sql = $@"SELECT COUNT(*) AS total_count + FROM ( + SELECT ui.full_name AS user_name, ol.* + FROM operation_log ol + LEFT JOIN userinfo ui ON ui.userinfo_guid COLLATE utf8mb4_unicode_ci = ol.user_guid + WHERE ol.operation_type = @operation_type + AND ol.building_tag = @building_tag + AND ol.created_at >= @start_time + AND ol.created_at <= @end_time + ) AS subquery;"; + total = await backendRepository.GetOneAsync(sql, + new + { + operation_type = pageResult.data?.operation_type, + building_tag = pageResult.data?.building_tag, + start_time = start_time, + end_time = end_time, + }); + // 設定呈現紀錄內容 + foreach (var log in logList) + { + if (log.parameter == null) + { + continue; + } + switch (log.operation_type) + { + case 1: + var chaName = JsonConvert.DeserializeObject(log.parameter); + if (chaName == null) continue; + log.content = chaName.TagName + ":" + chaName.ChangeN; + break; + case 2: + var schedule = JsonConvert.DeserializeObject(log.parameter); + if (schedule == null) continue; + var contentArr = new List() { "編號:" + schedule.light_schedule_guid, "名稱:" + schedule.full_name, }; - if (log.action_name == "修改") { - contentArr.Add("修改內容:" + string.Join("、", schedule.changeNames)); - } - log.content = string.Join("\n",contentArr); - break; + if (log.action_name == "修改") + { + contentArr.Add("修改內容:" + string.Join("、", schedule.changeNames)); + } + log.content = string.Join(mark, contentArr); + break; + } } } + else + { + apiResult.Code = "5000"; + apiResult.Msg = "無效參數"; + return apiResult; + } + + + var result = new PageResult> + { + pageSize = pageResult.pageSize, + totalItem = total, + currentPage = pageResult.currentPage, + data = logList.OrderByDescending(log => log.created_at).ToList() + }; + apiResult.Code = "0000"; - apiResult.Data = logList; + apiResult.Data = result; } catch (Exception exception) { apiResult.Code = "9999"; + apiResult.Msg = "系統內部錯誤,請聯絡管理者。"; Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message); - return Ok(apiResult); + return apiResult; } - return Ok(apiResult); + return apiResult; } [HttpPost] [Route("api/OperationLog/ExportList")] - public async Task ExportList([FromBody] OperationLogExportInput input) + public async Task ExportList([FromBody] OperationLogExportInput input) { List result = new List(); - if (input.isNiagara) + //if (input.isNiagara) + //{ + // result = input.exportList; + //} + //else + //{ + // PageResult pageResult = input.listInput; + // pageResult.isEnable = false; + // result = ((ApiResult>)((OkObjectResult)(await this.GetList(pageResult)).Result).Value).Data.ToList(); + //} + input.listInput.isEnable = true; + result = GetLogList(input.listInput).Result.Data.data; + + var FileName = $"{input.exportOpeTypeName}_{DateTime.Now}.csv"; + // 生成CSV文件 + string Csv; + string formatted_created_at = null; + + if (result.Count > 0) { - result = input.exportList; + StringBuilder csv = new StringBuilder(); + + // 添加CSV標題行 + csv.AppendLine("操作人,動作,內容,紀錄時間"); + + // 添加數據行 + foreach (var item in result) + { + + if (item.created_at.HasValue) + { + formatted_created_at = item.created_at.Value.ToString("yyyy/MM/dd HH:mm:ss"); + } + + csv.AppendLine($"{item.user_name},{item.action_name},{item.content},{formatted_created_at}"); + } + Csv = csv.ToString(); + + using (var fileMemoryStream = new MemoryStream()) + { + using (var streamWriter = new StreamWriter(fileMemoryStream, Encoding.UTF8)) + { + streamWriter.Write(Csv); + } + return File(fileMemoryStream.ToArray(), "text/csv", FileName); + } } else { - PageResult pageResult = input.listInput; - pageResult.isEnable = false; - result = ((ApiResult>)((OkObjectResult)(await this.GetList(pageResult)).Result).Value).Data.ToList(); + var msg = new { Code = "0003", Msg = "無資料可匯出。" }; + return StatusCode(400, msg); } - var workbook = new XSSFWorkbook(); + #region excel寫法,但有行數上限為 1,048,576 + #region excel設定 - IFont font12 = workbook.CreateFont(); - font12.FontName = "新細明體"; - font12.FontHeightInPoints = 12; - ICellStyle style12 = workbook.CreateCellStyle(); - style12.SetFont(font12); - style12.Alignment = HorizontalAlignment.Center; - style12.VerticalAlignment = VerticalAlignment.Center; - IFont font12Times = workbook.CreateFont(); - font12Times.FontName = "Times New Roman"; - font12Times.FontHeightInPoints = 12; - IFont font18 = workbook.CreateFont(); - font18.FontName = "新細明體"; - font18.FontHeightInPoints = 18; - font18.IsBold = true; - ICellStyle styleTitle18 = workbook.CreateCellStyle(); - styleTitle18.SetFont(font18); - styleTitle18.Alignment = HorizontalAlignment.Center; - styleTitle18.VerticalAlignment = VerticalAlignment.Center; - ICellStyle styleLeft12 = workbook.CreateCellStyle(); - styleLeft12.SetFont(font12); - styleLeft12.Alignment = HorizontalAlignment.Left; - styleLeft12.VerticalAlignment = VerticalAlignment.Center; - ICellStyle styleLine12 = workbook.CreateCellStyle(); - styleLine12.SetFont(font12); - styleLine12.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center; - styleLine12.VerticalAlignment = VerticalAlignment.Center; - styleLine12.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; - styleLine12.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; - styleLine12.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; - styleLine12.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; - ICellStyle stylein12 = workbook.CreateCellStyle(); - stylein12.SetFont(font12Times); - stylein12.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left; - stylein12.VerticalAlignment = VerticalAlignment.Center; - stylein12.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; - stylein12.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; - stylein12.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; - stylein12.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; - stylein12.WrapText = true; + //var workbook = new XSSFWorkbook(); + //IFont font12 = workbook.CreateFont(); + //font12.FontName = "新細明體"; + //font12.FontHeightInPoints = 12; + //ICellStyle style12 = workbook.CreateCellStyle(); + //style12.SetFont(font12); + //style12.Alignment = HorizontalAlignment.Center; + //style12.VerticalAlignment = VerticalAlignment.Center; + //IFont font12Times = workbook.CreateFont(); + //font12Times.FontName = "Times New Roman"; + //font12Times.FontHeightInPoints = 12; + //IFont font18 = workbook.CreateFont(); + //font18.FontName = "新細明體"; + //font18.FontHeightInPoints = 18; + //font18.IsBold = true; + //ICellStyle styleTitle18 = workbook.CreateCellStyle(); + //styleTitle18.SetFont(font18); + //styleTitle18.Alignment = HorizontalAlignment.Center; + //styleTitle18.VerticalAlignment = VerticalAlignment.Center; + //ICellStyle styleLeft12 = workbook.CreateCellStyle(); + //styleLeft12.SetFont(font12); + //styleLeft12.Alignment = HorizontalAlignment.Left; + //styleLeft12.VerticalAlignment = VerticalAlignment.Center; + //ICellStyle styleLine12 = workbook.CreateCellStyle(); + //styleLine12.SetFont(font12); + //styleLine12.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center; + //styleLine12.VerticalAlignment = VerticalAlignment.Center; + //styleLine12.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; + //styleLine12.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; + //styleLine12.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; + //styleLine12.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; + //ICellStyle stylein12 = workbook.CreateCellStyle(); + //stylein12.SetFont(font12Times); + //stylein12.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left; + //stylein12.VerticalAlignment = VerticalAlignment.Center; + //stylein12.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; + //stylein12.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; + //stylein12.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; + //stylein12.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; + //stylein12.WrapText = true; #endregion - var sheet = workbook.CreateSheet(input.exportOpeTypeName); - int RowPosition = 0; - if (result.Count > 0) - { - #region set cell - int ri = 0; - IRow row = sheet.CreateRow(RowPosition); - if (!input.isNiagara) { - sheet.SetColumnWidth(ri++, 1 * 160 * 12); - } - sheet.SetColumnWidth(ri++, 2 * 160 * 12); - sheet.SetColumnWidth(ri++, 2 * 160 * 12); - sheet.SetColumnWidth(ri++, 8 * 160 * 12); - sheet.SetColumnWidth(ri++, 4 * 160 * 12); + //var sheet = workbook.CreateSheet(input.exportOpeTypeName); + //int RowPosition = 0; + //if (result.Count > 0) + //{ + // #region set cell + // int ri = 0; + // IRow row = sheet.CreateRow(RowPosition); + // //if (!input.isNiagara) + // //{ + // // sheet.SetColumnWidth(ri++, 1 * 160 * 12); + // //} + // sheet.SetColumnWidth(ri++, 2 * 160 * 12); + // sheet.SetColumnWidth(ri++, 2 * 160 * 12); + // sheet.SetColumnWidth(ri++, 8 * 160 * 12); + // sheet.SetColumnWidth(ri++, 4 * 160 * 12); - int i = 0; + // int i = 0; - ICell cell = row.CreateCell(i++); - if (!input.isNiagara) - { - cell.SetCellValue("編號"); - cell.CellStyle = styleLine12; - cell = row.CreateCell(i++); - } - cell.SetCellValue("操作人"); - cell.CellStyle = styleLine12; - cell = row.CreateCell(i++); - cell.SetCellValue("動作"); - cell.CellStyle = styleLine12; + // ICell cell = row.CreateCell(i++); + // //if (!input.isNiagara) + // //{ + // // cell.SetCellValue("編號"); + // // cell.CellStyle = styleLine12; + // // cell = row.CreateCell(i++); + // //} + // cell.SetCellValue("操作人"); + // cell.CellStyle = styleLine12; + // cell = row.CreateCell(i++); + // cell.SetCellValue("動作"); + // cell.CellStyle = styleLine12; - cell = row.CreateCell(i++); - cell.SetCellValue("內容"); - cell.CellStyle = styleLine12; - cell = row.CreateCell(i++); - cell.SetCellValue("紀錄時間"); - cell.CellStyle = styleLine12; - #endregion + // cell = row.CreateCell(i++); + // cell.SetCellValue("內容"); + // cell.CellStyle = styleLine12; + // cell = row.CreateCell(i++); + // cell.SetCellValue("紀錄時間"); + // cell.CellStyle = styleLine12; + // #endregion - foreach (var r in result) - { - RowPosition += 1; - int k = 3; - row = sheet.CreateRow(RowPosition); - for (int j = 0; j <= i; j++) - { - int s = 0; - cell = row.CreateCell(j); - if (!input.isNiagara && j == s++) - { - cell.SetCellValue(r.id); - } - if (j == s++) - { - cell.SetCellValue(r.user_name); - } - if (j == s++) - { - cell.SetCellValue(r.action_name); - } + // foreach (var r in result) + // { + // RowPosition += 1; + // int k = 3; + // row = sheet.CreateRow(RowPosition); + // for (int j = 0; j <= i; j++) + // { + // int s = 0; + // cell = row.CreateCell(j); + // //if (!input.isNiagara && j == s++) + // //{ + // // cell.SetCellValue(r.id); + // //} + // if (j == s++) + // { + // cell.SetCellValue(r.user_name); + // } + // if (j == s++) + // { + // cell.SetCellValue(r.action_name); + // } - if (j == s++) - { - cell.SetCellValue(r.content); - } - - if (j == s++) - { - cell.SetCellValue(r.created_at != null ? ((DateTime)r.created_at).ToString("yyyy-MM-dd HH:mm:ss") : null); - } + // if (j == s++) + // { + // cell.SetCellValue(r.content); + // } - cell.CellStyle = style12; - } - } - } + // if (j == s++) + // { + // cell.SetCellValue(r.created_at != null ? ((DateTime)r.created_at).ToString("yyyy-MM-dd HH:mm:ss") : null); + // } - var ms = new NpoiMemoryStream - { - AllowClose = false - }; - workbook.Write(ms); - ms.Flush(); - ms.Seek(0, SeekOrigin.Begin); + // cell.CellStyle = style12; + // } + // } + //} - Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition"); + //var ms = new NpoiMemoryStream + //{ + // AllowClose = false + //}; + //workbook.Write(ms); + //ms.Flush(); + //ms.Seek(0, SeekOrigin.Begin); + + //Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition"); + + //return File(ms, "application/vnd.ms-excel", $"操作紀錄_{input.exportOpeTypeName}.xlsx"); + #endregion - return File(ms, "application/vnd.ms-excel", $"操作紀錄_{input.exportOpeTypeName}.xlsx"); } } } diff --git a/FrontendWebApi/Models/Operation.cs b/FrontendWebApi/Models/Operation.cs index 3c6e301..5d3ec2a 100644 --- a/FrontendWebApi/Models/Operation.cs +++ b/FrontendWebApi/Models/Operation.cs @@ -168,6 +168,7 @@ namespace FrontendWebApi.Models public string end_time { get; set; } public string building_tag{ get; set; } public short operation_type { get; set; } + public int type { get; set; } = 1; // log選項 1:系統紀錄;2:登入紀錄;3:燈控排程紀錄 } public class OperationLogExportInput { public bool isNiagara { get; set; } diff --git a/FrontendWebApi/Models/Share.cs b/FrontendWebApi/Models/Share.cs index e83bb38..d6d0c66 100644 --- a/FrontendWebApi/Models/Share.cs +++ b/FrontendWebApi/Models/Share.cs @@ -286,7 +286,7 @@ namespace FrontendWebApi.Models public class BasePageResult { public int? pageSize { get; set; } = 10; - + public int? totalItem { get; set; } = 0; public int? totalPage { get; set; } = 0; public int? currentPage { get; set; } = 0; } @@ -295,6 +295,6 @@ namespace FrontendWebApi.Models { public T data { get; set; } - public bool isEnable { get; set; } + public bool isEnable { get; set; } } }