From e2f3992b9c1db01c12c3fd7a372763364b17e466 Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Tue, 26 Nov 2024 16:45:53 +0800 Subject: [PATCH 1/9] =?UTF-8?q?[WebApi]=E6=93=8D=E4=BD=9C=E7=B4=80?= =?UTF-8?q?=E9=8C=84=E6=94=B9=E6=88=90MSSQL=E6=92=88=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApiControllers/OperationLogController.cs | 502 ++++++++++++------ FrontendWebApi/Models/Operation.cs | 1 + FrontendWebApi/Models/Share.cs | 4 +- 3 files changed, 333 insertions(+), 174 deletions(-) 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; } } } From b60530974f881428a756170af81bf088c70800d4 Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Tue, 26 Nov 2024 17:27:46 +0800 Subject: [PATCH 2/9] =?UTF-8?q?[BGService]=E5=B0=87=E9=83=A8=E5=88=86obix?= =?UTF-8?q?=E5=AE=9A=E6=99=82=E4=BB=BB=E5=8B=99=E6=94=B9=E6=88=90=E6=89=B9?= =?UTF-8?q?=E6=AC=A1=E6=92=88=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Quartz/Jobs/LightScheduleJob .cs | 382 ++++++++++++++---- .../Quartz/Jobs/ParkingJob.cs | 249 ++++++------ .../Quartz/Jobs/WeatherAPIJob.cs | 188 ++++++++- 3 files changed, 595 insertions(+), 224 deletions(-) diff --git a/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs b/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs index 9c3ffa0..c2ef1a5 100644 --- a/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs +++ b/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs @@ -38,14 +38,13 @@ namespace BackendWorkerService.Quartz.Jobs private readonly IBackendRepository backendRepository; private readonly ILogger loggers; public LightScheduleJob(ILogger logger, - IBackgroundServiceRepository backgroundServiceRepository, IBackendRepository backendRepository, ILogger loggers) + IBackgroundServiceRepository backgroundServiceRepository, IBackendRepository backendRepository, ILogger loggers) { this.logger = logger; this.backgroundServiceRepository = backgroundServiceRepository; this.backendRepository = backendRepository; this.loggers = loggers; } - public async Task Execute(IJobExecutionContext context) { Task_Detail task_Detail = new Task_Detail(loggers, backendRepository); @@ -58,33 +57,13 @@ namespace BackendWorkerService.Quartz.Jobs await task_Detail.InsertWorkTime("LightScheduleJob", "light_schedule"); var TimeNow = DateTime.Now.ToString("dddd HH:mm"); - var schedule = await backendRepository.GetAllAsync("light_schedule","deleted = 0 and status = 1"); + var schedule = await backendRepository.GetAllAsync("light_schedule", "deleted = 0 and status = 1"); + string date = DateTime.Now.ToString("yyyy-MM-dd"); foreach (var oneSchedule in schedule) { - // 檢查執行log - string light_schedule_guid = oneSchedule.light_schedule_guid; - string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; - var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); - string start_time = null; - string end_time = null; - if (schedule_log != null) - { - start_time = schedule_log.start_time; - end_time = schedule_log.end_time; - } - if (schedule_log == null) - { - Dictionary log = new Dictionary() - { - { "@light_schedule_guid", light_schedule_guid}, - { "@date", date}, - }; - await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); - } - // 如果log有紀錄 - + // 先檢查今日否需執行 var weeklistN = oneSchedule.week.Split(','); List weeklist = new List(); foreach (var weekN in weeklistN) @@ -102,35 +81,53 @@ namespace BackendWorkerService.Quartz.Jobs }; weeklist.Add(week); } + var Time = TimeNow.Split(" "); - string check = string.Empty; - // 檢查起始執行 - if (start_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) - { - check = ""; - UpdatedNiagara(oneSchedule, check); - Dictionary log = new Dictionary() - { - { "@start_time", Time[1]}, - }; - await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); - logger.LogInformation($"【LightScheduleJob】【燈控排程開啟成功】排程名稱 :{oneSchedule.full_name}"); + if (!weeklist.Contains(Time[0])) { continue; } + + // 檢查執行log + string light_schedule_guid = oneSchedule.light_schedule_guid; + string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; + var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); + string start_time = null; + string end_time = null; + if (schedule_log != null) + { + start_time = schedule_log.start_time; + end_time = schedule_log.end_time; } + + if (schedule_log == null) + { + Dictionary log = new Dictionary() + { + { "@light_schedule_guid", light_schedule_guid }, + { "@date", date }, + }; + await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); + } + + + string check = string.Empty; + + // 檢查起始執行 + if (start_time == null && end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) + { + check = "true"; // 開啟 + } + // 檢查結束執行 if (end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.end_time)) { - check = ""; - UpdatedNiagara(oneSchedule, check); - Dictionary log = new Dictionary() - { - { "@end_time", Time[1]}, - }; - await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); - logger.LogInformation($"【LightScheduleJob】【燈控排程關閉成功】排程名稱 :{oneSchedule.full_name}"); + check = "false"; // 關閉 + } + + if (!string.IsNullOrEmpty(check)) + { + bool requestSuccess = await UpdatedNiagara(oneSchedule, check); } } - await task_Detail.InsertWorkTime_End("LightScheduleJob", "light_schedule"); } catch (Exception ex) @@ -146,52 +143,279 @@ namespace BackendWorkerService.Quartz.Jobs logger.LogError("【LightScheduleJob】【任務失敗】[Exception]:{0}", exception.ToString()); } } - public async void UpdatedNiagara(Schedule oneSchedule, string check) + + public async Task UpdatedNiagara(Schedule oneSchedule, string check) { try { - var deviceNumList = await backendRepository.GetAllAsync(@$"select d.device_number from schedule_device sd join device d on sd.device_guid = d.device_guid - where light_schedule_guid = '{oneSchedule.light_schedule_guid}' and is_link = 1"); + // 取得排程所對應的設備號碼列表 + var deviceNumList = await backendRepository.GetAllAsync(@$"SELECT d.device_number + FROM schedule_device sd + JOIN device d ON sd.device_guid = d.device_guid + WHERE light_schedule_guid = '{oneSchedule.light_schedule_guid}' AND is_link = 1"); + + // 取得obix配置 + var variableObix = await backendRepository.GetAllAsync(@$"SELECT system_value as Value, system_key as Name + FROM variable + WHERE deleted = 0 AND system_type = 'obixConfig'"); + + // 取得obix相關配置參數 + string url = variableObix.FirstOrDefault(x => x.Name == "ApiBase")?.Value; + string account = variableObix.FirstOrDefault(x => x.Name == "UserName")?.Value; + string pass = variableObix.FirstOrDefault(x => x.Name == "Password")?.Value; + + // 檢查是否有配置缺失 + if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(account) || string.IsNullOrEmpty(pass)) + { + logger.LogWarning("【LightScheduleJob】【obix配置缺失】請檢查obix配置"); + return false; + } + + // 準備HTTP請求的基本資訊 + string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes($"{account}:{pass}")); + + // 構建每個設備的請求 + List batchRequests = new List(); + TagChangeFunction tagChange = new TagChangeFunction(); - var variableObix = await backendRepository.GetAllAsync("SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'"); - string url = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); - string account = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault(); - string pass = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault(); foreach (var deviceNum in deviceNumList) { - TagChangeFunction tagChange = new TagChangeFunction(); + // 處理設備號碼,分解到URL中 var d = tagChange.AddStringIfStartsWithDigit(deviceNum, "$3"); - var html = $"{url}obix/config/Arena/" + $"{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; - string authInfo = account + ":" + pass; - authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(html); - request.Method = "POST"; - request.Accept = "application/json; charset=utf-8"; - request.Headers["Authorization"] = "Basic " + authInfo; - byte[] byteArray = Encoding.UTF8.GetBytes(check); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(byteArray, 0, byteArray.Length); - } - var response = (HttpWebResponse)request.GetResponse(); - string strResponse = ""; + var uri = $"{url}obix/config/Arena/{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; - using (var sr = new StreamReader(response.GetResponseStream())) - { - strResponse = sr.ReadToEnd(); - } - // 只取err會取到override - if (strResponse.Contains(""; + + // 建立批次請求 + batchRequests.Add($"" + realData + ""); } + + // 構建整體批次請求 + var batchRequestData = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "obix/batch"); + request.Method = "POST"; + request.Accept = "application/json; charset=utf-8"; + request.Headers["Authorization"] = "Basic " + authInfo; + + // 將所有設備的請求內容合併成一個批次請求 + byte[] byteArray = Encoding.UTF8.GetBytes(batchRequestData); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(byteArray, 0, byteArray.Length); + } + + // 發送請求並處理回應 + var response = (HttpWebResponse)request.GetResponse(); + string responseContent = string.Empty; + + using (var sr = new StreamReader(response.GetResponseStream())) + { + responseContent = sr.ReadToEnd(); + } + + + // 檢查回應中是否有錯誤 + if (responseContent.Contains(" log = new Dictionary(); + + string time = DateTime.Now.ToString("HH:mm"); + if (check == "true") + { + log.Add("@start_time", time); + } + else + { + log.Add("@end_time", time); + } + + + await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{oneSchedule.light_schedule_guid}' and date = '{DateTime.Now:yyyy-MM-dd}'"); + + logger.LogInformation($"【LightScheduleJob】【Niagara燈控設置成功】排程名稱 :{oneSchedule.full_name}"); + return true; } catch (Exception ex) { - logger.LogError("【LightScheduleJob】" + "UpdatedNiagaraFail:" + ex.ToString()); - throw ex; + logger.LogError("【LightScheduleJob】批次請求發送失敗:" + ex.ToString()); + return false; } } + + + + + + + + //public async Task Execute(IJobExecutionContext context) + //{ + // Task_Detail task_Detail = new Task_Detail(loggers, backendRepository); + // try + // { + // if (await task_Detail.GetNeedWorkTask("LightScheduleJob", "light_schedule")) + // { + // try + // { + // await task_Detail.InsertWorkTime("LightScheduleJob", "light_schedule"); + + // var TimeNow = DateTime.Now.ToString("dddd HH:mm"); + // var schedule = await backendRepository.GetAllAsync("light_schedule","deleted = 0 and status = 1"); + // string date = DateTime.Now.ToString("yyyy-MM-dd"); + + // foreach (var oneSchedule in schedule) + // { + // // 檢查執行log + // string light_schedule_guid = oneSchedule.light_schedule_guid; + // string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; + // var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); + // string start_time = null; + // string end_time = null; + // if (schedule_log != null) + // { + // start_time = schedule_log.start_time; + // end_time = schedule_log.end_time; + // } + // if (schedule_log == null) + // { + // Dictionary log = new Dictionary() + // { + // { "@light_schedule_guid", light_schedule_guid}, + // { "@date", date}, + // }; + // await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); + // } + // // 如果log有紀錄 + + // var weeklistN = oneSchedule.week.Split(','); + // List weeklist = new List(); + // foreach (var weekN in weeklistN) + // { + // var week = weekN switch + // { + // "0" => "星期日", + // "1" => "星期一", + // "2" => "星期二", + // "3" => "星期三", + // "4" => "星期四", + // "5" => "星期五", + // "6" => "星期六", + // _ => "" + // }; + // weeklist.Add(week); + // } + // var Time = TimeNow.Split(" "); + // string check = string.Empty; + // // 檢查起始執行 + // if (start_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) + // { + // check = ""; + // UpdatedNiagara(oneSchedule, check); + // Dictionary log = new Dictionary() + // { + // { "@start_time", Time[1]}, + // }; + // await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); + // logger.LogInformation($"【LightScheduleJob】【燈控排程開啟成功】排程名稱 :{oneSchedule.full_name}"); + // } + // // 檢查結束執行 + // if (end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.end_time)) + // { + // check = ""; + // UpdatedNiagara(oneSchedule, check); + // Dictionary log = new Dictionary() + // { + // { "@end_time", Time[1]}, + // }; + // await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); + // logger.LogInformation($"【LightScheduleJob】【燈控排程關閉成功】排程名稱 :{oneSchedule.full_name}"); + // } + // } + + + // await task_Detail.InsertWorkTime_End("LightScheduleJob", "light_schedule"); + // } + // catch (Exception ex) + // { + // logger.LogInformation($"LightScheduleJob fail"); + // await task_Detail.WorkFail("LightScheduleJob", "light_schedule", ex.Message.ToString()); + // } + // } + // } + // catch (Exception exception) + // { + // logger.LogError("【LightScheduleJob】【任務失敗】"); + // logger.LogError("【LightScheduleJob】【任務失敗】[Exception]:{0}", exception.ToString()); + // } + //} + //public async void UpdatedNiagara(Schedule oneSchedule, string check) + //{ + // try + // { + // var deviceNumList = await backendRepository.GetAllAsync(@$"select d.device_number from schedule_device sd join device d on sd.device_guid = d.device_guid + // where light_schedule_guid = '{oneSchedule.light_schedule_guid}' and is_link = 1"); + + // var variableObix = await backendRepository.GetAllAsync("SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'"); + // string url = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); + // string account = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault(); + // string pass = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault(); + // foreach (var deviceNum in deviceNumList) + // { + // TagChangeFunction tagChange = new TagChangeFunction(); + // var d = tagChange.AddStringIfStartsWithDigit(deviceNum, "$3"); + // var html = $"{url}obix/config/Arena/" + $"{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; + // string authInfo = account + ":" + pass; + // authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); + // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(html); + // request.Method = "POST"; + // request.Accept = "application/json; charset=utf-8"; + // request.Headers["Authorization"] = "Basic " + authInfo; + // byte[] byteArray = Encoding.UTF8.GetBytes(check); + // using (Stream reqStream = request.GetRequestStream()) + // { + // reqStream.Write(byteArray, 0, byteArray.Length); + // } + // var response = (HttpWebResponse)request.GetResponse(); + // string strResponse = ""; + + // using (var sr = new StreamReader(response.GetResponseStream())) + // { + // strResponse = sr.ReadToEnd(); + // } + // // 只取err會取到override + // if (strResponse.Contains(" batchRequests = new List(); // 用來存儲批次請求的列表 + foreach (var area in spaceResponseResult.Payload.Areas) { - //找出對定的設備代碼 - var selectedMapping = parkingSapceMapping.Where(x => x.System_key == area.Name).FirstOrDefault(); + // 找出對應的設備代碼 + var selectedMapping = parkingSapceMapping.FirstOrDefault(x => x.System_key == area.Name); if (selectedMapping != null) { - item = area.Name; + var name = area.Name; // 保存設備名稱 var tagName = selectedMapping.system_value; var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/CV/set"; var tagNameSplit = tagName.Split("_"); - var parames = new List(); - parames.Add(parkingConfig.ApiBase); - for (var i = 0; i < tagNameSplit.Length; i++) - { - if (i != tagNameSplit.Length - 1) - { - parames.Add(tagNameSplit[i]); // tag 前 4段 - } - else - { - parames.Add(tagName); // 第五段 完整 tag - } - } - //logger.LogError(@$"【ParkingJob】【停車場剩餘車位】{apiFormat}"); - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray())); - request.Method = "POST"; - request.Headers.Add("Authorization", "Basic " + encoded); - request.PreAuthenticate = true; - request.Timeout = System.Threading.Timeout.Infinite; + var parames = new List { parkingConfig.ApiBase }; + parames.AddRange(tagNameSplit.Take(tagNameSplit.Length - 1)); // tag 前 4段 + parames.Add(tagName); // 最後一段 完整 tag + string requestUri = string.Format(apiFormat, parames.ToArray()); + + // 構建要發送的實體資料 var real = $@""; - byte[] realByteArray = Encoding.UTF8.GetBytes(real); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(realByteArray, 0, realByteArray.Length); - } - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + batchRequests.Add($"" + + $"" + + $""); - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(responseContent); - string json = JsonConvert.SerializeXmlNode(xmlDocument); - JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json); - - if (jsonResult.ContainsKey("err")) //抓取錯誤 - { - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】"); - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[錯誤內容]:{0}", json); - } - else - { - if (jsonResult.ContainsKey("real")) //表示可以讀取到內容 - { - List> ontimeRawDatas = new List>(); - - var realList = jsonResult["real"]; - var display = realList["@display"]; - if (display != null) - { - var tempStrSplit = display.ToString().Split(" "); - if (tempStrSplit[0] != area.Remain.ToString()) - { - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[修改失敗]:{0}", display.ToString()); - } - else - { - logger.LogInformation("【ParkingJob】【停車場剩餘車位資訊】[修改成功]:{0}", display.ToString()); - logger.LogInformation("【ParkingJob】【停車場剩餘車位資訊】[停車場資訊]:{0}", item); - } - } - } - } + // 進行日誌記錄 + logger.LogInformation("【ParkingJob】【停車場剩餘車位】準備更新設備:{0},剩餘車位數:{1}", name, area.Remain); } else { @@ -175,11 +129,59 @@ namespace BackendWorkerService.Quartz.Jobs } } + if (batchRequests.Any()) + { + // 建立批次請求 XML + var batchRequestXml = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(parkingConfig.ApiBase + "obix/batch"); + request.Method = "POST"; + request.Headers.Add("Authorization", "Basic " + encoded); + request.PreAuthenticate = true; + request.Timeout = System.Threading.Timeout.Infinite; + + byte[] requestData = Encoding.UTF8.GetBytes(batchRequestXml); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(requestData, 0, requestData.Length); + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + // 檢查回應中是否有錯誤 + if (responseContent.Contains(" batchRequests = new List(); // 用來存儲批次請求的列表 + foreach (var equipment in equipmentResponseResult.Payload) { - //找出對定的設備代碼 - var selectedMapping = parkingEquipmentMapping.Where(x => x.System_key == equipment.Id).FirstOrDefault(); + // 找出對應的設備代碼 + var selectedMapping = parkingEquipmentMapping.FirstOrDefault(x => x.System_key == equipment.Id); if (selectedMapping != null) { - item = equipment.Id; + var name = equipment.Id; // 保存設備ID var tagName = selectedMapping.system_value; var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/ST/set"; var tagNameSplit = tagName.Split("_"); - var parames = new List(); - parames.Add(parkingConfig.ApiBase); - for (var i = 0; i < tagNameSplit.Length; i++) - { - if (i != tagNameSplit.Length - 1) - { - parames.Add(tagNameSplit[i]); - } - else - { - parames.Add(tagName); - } - } + var parames = new List { parkingConfig.ApiBase }; + parames.AddRange(tagNameSplit.Take(tagNameSplit.Length - 1)); // tag 前 4段 + parames.Add(tagName); // 最後一段 完整 tag - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray())); - request.Method = "POST"; - request.Headers.Add("Authorization", "Basic " + encoded); - request.PreAuthenticate = true; + string requestUri = string.Format(apiFormat, parames.ToArray()); + // 構建要發送的實體資料 var real = $@""; - byte[] realByteArray = Encoding.UTF8.GetBytes(real); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(realByteArray, 0, realByteArray.Length); - } + batchRequests.Add($"" + + $"" + + $""); - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); - - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(responseContent); - string json = JsonConvert.SerializeXmlNode(xmlDocument); - JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json); - - if (jsonResult.ContainsKey("err")) //抓取錯誤 - { - logger.LogError("【ParkingJob】【設備資訊】"); - logger.LogError("【ParkingJob】【設備資訊】[錯誤內容]:{0}", json); - } - else - { - if (jsonResult.ContainsKey("bool")) //表示可以讀取到內容 - { - List> ontimeRawDatas = new List>(); - - var realList = jsonResult["bool"]; - var val = realList["@val"]; - if (val != null) - { - var tempStrSplit = val.ToString(); - if (tempStrSplit != equipment.Alive.ToString().ToLower()) - { - logger.LogError("【ParkingJob】【設備資訊】[修改失敗]:{0}", val.ToString()); - } - else - { - logger.LogInformation("【ParkingJob】【設備資訊】[修改成功]:{0}", val.ToString()); - logger.LogInformation("【ParkingJob】【設備資訊】[設備資訊]:{0}", item); - } - } - } - } + // 進行日誌記錄 + logger.LogInformation("【ParkingJob】【設備資訊】準備更新設備:{0},設備狀態:{1}", name, equipment.Alive); } else { logger.LogWarning("【ParkingJob】【設備資訊】[查無該名稱對應表]:{0}", equipment.Id); } } + + if (batchRequests.Any()) + { + // 建立批次請求 XML + var batchRequestXml = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(parkingConfig.ApiBase + "obix/batch"); + request.Method = "POST"; + request.Headers.Add("Authorization", "Basic " + encoded); + request.PreAuthenticate = true; + + byte[] requestData = Encoding.UTF8.GetBytes(batchRequestXml); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(requestData, 0, requestData.Length); + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + // 檢查回應中是否有錯誤 + if (responseContent.Contains("(sql); - var T = types.Where(a => a.weather_type == "T").FirstOrDefault(); - var RbT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set", T.get_value); - UpdatedNiagara("api_weateher", RbT, T.id); + var urlMapping = new Dictionary + { + { "T", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set" }, + { "RH", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set" }, + { "PoP12h", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set" }, + { "Wx", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set" } + }; - var RH = types.Where(a => a.weather_type == "RH").FirstOrDefault(); - var RHT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set", RH.get_value); - UpdatedNiagara("api_weateher", RHT, RH.id); + // 建立批次請求 + var batchRequests = types + .Where(t => urlMapping.ContainsKey(t.weather_type)) + .Select(t => ( + url: obixApiConfig.ApiBase + urlMapping[t.weather_type], + value: t.get_value + )) + .ToList(); + + + // 呼叫批次請求 + var batchResponse = await ProcessBatchRequestAsync(obixApiConfig, batchRequests); + + // 解析回應 XML + var batchResponseXml = XDocument.Parse(batchResponse); + + var listElement = batchResponseXml.Descendants().FirstOrDefault(e => e.Name.LocalName == "list"); + + if (listElement == null) + { + throw new Exception("Batch response XML does not contain a 'list' element."); + } + + var childElements = listElement.Elements().ToList(); + + // 使用 urlMapping 的值反向找對應的 weather_type + for (int i = 0; i < childElements.Count; i++) + { + var tag = childElements[i].Name.LocalName; + var responseStr = childElements[i].ToString(); + var currentRequest = batchRequests[i]; + + // 找到當前 URL 在 urlMapping 中的 key (weather_type) + var weatherTypeKey = urlMapping.FirstOrDefault(x => currentRequest.url.Contains(x.Value)).Key; + + if (weatherTypeKey != null) + { + var weatherType = types.FirstOrDefault(t => t.weather_type == weatherTypeKey); + if (weatherType != null) + { + if (tag == "err") + { + UpdatedNiagara("api_weateher", responseStr, weatherType.id); + } + else + { + UpdatedNiagara("api_weateher", "success", weatherType.id); + } + } + else + { + logger.LogWarning($"No matching weather type found for key: {weatherTypeKey}"); + } + } + else + { + logger.LogWarning($"No matching URL found for request: {currentRequest.url}"); + } + } - var PoP12h = types.Where(a => a.weather_type == "PoP12h").FirstOrDefault(); - var PoP12hT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set", PoP12h.get_value); - UpdatedNiagara("api_weateher", PoP12hT, PoP12h.id); - var Wx = types.Where(a => a.weather_type == "Wx").FirstOrDefault(); - var WxT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set", Wx.get_value); - UpdatedNiagara("api_weateher", WxT, Wx.id); await task_Detail.InsertWorkTime_End("WeatherAPI", "set_weather"); - logger.LogInformation($"set niagara weather value success"); + logger.LogInformation($"Set Niagara weather value success"); } catch (Exception ex) { - logger.LogInformation($"set niagara weather value fail"); - await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message.ToString()); + logger.LogError($"Set Niagara weather value fail: {ex.Message}"); + await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message); } } + // Niagara單次寫法 + //if (await task_Detail.GetNeedWorkTask("WeatherAPI", "set_weather")) + //{ + // try + // { + // await task_Detail.InsertWorkTime("WeatherAPI", "set_weather"); + // var sql = @$"SELECT + // id, + // weather_type, + // get_value + // FROM api_weateher + // where id in (select MAX(id) from api_weateher where start_time < NOW() group by weather_type) + // order by start_time desc"; + // var types = await backendRepository.GetAllAsync(sql); + // var T = types.Where(a => a.weather_type == "T").FirstOrDefault(); + // var RbT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set", T.get_value); + // UpdatedNiagara("api_weateher", RbT, T.id); + + // var RH = types.Where(a => a.weather_type == "RH").FirstOrDefault(); + // var RHT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set", RH.get_value); + // UpdatedNiagara("api_weateher", RHT, RH.id); + + // var PoP12h = types.Where(a => a.weather_type == "PoP12h").FirstOrDefault(); + // var PoP12hT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set", PoP12h.get_value); + // UpdatedNiagara("api_weateher", PoP12hT, PoP12h.id); + + // var Wx = types.Where(a => a.weather_type == "Wx").FirstOrDefault(); + // var WxT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set", Wx.get_value); + // UpdatedNiagara("api_weateher", WxT, Wx.id); + // await task_Detail.InsertWorkTime_End("WeatherAPI", "set_weather"); + // logger.LogInformation($"set niagara weather value success"); + // } + // catch (Exception ex) + // { + // logger.LogInformation($"set niagara weather value fail"); + // await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message.ToString()); + // } + //} } catch (Exception exception) { @@ -737,6 +836,51 @@ namespace BackendWorkerService.Quartz.Jobs return rint; } + public async Task ProcessBatchRequestAsync(ObixApiConfig obixApiConfig, List<(string url, string value)> batchRequests) + { + try + { + + var batchRequestData = new StringBuilder(); + string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes($"{obixApiConfig.UserName}:{obixApiConfig.Password}")); + + // 組合批次請求的資料 + foreach (var request in batchRequests) + { + var jsonData = $""; + batchRequestData.AppendLine($"" + jsonData + ""); + } + + // 最終的批次請求資料 + var batchRequestXml = $@"{batchRequestData}"; + + // 建立 HTTP 請求 + var requestBacth = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/batch"); + requestBacth.Method = "POST"; + requestBacth.Headers.Add("Authorization", "Basic " + authInfo); + + // 寫入請求資料 + using (var streamWriter = new StreamWriter(requestBacth.GetRequestStream())) + { + streamWriter.Write(batchRequestXml); + } + + // 獲取回應 + using (var response = (HttpWebResponse)await requestBacth.GetResponseAsync()) + using (var streamReader = new StreamReader(response.GetResponseStream())) + { + return await streamReader.ReadToEndAsync(); + } + + } + catch (Exception) + { + + return "BatchRequestg失敗"; + } + } + + public async void UpdatedNiagara(string DBTableName, string ResponseStr, int CheckNumId) { try From a794808d49c617469b312f1c31112917ffcdf04f Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Tue, 4 Feb 2025 11:22:50 +0800 Subject: [PATCH 3/9] =?UTF-8?q?[WebApi]=E4=BF=AE=E6=94=B9=E8=A8=AD?= =?UTF-8?q?=E5=82=99=E9=BB=9E=E4=BD=8D=E6=98=AF=E5=90=A6=E9=A1=AF=E7=A4=BA?= =?UTF-8?q?=E5=9C=A8=E6=AD=B7=E5=8F=B2=E7=B4=80=E9=8C=84=E7=9A=84=E9=82=8F?= =?UTF-8?q?=E8=BC=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FrontendWebApi/ApiControllers/HistoryController.cs | 2 +- .../Implement/NiagaraDataSynchronizeRepository.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/FrontendWebApi/ApiControllers/HistoryController.cs b/FrontendWebApi/ApiControllers/HistoryController.cs index 830a948..fdacbad 100644 --- a/FrontendWebApi/ApiControllers/HistoryController.cs +++ b/FrontendWebApi/ApiControllers/HistoryController.cs @@ -637,7 +637,7 @@ namespace FrontendWebApi.ApiControllers and a.device_building_tag COLLATE utf8mb4_unicode_ci = b.device_building_tag and a.device_name_tag COLLATE utf8mb4_unicode_ci = b.device_name_tag join building c on c.building_tag = b.device_building_tag - join import_niagara_item_history h on b.device_number = h.device_number and a.points = h.device_point_name + -- join import_niagara_item_history h on b.device_number = h.device_number and a.points = h.device_point_name join variable v1 on v1.system_value = b.device_system_tag and v1.deleted = 0 and v1.system_type = 'device_system_category_layer2' join variable v2 on v2.system_value = b.device_name_tag and v2.deleted = 0 and v2.system_type = 'device_system_category_layer3' where a.deleted = 0 and b.deleted = 0 and v2.deleted = 0 and v1.deleted = 0 diff --git a/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs b/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs index a0d10f8..ce4d1aa 100644 --- a/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs +++ b/Repository/BackendRepository/Implement/NiagaraDataSynchronizeRepository.cs @@ -951,8 +951,7 @@ namespace Repository.BackendRepository.Implement AND d.device_name_tag = subquery.device_name_tag AND d.points = subquery.device_point_name AND d.device_building_tag = subquery.device_building_tag - SET d.is_show_history = CASE WHEN subquery.device_point_name IS NULL THEN 0 ELSE 1 END - where date(d.created_at) = subquery.created_at;"); + SET d.is_show_history = CASE WHEN subquery.device_point_name IS NULL THEN 0 ELSE 1 END"); using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { From 60003dd89f952703fd3c7eeaa77017fbd51ee054 Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Wed, 5 Feb 2025 10:52:52 +0800 Subject: [PATCH 4/9] =?UTF-8?q?[WebApi][BGService]=E6=B0=A3=E8=B1=A1?= =?UTF-8?q?=E5=B1=80=E8=B3=87=E6=96=99=E6=94=B9=E7=89=88=E5=B0=8D=E6=87=89?= =?UTF-8?q?=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Backend/Models/WeatherAPIJob.cs | 112 ++++++++ .../Quartz/Jobs/WeatherAPIJob.cs | 239 +++++++++++------- .../ApiControllers/BuildController.cs | 10 +- 3 files changed, 259 insertions(+), 102 deletions(-) diff --git a/Backend/Models/WeatherAPIJob.cs b/Backend/Models/WeatherAPIJob.cs index 338b809..65f7613 100644 --- a/Backend/Models/WeatherAPIJob.cs +++ b/Backend/Models/WeatherAPIJob.cs @@ -266,7 +266,119 @@ namespace Backend.Models #endregion + #region 新架構 weather api + public class Root3 + { + public string Success { get; set; } + public Records3 Records { get; set; } + } + public class Records3 + { + public string DatasetDescription { get; set; } + public string LocationsName { get; set; } + public string Dataid { get; set; } + public List Locations { get; set; } + } + + public class Locations3 + { + public List Location { get; set; } + } + + public class Location3 + { + public string LocationName { get; set; } + public string Geocode { get; set; } + public string Latitude { get; set; } + public string Longitude { get; set; } + public List WeatherElement { get; set; } + } + + public class WeatherElement3 + { + public string ElementName { get; set; } + public List