diff --git a/FrontendWebApi/ApiControllers/HydroMeterController.cs b/FrontendWebApi/ApiControllers/HydroMeterController.cs index 8bc1b49..83cd651 100644 --- a/FrontendWebApi/ApiControllers/HydroMeterController.cs +++ b/FrontendWebApi/ApiControllers/HydroMeterController.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Ionic.Zip; using System.Collections.Immutable; using System.Text; +using iTextSharp.text; namespace FrontendWebApi.ApiControllers { @@ -822,6 +823,341 @@ namespace FrontendWebApi.ApiControllers return File(ms, "application/vnd.ms-excel", @$"電表報表{System.DateTime.Now.ToString("yyyyMMddHHmm")}.xlsx"); } + [HttpPost] + [Route("api/ExportElectricEachCompareList")] + public FileResult OpeExportEachCompareExcelElec([FromBody] HydroMeterInput input) + { + List> result = new List>(); + var building = backendRepository.GetAllAsync("select * from building where deleted = 0").Result; + StringBuilder fix_buildingTag = new StringBuilder(); + foreach (var b in building) + { + fix_buildingTag.Append("'").Append(b.building_tag.Trim()).Append("', "); + } + input.building_tag = fix_buildingTag.ToString().TrimEnd(',', ' '); + + result.Add(ElectricList_keke(input).Result.Value.Data.ToList()); + + // --- 8/24 修改到這裡囉 --- + + List> docFile = new List>(); + + var workbook = new XSSFWorkbook(); + #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; + #endregion + foreach (var r in result) + { + if (r.Count > 0) + { + string buildingName = r.Select(x => x.building_name).FirstOrDefault(); + var sheet = workbook.CreateSheet($"{buildingName} 電表報表"); + int RowPosition = 0; + #region set cell + IRow row = sheet.CreateRow(RowPosition); + sheet.SetColumnWidth(0, 4 * 160 * 12); + sheet.SetColumnWidth(1, 4 * 160 * 12); + sheet.SetColumnWidth(2, 4 * 160 * 12); + + int i = 0; + ICell 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; + + foreach (var rr in r.FirstOrDefault().rawData) + { + cell = row.CreateCell(i++); + cell.SetCellValue(rr.timeStamp); + 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 + + foreach (var rr in r) + { + RowPosition += 1; + int k = 4; + row = sheet.CreateRow(RowPosition); + for (int j = 0; j <= i; j++) + { + cell = row.CreateCell(j); + if (j == 0) + { + cell.SetCellValue(rr.building_name); + } + else if (j == 1) + { + cell.SetCellValue(rr.floor_tag); + } + else if (j == 2) + { + cell.SetCellValue(rr.device_full_name); + } + else if (j == 3) + { + cell.SetCellValue("kWh"); + } + + else if (j == 4) + { + foreach (var rrr in rr.rawData) + { + cell.SetCellValue(rrr.avg_rawdata.ToString()); + j++; + k++; + cell = row.CreateCell(j); + } + } + + if (j == k) + { + cell.SetCellValue(rr.total); + } + else if (j == k + 1) + { + cell.SetCellValue(rr.price); + } + else if (j == k + 2) + { + cell.SetCellValue(rr.total_price); + } + + cell.CellStyle = style12; + } + } + } + } + + 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", @$"電表報表{System.DateTime.Now.ToString("yyyyMMddHHmm")}.xlsx"); + } + + [HttpPost] + [Route("api/ElectricList_keke")] + public async Task>>> ElectricList_keke([FromBody] HydroMeterInput input) + { + ApiResult> apiResult = new ApiResult>(jwt_str); + if (!jwtlife) + { + apiResult.Code = "5000"; + return BadRequest(apiResult); + } + + string tableType = "day week month year"; + if (input.building_tag == null) + { + apiResult.Code = "9999"; + apiResult.Msg = "棟別沒有被選取"; + return BadRequest(apiResult); + } + else if (input.tableType == null || !tableType.Contains(input.tableType)) + { + apiResult.Code = "9999"; + apiResult.Msg = "表單類別錯誤"; + return BadRequest(apiResult); + } + + try + { + // 利用今年當月的字串,產生今年上月及去年同月的字串 + DateTime date = DateTime.ParseExact(input.startTime, "yyyy-MM", null); // 2023-08 + DateTime start = date.AddYears(-1).AddMonths(-1); + DateTime end = date.AddMonths(1); + DateTime previousYear = date.AddYears(-1); + DateTime previousMonth = date.AddMonths(-1); + //Console.WriteLine(previousYear.ToString("yyyy-MM")); // 2022-08 + //Console.WriteLine(previousMonth.ToString("yyyy-MM")); // 2023-07 + + var startTime = start.ToString("yyyy-MM"); // 查詢月份的去年 (去年同月) + var endTime = end.ToString("yyyy-MM"); // 查詢月份的上個月 + var lastYear = previousYear.ToString("yyyy-MM"); + var lastMonth = previousMonth.ToString("yyyy-MM"); + var searchTime = input.startTime; // 欲查詢的月份 + + string sqlWhere = ""; + string sqlGroup = ""; + string sqlAvgRawData = ""; + string buildingSql = ""; + string tag_quantity = await backendRepository.GetOneAsync("select system_value from variable where system_type = 'obixConfig' and system_key = 'tag_quantity' and deleted = 0"); + + // 將棟別字串前處理 (後續 SQL 語法可以使用 IN 的格式) + string[] parts_buildingTag = input.building_tag.Split(','); + StringBuilder fix_buildingTag = new StringBuilder(); + foreach (string part in parts_buildingTag) + { + fix_buildingTag.Append("'").Append(part.Trim()).Append("', "); + } + input.building_tag = fix_buildingTag.ToString().TrimEnd(',', ' '); + + if (tag_quantity == "5") + buildingSql = @$" and SUBSTRING_INDEX(device_number, '_', 1) in ({input.building_tag}) "; + else + buildingSql = @$" and SUBSTRING_INDEX(SUBSTRING_INDEX(device_number, '_', 2), '_', -1) in ({input.building_tag}) "; + + sqlAvgRawData = " round(kwh_result, 2) as avg_rawdata, start_timestamp, end_timestamp "; + + var table = "archive_electric_meter_month"; + var schema = await backendRepository.GetOneAsync($"select system_value from variable where system_type = 'project_name'"); + var isTable = await backendRepository.GetOneAsync($"select table_name from information_schema.tables where table_name = '{table}' and table_schema = '{schema.Split('/')[0]}'"); + if (string.IsNullOrEmpty(isTable)) //check for has table or not + { + apiResult.Code = "0000"; + apiResult.Data = new List() { }; + return Ok(apiResult); + } + + var dateFormat = input.tableType == "day" || input.tableType == "week" ? "%Y-%m-%d" : input.tableType == "month" ? "%Y-%m" : input.tableType == "year" ? "%Y" : null; + var aemmEndDate = input.tableType == "year" ? $"year(DATE_ADD(fd.date, INTERVAL +1 {input.tableType}))" : $"DATE_ADD(fd.date, INTERVAL +1 {input.tableType})"; + var aemmStaDate = input.tableType == "year" ? "year(fd.date)" : "fd.date"; + var sql = $@"set @i = -1; + select fd.device_number, case when aemm.avg_rawdata = -1.0 then 'NaN' when aemm.avg_rawdata is null then 0.00 else aemm.avg_rawdata end as avg_rawdata, DATE_FORMAT(fd.date, '{dateFormat}') as timestamp + from ( + select * + from ( + ( + SELECT DATE(ADDDATE(@startTime, INTERVAL @i:=@i+1 {input.tableType})) AS date + FROM {table} + HAVING @i < TIMESTAMPDIFF({input.tableType}, @startTime, ADDDATE(@endTime, INTERVAL -1 DAY)) + ) d, + ( + select device_number + from {table} + where start_timestamp >= @startTime and end_timestamp < @endTime and point = 'KWH' {buildingSql} + {sqlWhere} + group by device_number + ) dn + ) + ) fd + left join ( + select device_number, {sqlAvgRawData} + from {table} + where start_timestamp >= @startTime and end_timestamp < @endTime and point = 'KWH' {buildingSql} + {sqlWhere} {sqlGroup} + ) aemm on aemm.start_timestamp >= {aemmStaDate} and aemm.end_timestamp < {aemmEndDate} and aemm.device_number = fd.device_number + where DATE_FORMAT(fd.date, '%Y-%m') = '{searchTime}' or DATE_FORMAT(fd.date, '%Y-%m') = '{lastMonth}' or DATE_FORMAT(fd.date, '%Y-%m') = '{lastYear}' + order by fd.device_number, fd.date"; + Logger.LogInformation("SQL = " + sql + " startTime=" + startTime + " endTime=" + endTime + " building=" + input.building_tag + " floor_tag = " + input.floor_tag); + var rawData = await backendRepository.GetAllAsync(sql, + new { startTime = startTime, endtime = endTime, building_tag = input.building_tag, dateFormat = dateFormat }); + + List Result = new List(); + if (tag_quantity == "5") + { + Result = rawData + .GroupBy(x => new { building_tag = x.device_number.Split("_")[0], floor_tag = x.device_number.Split("_")[2], device_serial_tag = x.device_number.Split("_")[4], device_number = x.device_number }) + .Select(x => new HydroMeterOutput { building_tag = x.Key.building_tag, floor_tag = x.Key.floor_tag, device_serial_tag = x.Key.device_serial_tag, device_number = x.Key.device_number }) + .ToList(); + } + else + { + Result = rawData + .GroupBy(x => new { building_tag = x.device_number.Split("_")[1], floor_tag = x.device_number.Split("_")[4], device_master = x.device_number.Split("_")[5], device_serial_tag = x.device_number.Split("_")[7], device_number = x.device_number }) + .Select(x => new HydroMeterOutput { building_tag = x.Key.building_tag, floor_tag = x.Key.floor_tag, device_serial_tag = x.Key.device_serial_tag, device_master = x.Key.device_master, device_number = x.Key.device_number }) + .ToList(); + } + + foreach (var l in Result) + { + l.rawData = new List(); + l.device_full_name = await backendRepository.GetOneAsync($"select full_name from device where device_number = '{l.device_number}'"); + if (tag_quantity == "5") + { + l.rawData.AddRange( + rawData.Where(x => x.device_number.Split("_")[0] == l.building_tag && x.device_number.Split("_")[2] == l.floor_tag && x.device_number.Split("_")[4] == l.device_serial_tag) + ); + } + else + { + l.rawData.AddRange( + rawData.Where(x => x.device_number.Split("_")[1] == l.building_tag && x.device_number.Split("_")[4] == l.floor_tag && x.device_number.Split("_")[5] == l.device_master && x.device_number.Split("_")[7] == l.device_serial_tag) + ); + } + l.building_name = await backendRepository.GetOneAsync("select full_name from building where building_tag = @building_tag and deleted = 0", + new { building_tag = l.building_tag }); + l.total = l.rawData.Where(x => x.avg_rawdata != "NaN").Sum(x => decimal.Parse(x.avg_rawdata ?? "0", System.Globalization.NumberStyles.Float)).ToString(); + l.price = input.price.HasValue + ? (Math.Round(input.price.Value, 2)).ToString() + : Math.Round((await backendRepository.GetOneAsync("select system_value from variable where system_type = 'ElectricPrice' and deleted = 0")), 2).ToString(); + l.total_price = Math.Round((Decimal.Parse(l.total) * Decimal.Parse(l.price)), 2).ToString(); + } + + apiResult.Code = "0000"; + apiResult.Data = Result; + } + catch (Exception exception) + { + apiResult.Code = "9999"; + apiResult.Msg = "系統內部錯誤,請聯絡管理者。"; + string json = System.Text.Json.JsonSerializer.Serialize(input); + Logger.LogError("【" + controllerName + "/" + actionName + "】" + json); + Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message); + } + return apiResult; + } + public static int GetDayInMonth(string yearMonth) { List datesList = new List();