From 6ad6054bbaf4c54a3bf6e0295d3b06e359723e10 Mon Sep 17 00:00:00 2001 From: Kai Date: Thu, 5 Aug 2021 17:12:38 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=8D=B3=E6=99=82=E8=B3=87=E8=A8=8A=20and?= =?UTF-8?q?=20=E5=90=88=E4=BD=B5=E9=9B=BB=E7=AB=99=E5=9C=96=E8=A1=A8?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=A8=A1=E7=B5=84=E6=BA=AB=E5=BA=A6?= =?UTF-8?q?=202.Sensor=20=E5=A6=82=E6=9C=89=E5=A4=9A=E5=80=8B=E9=9C=80?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=82=BA=E5=A4=9A=E5=80=8B=E5=B9=B3=E5=9D=87?= =?UTF-8?q?=203.=E5=90=88=E4=BD=B5=E9=9B=BB=E7=AB=99=EF=BC=9A=E9=81=B8?= =?UTF-8?q?=E6=93=87=E9=9B=BB=E7=AB=99=E6=94=B9=E7=82=BA=E8=B7=9F=E4=BA=A4?= =?UTF-8?q?=E5=8F=89=E5=88=86=E6=9E=90=E4=B8=AD=E7=9A=84=E5=B7=A6=E5=81=B4?= =?UTF-8?q?=E9=81=B8=E5=96=AE=E7=9B=B8=E5=90=8C=204.=20bug=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/StationOverviewController.cs | 8 +- .../Controllers/StationReportController.cs | 3 +- SolarPower/DBSchema/solar_power_schema.sql | 12 +- SolarPower/Models/AnalysisStationCombine.cs | 1 + SolarPower/Models/NoticeSchedule.cs | 1 + SolarPower/Models/Overview.cs | 2 + SolarPower/Quartz/Jobs/CalcPowerStationJob.cs | 9 +- SolarPower/Quartz/Jobs/SendEmailJob.cs | 70 +- .../AnalysisStationCombineRepository.cs | 14 +- .../Implement/OverviewRepository.cs | 17 +- .../Implement/PowerStationRepository.cs | 19 +- .../Interface/IPowerStationRepository.cs | 2 +- .../Views/AnalysisInverter/Index.cshtml | 2 +- .../Views/AnalysisStationCombine/Index.cshtml | 719 +++++++++--------- .../PowerStation/PowerStationEdit.cshtml | 159 ++-- SolarPower/Views/Shared/_Layout.cshtml | 4 +- SolarPower/Views/StationOverview/Index.cshtml | 1 + .../StationOverviewInfo.cshtml | 213 +++++- SolarPower/Views/StationReport/Index.cshtml | 2 +- SolarPower/appsettings.Development.json | 26 +- ...0f-43a0-924d-071bff9df54f.png => main.png} | Bin .../FIC太陽能監控平台_日報表_120210803.xlsx | Bin 4640 -> 4752 bytes .../FIC太陽能監控平台_日報表_220210803.xlsx | Bin 0 -> 5636 bytes .../FIC太陽能監控平台_日報表_320210803.xlsx | Bin 0 -> 4624 bytes .../FIC太陽能監控平台_日報表_420210803.xlsx | Bin 0 -> 4815 bytes 25 files changed, 802 insertions(+), 482 deletions(-) rename SolarPower/wwwroot/upload/power_station/1/{738117f3-640f-43a0-924d-071bff9df54f.png => main.png} (100%) create mode 100644 SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_220210803.xlsx create mode 100644 SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_320210803.xlsx create mode 100644 SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_420210803.xlsx diff --git a/SolarPower/Controllers/StationOverviewController.cs b/SolarPower/Controllers/StationOverviewController.cs index bc5d830..fdc4547 100644 --- a/SolarPower/Controllers/StationOverviewController.cs +++ b/SolarPower/Controllers/StationOverviewController.cs @@ -215,6 +215,7 @@ namespace SolarPower.Controllers powerIrradianceTodayChart.Labels = powerIrradianceToday.Select(x => x.Label).ToList(); powerIrradianceTodayChart.PowerDatas = powerIrradianceToday.Select(x => x.PowerData).ToList(); powerIrradianceTodayChart.IrradianceDatas = powerIrradianceToday.Select(x => x.IrradianceData).ToList(); + powerIrradianceTodayChart.TemperatureDatas = powerIrradianceToday.Select(x => x.TemperatureData).ToList(); chartUptoDate.ChartToday = powerIrradianceTodayChart; //7日發電量日照度List @@ -224,24 +225,27 @@ namespace SolarPower.Controllers powerIrradiance7dayChart.Labels = powerIrradiance7day.Select(x => x.Label).ToList(); powerIrradiance7dayChart.PowerDatas = powerIrradiance7day.Select(x => x.PowerData).ToList(); powerIrradiance7dayChart.IrradianceDatas = powerIrradiance7day.Select(x => x.IrradianceData).ToList(); + powerIrradiance7dayChart.TemperatureDatas = powerIrradiance7day.Select(x => x.TemperatureData).ToList(); chartUptoDate.Chart7day = powerIrradiance7dayChart; //本月發電量日照度List var powerIrradianceMonth = await overviewRepository.GetListPowerIrradianceMonthByPowerStationId(id, nowDay); - //今日資料轉換 + //本月資料轉換 PowerIrradianceChart powerIrradianceMonthChart = new PowerIrradianceChart(); powerIrradianceMonthChart.Labels = powerIrradianceMonth.Select(x => x.Label).ToList(); powerIrradianceMonthChart.PowerDatas = powerIrradianceMonth.Select(x => x.PowerData).ToList(); powerIrradianceMonthChart.IrradianceDatas = powerIrradianceMonth.Select(x => x.IrradianceData).ToList(); + powerIrradianceMonthChart.TemperatureDatas = powerIrradianceMonth.Select(x => x.TemperatureData).ToList(); chartUptoDate.ChartMonth = powerIrradianceMonthChart; //本年發電量日照度List var powerIrradianceYear = await overviewRepository.GetListPowerIrradianceYearByPowerStationId(id, nowDay); - //今日資料轉換 + //本月資料轉換 PowerIrradianceChart powerIrradianceYearChart = new PowerIrradianceChart(); powerIrradianceYearChart.Labels = powerIrradianceYear.Select(x => x.Label).ToList(); powerIrradianceYearChart.PowerDatas = powerIrradianceYear.Select(x => x.PowerData).ToList(); powerIrradianceYearChart.IrradianceDatas = powerIrradianceYear.Select(x => x.IrradianceData).ToList(); + powerIrradianceYearChart.TemperatureDatas = powerIrradianceYear.Select(x => x.TemperatureData).ToList(); chartUptoDate.ChartYear = powerIrradianceYearChart; apiResult.Code = "0000"; diff --git a/SolarPower/Controllers/StationReportController.cs b/SolarPower/Controllers/StationReportController.cs index acd4e08..e99c45b 100644 --- a/SolarPower/Controllers/StationReportController.cs +++ b/SolarPower/Controllers/StationReportController.cs @@ -7,6 +7,7 @@ using NPOI.SS.Util; using NPOI.XSSF.UserModel; using SolarPower.Models; using SolarPower.Models.PowerStation; +using SolarPower.Models.Role; using SolarPower.Repository.Interface; using System; using System.Collections.Generic; @@ -49,7 +50,7 @@ namespace SolarPower.Controllers } else { - powerStations = await powerStationRepository.GetPowerStationsByCompanyIdWithfilter(myUser.CompanyId,filter); + powerStations = await powerStationRepository.GetPowerStationsByCompanyIdWithfilter(myUser,filter); } var siteDBNamePowerStationId = new Dictionary>(); diff --git a/SolarPower/DBSchema/solar_power_schema.sql b/SolarPower/DBSchema/solar_power_schema.sql index 7ad62a7..e9d2291 100644 --- a/SolarPower/DBSchema/solar_power_schema.sql +++ b/SolarPower/DBSchema/solar_power_schema.sql @@ -428,12 +428,12 @@ INSERT INTO `auth_page` (`AuthCode`, `MainName`, `SubName`, `TagName`, `ControlN ('L', '交叉分析', '合併電站', NULL, 'AnalysisStationCombine'), ('M', '交叉分析', '電站交叉分析', NULL, 'AnalysisStationInfo'), ('N', '交叉分析', '逆變器交叉分析', NULL, 'AnalysisInverter'), - ('P', '報表查詢', '電站報表', NULL, 'CCC'), + ('P', '報表查詢', '電站報表', NULL, 'StationReport'), ('Q', '報表查詢', '電廠發電效能統計', NULL, 'HHH'), - ('R', '報表查詢', '輸入台電售電紀錄', NULL, 'JJJ'), + ('R', '報表查詢', '輸入台電售電紀錄', NULL, 'ElectricitySoldRecord'), ('S', '報表查詢', '報告發送設定', NULL, 'JJJ'), ('T', '即時告警', '異常事件查詢', NULL, 'KKK'), - ('U', '運維管理', '電站管理', NULL, 'PowerStationManager'), + ('U', '運維管理', '電站管理', NULL, 'PowerStation'), ('V', '運維管理', '定期計畫建立', NULL, 'Operation'), ('W', '運維管理', '運維作業記錄', NULL, 'OperationRecord'), ('X', '系統管理', '公司管理', NULL, 'Company'), @@ -1262,7 +1262,7 @@ CREATE TABLE IF NOT EXISTS `weather_description` ( `WeatherValue` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '分類代碼', `WeatherKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'icon代號', PRIMARY KEY (`Id`) -) ENGINE=InnoDB AUTO_INCREMENT=355 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='天氣描述分類'; +) ENGINE=InnoDB AUTO_INCREMENT=355 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='天氣描述分類'; -- 正在傾印表格 solar_power_test.weather_description 的資料:~0 rows (近似值) DELETE FROM `weather_description`; @@ -1636,7 +1636,7 @@ CREATE TABLE IF NOT EXISTS `weather_forecast` ( `CreatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`Id`), KEY `IDX_01` (`LocationName`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='天氣預報'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='天氣預報'; @@ -1648,7 +1648,7 @@ CREATE TABLE IF NOT EXISTS `weather_observation` ( `Temp` double DEFAULT NULL COMMENT '溫度', PRIMARY KEY (`Id`), KEY `IDX_01` (`PowerStationId`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='天氣觀測'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='天氣觀測'; diff --git a/SolarPower/Models/AnalysisStationCombine.cs b/SolarPower/Models/AnalysisStationCombine.cs index 2c480ce..d78b9f0 100644 --- a/SolarPower/Models/AnalysisStationCombine.cs +++ b/SolarPower/Models/AnalysisStationCombine.cs @@ -27,6 +27,7 @@ namespace SolarPower.Models public class Chartoutput { public double Irradiance { get; set; } + public double Temperature { get; set; } public double KWH { get; set; } public string Time { get; set; } } diff --git a/SolarPower/Models/NoticeSchedule.cs b/SolarPower/Models/NoticeSchedule.cs index f80d5a7..e121f95 100644 --- a/SolarPower/Models/NoticeSchedule.cs +++ b/SolarPower/Models/NoticeSchedule.cs @@ -16,6 +16,7 @@ namespace SolarPower.Models public string Attachment { get; set; } public byte IsDelivery { get; set; } public string DeliveryAt { get; set; } + public string Reason { get; set; } } public class OperationPersonnel diff --git a/SolarPower/Models/Overview.cs b/SolarPower/Models/Overview.cs index 640e473..e8abc06 100644 --- a/SolarPower/Models/Overview.cs +++ b/SolarPower/Models/Overview.cs @@ -77,6 +77,7 @@ namespace SolarPower.Models public string Label { get; set; } public double PowerData { get; set; } public double IrradianceData { get; set; } + public double TemperatureData { get; set; } } public class PowerIrradianceChart @@ -84,6 +85,7 @@ namespace SolarPower.Models public List Labels { get; set; } public List PowerDatas { get; set; } public List IrradianceDatas { get; set; } + public List TemperatureDatas { get; set; } } public class ExceptionSent diff --git a/SolarPower/Quartz/Jobs/CalcPowerStationJob.cs b/SolarPower/Quartz/Jobs/CalcPowerStationJob.cs index a37afa6..63c979c 100644 --- a/SolarPower/Quartz/Jobs/CalcPowerStationJob.cs +++ b/SolarPower/Quartz/Jobs/CalcPowerStationJob.cs @@ -194,7 +194,7 @@ namespace SolarPower.Quartz.Jobs logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的日照計設備資訊】", powerStation.Code, dateTime); logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的日照計設備資訊】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(deviceInfos)); - if (deviceInfos != null) + if (deviceInfos != null && deviceInfos.Count() > 0) { //2. 計算該電站所有日照計設的每小時的平均在依照日照計數量平均 logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的日照計的日照度】", powerStation.Code, dateTime); @@ -216,7 +216,7 @@ namespace SolarPower.Quartz.Jobs var tempdeviceInfos = await powerStationRepository.GetListTempByPowerStationId(powerStation.Id, powerStation.SiteDB); logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的溫度計設備資訊】", powerStation.Code, dateTime); logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的溫度計設備資訊】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(tempdeviceInfos)); - if (tempdeviceInfos != null) + if (tempdeviceInfos != null && tempdeviceInfos.Count() > 0) { logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的溫度計的平均溫度】", powerStation.Code, dateTime); var tempHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, tempdeviceInfos, 1); @@ -244,7 +244,7 @@ namespace SolarPower.Quartz.Jobs var full_inverter_table_name = String.Format("`{0}`.`{1}`", powerStation.SiteDB, inverter_table_name); var exist_inverter_table = await powerStationRepository.ExistTable(powerStation.SiteDB, inverter_table_name); - if (!string.IsNullOrEmpty(exist_inverter_table)) + if (!string.IsNullOrEmpty(exist_inverter_table) && inverterIds !=null && inverterIds.Count() > 0) { logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的逆變器的資訊】", powerStation.Code, dateTime); inverterHistories = await powerStationRepository.CalcInverterHisyortHourData(dateTime, powerStation.SiteDB, full_inverter_table_name, inverterIds); @@ -322,10 +322,11 @@ namespace SolarPower.Quartz.Jobs { if (Location.StationId == powerStation.WeathersStationId) { + calcPowerStation.TodayWeatherTemp = Convert.ToDouble(Location.WeatherElement[0].ElementValue); weatherObservation.PowerStationId = powerStation.Id; weatherObservation.Temp = Convert.ToDouble(Location.WeatherElement[0].ElementValue); - weatherObservation.ObsTime = Location.Time.ObsTime.ToString(); + weatherObservation.ObsTime = Convert.ToInt32(Location.Time.ObsTime.Substring(0, 4)) < 1970? null : Location.Time.ObsTime; calcPowerStation.WeathersStationId = powerStation.WeathersStationId; break; } diff --git a/SolarPower/Quartz/Jobs/SendEmailJob.cs b/SolarPower/Quartz/Jobs/SendEmailJob.cs index e5fb2df..3808b40 100644 --- a/SolarPower/Quartz/Jobs/SendEmailJob.cs +++ b/SolarPower/Quartz/Jobs/SendEmailJob.cs @@ -55,7 +55,7 @@ namespace SolarPower.Quartz.Jobs var result = Send(recipientEmails, notice.Subject, notice.Content, attachments); - if(result) + if (result.CompareTo("成功") == 0) { NoticeSchedule noticeSchedule = new NoticeSchedule(); noticeSchedule.Id = notice.Id; @@ -64,6 +64,16 @@ namespace SolarPower.Quartz.Jobs updateNoticeSchedules.Add(noticeSchedule); } + else + { + NoticeSchedule noticeSchedule = new NoticeSchedule(); + noticeSchedule.Id = notice.Id; + noticeSchedule.IsDelivery = 2; + noticeSchedule.DeliveryAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + noticeSchedule.Reason = result; + + updateNoticeSchedules.Add(noticeSchedule); + } List properties = new List() { @@ -83,8 +93,10 @@ namespace SolarPower.Quartz.Jobs } } - private bool Send(List recipientEmails, string subject, string content, List attachments) + private string Send(List recipientEmails, string subject, string content, List attachments) { + var reason = string.Empty; + var CanDoSend = true; MailMessage MyMail = new MailMessage(); MyMail.SubjectEncoding = System.Text.Encoding.UTF8;//郵件標題編碼 @@ -100,37 +112,53 @@ namespace SolarPower.Quartz.Jobs MyMail.Subject = subject; //主題 MyMail.Body = content; //設定信件內容 - foreach(var attachment in attachments) + foreach (var attachment in attachments) { var directoryBase = Directory.GetCurrentDirectory(); var filePath = @$"{directoryBase}\wwwroot{attachment}"; - var data = new Attachment(filePath); - MyMail.Attachments.Add(data); + if (File.Exists(filePath)) + { + var data = new Attachment(filePath); + MyMail.Attachments.Add(data); + } + else + { + CanDoSend = false; + reason = "失敗 - 檔案遺失"; + break; + } } //讀取 SMTP Config - SmtpClient MySMTP = new SmtpClient(smtp.Host, smtp.Port); - MySMTP.EnableSsl = smtp.EnableSsl; - MySMTP.Credentials = new System.Net.NetworkCredential(smtp.UserName, smtp.Password); - try + if (CanDoSend) { - MySMTP.Send(MyMail); - MySMTP.Dispose(); - MyMail.Dispose(); //釋放資源 + SmtpClient MySMTP = new SmtpClient(smtp.Host, smtp.Port); + MySMTP.EnableSsl = smtp.EnableSsl; + MySMTP.Credentials = new System.Net.NetworkCredential(smtp.UserName, smtp.Password); + try + { + MySMTP.Send(MyMail); + MySMTP.Dispose(); + MyMail.Dispose(); //釋放資源 - return true; + return "成功"; + } + catch (Exception ex) + { + string json = System.Text.Json.JsonSerializer.Serialize(recipientEmails); + logger.LogError("【SendEmailJob】 " + "寄送信件失敗"); + logger.LogError("【SendEmailJob】 - Emails:" + json); + logger.LogError("【SendEmailJob】 - Exception:" + ex.Message); + + return "失敗 - " + ex.Message; + } } - catch (Exception ex) + else { - string json = System.Text.Json.JsonSerializer.Serialize(recipientEmails); - logger.LogError("【SendEmailJob】 " + "寄送信件失敗"); - logger.LogError("【SendEmailJob】 - Emails:" + json); - logger.LogError("【SendEmailJob】 - Exception:" + ex.Message); - - return false; + return reason; } - + } } } diff --git a/SolarPower/Repository/Implement/AnalysisStationCombineRepository.cs b/SolarPower/Repository/Implement/AnalysisStationCombineRepository.cs index 5571d49..800b4d2 100644 --- a/SolarPower/Repository/Implement/AnalysisStationCombineRepository.cs +++ b/SolarPower/Repository/Implement/AnalysisStationCombineRepository.cs @@ -159,7 +159,10 @@ namespace SolarPower.Repository.Implement switch (post.SeacrhType) { case 0: - sql = $@"SELECT DATE_FORMAT(ps.TIMESTAMP,'%h %p') AS `Time`,SUM(ps.KWH) AS KWH,SUM(sh.Irradiance) AS Irradiance + sql = $@"SELECT DATE_FORMAT(ps.TIMESTAMP,'%h %p') AS `Time`, + SUM(ps.KWH) AS KWH, + SUM(sh.Irradiance) AS Irradiance, + AVG(sh.Temperature) AS Temperature FROM power_station_history_hour ps LEFT JOIN sensor_history_hour sh ON sh.TIMESTAMP = ps.TIMESTAMP AND sh.PowerStationId = ps.PowerStationId @@ -171,7 +174,8 @@ namespace SolarPower.Repository.Implement sql = $@"SELECT DATE_FORMAT(ps.TIMESTAMP,'%Y-%m-%d') AS `Time`, SUM(ps.TODAYKWH) AS KWH, - SUM(sh.Irradiance) AS Irradiance + SUM(sh.Irradiance) AS Irradiance, + AVG(sh.Temperature) AS Temperature FROM power_station_history_day ps LEFT JOIN sensor_history_day sh ON sh.TIMESTAMP = ps.TIMESTAMP @@ -182,7 +186,8 @@ namespace SolarPower.Repository.Implement sql = $@"SELECT DATE_FORMAT(ps.TIMESTAMP,'%Y-%m-%d') AS `Time`, SUM(ps.TODAYKWH) AS KWH, - SUM(sh.Irradiance) AS Irradiance + SUM(sh.Irradiance) AS Irradiance, + AVG(sh.Temperature) AS Temperature FROM power_station_history_day ps LEFT JOIN sensor_history_day sh ON sh.TIMESTAMP = ps.TIMESTAMP @@ -193,7 +198,8 @@ namespace SolarPower.Repository.Implement sql = $@"SELECT DATE_FORMAT(ps.TIMESTAMP,'%Y-%m') AS `Time`, SUM(ps.MONTHKWH) AS KWH, - SUM(sh.Irradiance) AS Irradiance + SUM(sh.Irradiance) AS Irradiance, + AVG(sh.Temperature) AS Temperature FROM power_station_history_month ps LEFT JOIN sensor_history_month sh ON sh.TIMESTAMP = ps.TIMESTAMP diff --git a/SolarPower/Repository/Implement/OverviewRepository.cs b/SolarPower/Repository/Implement/OverviewRepository.cs index 8eaf39e..d9ecd60 100644 --- a/SolarPower/Repository/Implement/OverviewRepository.cs +++ b/SolarPower/Repository/Implement/OverviewRepository.cs @@ -110,11 +110,16 @@ namespace SolarPower.Repository.Implement var dateNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var sql = @$"SELECT - w.Wx, + wf.Wx, ps.* FROM power_station ps LEFT JOIN city c ON ps.CityId = c.Id - LEFT JOIN weather_forecast w ON c.Name = w.LocationName AND w.StartTime < @DateNow AND w.EndTime > @DateNow + LEFT JOIN (SELECT * FROM ( + SELECT MAX(w.Id) AS aa FROM weather_forecast w + WHERE w.StartTime < @DateNow AND w.EndTime > @DateNow + GROUP BY w.LocationName + ) A + LEFT JOIN weather_forecast B ON A.aa = B.Id) wf ON c.Name = wf.LocationName WHERE ps.Id IN @PowerStationIds "; @@ -206,7 +211,7 @@ namespace SolarPower.Repository.Implement { try { - var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp,'%H %p') AS Label, ps.KWH AS PowerData, pyr.Irradiance AS IrradianceData + var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp,'%H %p') AS Label, ps.KWH AS PowerData, pyr.Irradiance AS IrradianceData, pyr.Temperature AS TemperatureData FROM power_station_history_hour ps LEFT JOIN sensor_history_hour pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d %H') = DATE_FORMAT(pyr.timestamp, '%Y-%m-%d %H') WHERE ps.PowerStationId = @PowerStationId @@ -231,7 +236,7 @@ namespace SolarPower.Repository.Implement { var startDay = Convert.ToDateTime(nowDay).AddDays(-7).ToString("yyyy-MM-dd"); - var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData + var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData, pyr.Temperature AS TemperatureData FROM power_station_history_day ps LEFT JOIN sensor_history_day pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') = DATE_FORMAT(pyr.timestamp, '%Y-%m-%d') WHERE ps.PowerStationId = @PowerStationId @@ -256,7 +261,7 @@ namespace SolarPower.Repository.Implement { var startDay = Convert.ToDateTime(nowDay).ToString("yyyy-MM-01"); - var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData + var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData, pyr.Temperature AS TemperatureData FROM power_station_history_day ps LEFT JOIN sensor_history_day pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') = DATE_FORMAT(pyr.timestamp, '%Y-%m-%d') WHERE ps.PowerStationId = @PowerStationId @@ -282,7 +287,7 @@ namespace SolarPower.Repository.Implement { var startyear = Convert.ToDateTime(nowDay).ToString("yyyy"); - var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m') AS Label, ps.MONTHKWH AS PowerData, pyr.Irradiance AS IrradianceData + var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m') AS Label, ps.MONTHKWH AS PowerData, pyr.Irradiance AS IrradianceData, pyr.Temperature AS TemperatureData FROM power_station_history_month ps LEFT JOIN sensor_history_month pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m') = DATE_FORMAT(pyr.timestamp, '%Y-%m') WHERE ps.PowerStationId = @PowerStationId diff --git a/SolarPower/Repository/Implement/PowerStationRepository.cs b/SolarPower/Repository/Implement/PowerStationRepository.cs index b67b99f..f155e30 100644 --- a/SolarPower/Repository/Implement/PowerStationRepository.cs +++ b/SolarPower/Repository/Implement/PowerStationRepository.cs @@ -3287,7 +3287,7 @@ namespace SolarPower.Repository.Implement FROM city c LEFT JOIN weather_forecast wf ON wf.LocationName = c.`Name` LEFT JOIN weather_description wd ON wd.WeatherName = wf.Wx - WHERE c.Priority = {CityId} AND '{now}' BETWEEN wf.StartTime AND wf.EndTime ORDER BY wf.CreatedAt desc"; + WHERE c.Id = {CityId} AND '{now}' BETWEEN wf.StartTime AND wf.EndTime ORDER BY wf.CreatedAt desc"; result = await conn.QueryFirstOrDefaultAsync(sql); } @@ -3754,7 +3754,7 @@ namespace SolarPower.Repository.Implement FROM power_station ps LEFT JOIN `city` c ON ps.CityId = c.Id LEFT JOIN {powerStationDic.Key}.controller con ON ps.Id = con.PowerStationId - LEFT JOIN {powerStationDic.Key}.inverter inv ON con.Id = inv.ControllerId + LEFT JOIN {powerStationDic.Key}.inverter inv ON con.Id = inv.ControllerId AND inv.Enabled = 1 AND inv.status != 0 WHERE ps.Deleted = 0 AND ps.Id IN ({powerStationIds})"; if (!string.IsNullOrEmpty(filter)) @@ -4010,7 +4010,7 @@ namespace SolarPower.Repository.Implement } - public async Task> GetPowerStationsByCompanyIdWithfilter(int companyId, string filter) + public async Task> GetPowerStationsByCompanyIdWithfilter(MyUser myUser, string filter) { List result; using (IDbConnection conn = this._databaseHelper.GetConnection()) @@ -4018,14 +4018,23 @@ namespace SolarPower.Repository.Implement try { var sql = $@"SELECT ps.Id AS PowerStationId , ps.`Name` AS PowerStationName,city.Name AS CityName FROM {tableName} ps - LEFT JOIN city ON city.Id = ps.CityId WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId "; + LEFT JOIN city ON city.Id = ps.CityId"; + if (myUser.Role.Layer == 2) + { + sql += " WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId "; + } + else + { + sql += @" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId + WHERE ps.Deleted = 0 AND op.Deleted = 0 AND op.UserId = @UserId "; + } if (!string.IsNullOrEmpty(filter)) { sql += @" AND ps.Name LIKE CONCAT('%', @Filter, '%')"; } - result = (await conn.QueryAsync(sql, new { CompanyId = companyId, Filter = filter })).ToList(); + result = (await conn.QueryAsync(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id, Filter = filter })).ToList(); } catch (Exception exception) { diff --git a/SolarPower/Repository/Interface/IPowerStationRepository.cs b/SolarPower/Repository/Interface/IPowerStationRepository.cs index 51e7d95..4fdd185 100644 --- a/SolarPower/Repository/Interface/IPowerStationRepository.cs +++ b/SolarPower/Repository/Interface/IPowerStationRepository.cs @@ -552,7 +552,7 @@ namespace SolarPower.Repository.Interface Task> GetInverterHistoryRowData(string nowDay, List entities); Task> GetInverterHistoryByDate(string startDay, string endDay, List entities); Task> GetInverterHistoryByYear(string year, List entities); - Task> GetPowerStationsByCompanyIdWithfilter(int companyId, string filter); + Task> GetPowerStationsByCompanyIdWithfilter(MyUser myUser, string filter); Task> GetPowerStationsAllWithfilter(string filter); Task> GetDeviceByPowerStationIdAndDeviceIds(string db_name, int powerStationId, List deviceIds); Task GetSensorAvgByDevices(string date, byte searchType, List devices); diff --git a/SolarPower/Views/AnalysisInverter/Index.cshtml b/SolarPower/Views/AnalysisInverter/Index.cshtml index 312c60d..76adb1f 100644 --- a/SolarPower/Views/AnalysisInverter/Index.cshtml +++ b/SolarPower/Views/AnalysisInverter/Index.cshtml @@ -429,7 +429,7 @@ $.post(url, send_data, function (rel) { if (rel.code != "0000") { - toast_error(rel.data.msg); + toast_error(rel.msg); return; } diff --git a/SolarPower/Views/AnalysisStationCombine/Index.cshtml b/SolarPower/Views/AnalysisStationCombine/Index.cshtml index 23d75bc..a9c6d13 100644 --- a/SolarPower/Views/AnalysisStationCombine/Index.cshtml +++ b/SolarPower/Views/AnalysisStationCombine/Index.cshtml @@ -6,196 +6,226 @@ @using SolarPower.Models.Role @model RoleLayerEnum - -
-

- 合併電站 -

-
-
-
-
-
-
-
-
- -
-
- -
+
+
+ -
+ +
+ +
+ +
+ +
+

+ 合併電站 +

+
+ +
+
+
+
+
+ @*
+
+ +
+
+ +
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
*@ + +
+
+
+ + + + +
+
+
+ + +
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+

發電量

+
kW h
+
+
+
+

總發電量

+

126,161.72

+
+
+

今日發電量

+

4,069.73

+
+
+
+
+
+

發電金額

+
NTD
+
+
+
+

總發金額

+

126,161.72

+
+
+

今日發電金額

+

4,069.73

+
+
+
+ +
+
+

有效日照時數

+
hr
+
+
+
+

平均有效日照時數

+

140.39

+
+
+

今日有效日照時數

+

4.53

+
+
+
+
+
+

PR值

+
%
+
+
+
+

平均 PR 值

+

119.04

+
+
+

今日PR值

+

3.84

+
+
+
+ +
+
+

減碳量

+
kG
+
+
+
+

總減碳量

+

6,091.78

+
+
+

今日減碳量

+

985.98

+
+
+
+
+
+ +
+ +
+
+ +
+
+
+ +
+ + +
+
+
+
+
+
+ + + @section Scripts{ -} \ No newline at end of file +} diff --git a/SolarPower/Views/PowerStation/PowerStationEdit.cshtml b/SolarPower/Views/PowerStation/PowerStationEdit.cshtml index a39bb8f..e009f6a 100644 --- a/SolarPower/Views/PowerStation/PowerStationEdit.cshtml +++ b/SolarPower/Views/PowerStation/PowerStationEdit.cshtml @@ -967,54 +967,127 @@ $("#power_station_operation_personnel").select2(); + var ps_company_text = $("#select_power_station_company").find(':selected').text(); - var url = "/PowerStation/SavePowerStationInfo"; + @if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformUser) + { + + Swal.fire( + { + title: "", + text: "你確定是否要將該電站加入至【" + ps_company_text + "】?", + type: "question", + icon: 'question', + showCancelButton: true, + confirmButtonText: "是", + cancelButtonText: "否" + }).then(function (result) { + if (result.value) { + var url = "/PowerStation/SavePowerStationInfo"; - var send_data = { - Id: stationId, - CityId: $("#select_city").val(), - AreaId: $("#select_area").val(), - Address: $("#address_detail").val(), - Name: $("#power_station_name").val(), - IsEscrow: $('#check_escrow').is(':checked') ? 1 : 0, - ElectricityMeterAt: $("#electricity_meter_at").val(), - EstimatedRecoveryTime: $("#estimated_recovery_time").val(), - GeneratingCapacity: $("#generating_capacity").val(), - EscrowName: $('#check_escrow').is(':checked') ? $("#escrow_name").val() : "", - PowerRate: $("#power_rate").val(), - Coordinate: $("#coordinate").val(), - OperationPersonnelIds: $("#power_station_operation_personnel").val(), - InverterBrand: $("#inverter_brand").val(), - InverterProductModel: $("#inverter_product_model").val(), - InverterAmount: $("#inverter_amount").val(), - PhotovoltaicPanelBrand: $("#photovoltaic_panel_brand").val(), - PhotovoltaicPanelSpecification: $("#photovoltaic_panel_specification").val(), - PhotovoltaicPanelAmount: $("#photovoltaic_panel_amount").val(), - PhotovoltaicPanelProductModel: $("#photovoltaic_panel_product_model").val(), - SolarType: $("#select_solar_tpye").val(), - line_token: $("#line_token").val(), - Estimate_kwh: $("#estimate_kwh").val(), - EstimateEfficacy: $("#estimate_efficacy").val(), - CompanyId: $("#select_power_station_company").val(), + var send_data = { + Id: stationId, + CityId: $("#select_city").val(), + AreaId: $("#select_area").val(), + Address: $("#address_detail").val(), + Name: $("#power_station_name").val(), + IsEscrow: $('#check_escrow').is(':checked') ? 1 : 0, + ElectricityMeterAt: $("#electricity_meter_at").val(), + EstimatedRecoveryTime: $("#estimated_recovery_time").val(), + GeneratingCapacity: $("#generating_capacity").val(), + EscrowName: $('#check_escrow').is(':checked') ? $("#escrow_name").val() : "", + PowerRate: $("#power_rate").val(), + Coordinate: $("#coordinate").val(), + OperationPersonnelIds: $("#power_station_operation_personnel").val(), + InverterBrand: $("#inverter_brand").val(), + InverterProductModel: $("#inverter_product_model").val(), + InverterAmount: $("#inverter_amount").val(), + PhotovoltaicPanelBrand: $("#photovoltaic_panel_brand").val(), + PhotovoltaicPanelSpecification: $("#photovoltaic_panel_specification").val(), + PhotovoltaicPanelAmount: $("#photovoltaic_panel_amount").val(), + PhotovoltaicPanelProductModel: $("#photovoltaic_panel_product_model").val(), + SolarType: $("#select_solar_tpye").val(), + line_token: $("#line_token").val(), + Estimate_kwh: $("#estimate_kwh").val(), + EstimateEfficacy: $("#estimate_efficacy").val(), + CompanyId: $("#select_power_station_company").val(), + } + + $.post(url, send_data, function (rel) { + if (rel.code != "0000") { + toast_error(rel.msg); + return; + } + + toast_ok(rel.msg); + + if (stationId == "new") { + window.location = "/PowerStation/Edit?stationId=" + rel.data.id + } else { + //回填資料 + powerStationData = rel.data; + SetStationInfo(); + ChangeMode("station_info", "view"); + } + }, 'json'); + } + }); + + } + else + { + + var url = "/PowerStation/SavePowerStationInfo"; + + var send_data = { + Id: stationId, + CityId: $("#select_city").val(), + AreaId: $("#select_area").val(), + Address: $("#address_detail").val(), + Name: $("#power_station_name").val(), + IsEscrow: $('#check_escrow').is(':checked') ? 1 : 0, + ElectricityMeterAt: $("#electricity_meter_at").val(), + EstimatedRecoveryTime: $("#estimated_recovery_time").val(), + GeneratingCapacity: $("#generating_capacity").val(), + EscrowName: $('#check_escrow').is(':checked') ? $("#escrow_name").val() : "", + PowerRate: $("#power_rate").val(), + Coordinate: $("#coordinate").val(), + OperationPersonnelIds: $("#power_station_operation_personnel").val(), + InverterBrand: $("#inverter_brand").val(), + InverterProductModel: $("#inverter_product_model").val(), + InverterAmount: $("#inverter_amount").val(), + PhotovoltaicPanelBrand: $("#photovoltaic_panel_brand").val(), + PhotovoltaicPanelSpecification: $("#photovoltaic_panel_specification").val(), + PhotovoltaicPanelAmount: $("#photovoltaic_panel_amount").val(), + PhotovoltaicPanelProductModel: $("#photovoltaic_panel_product_model").val(), + SolarType: $("#select_solar_tpye").val(), + line_token: $("#line_token").val(), + Estimate_kwh: $("#estimate_kwh").val(), + EstimateEfficacy: $("#estimate_efficacy").val(), + CompanyId: $("#select_power_station_company").val(), + } + + $.post(url, send_data, function (rel) { + if (rel.code != "0000") { + toast_error(rel.msg); + return; + } + + toast_ok(rel.msg); + + if (stationId == "new") { + window.location = "/PowerStation/Edit?stationId=" + rel.data.id + } else { + //回填資料 + powerStationData = rel.data; + SetStationInfo(); + ChangeMode("station_info", "view"); + } + }, 'json'); + } - $.post(url, send_data, function (rel) { - if (rel.code != "0000") { - toast_error(rel.msg); - return; - } - toast_ok(rel.msg); - - if (stationId == "new") { - window.location = "/PowerStation/Edit?stationId=" + rel.data.id - } else { - //回填資料 - powerStationData = rel.data; - SetStationInfo(); - ChangeMode("station_info", "view"); - } - }, 'json'); } //#endregion diff --git a/SolarPower/Views/Shared/_Layout.cshtml b/SolarPower/Views/Shared/_Layout.cshtml index 0c6beb6..b69ef46 100644 --- a/SolarPower/Views/Shared/_Layout.cshtml +++ b/SolarPower/Views/Shared/_Layout.cshtml @@ -1252,8 +1252,8 @@
- - + + diff --git a/SolarPower/Views/StationOverview/Index.cshtml b/SolarPower/Views/StationOverview/Index.cshtml index b44c6b6..9a29d96 100644 --- a/SolarPower/Views/StationOverview/Index.cshtml +++ b/SolarPower/Views/StationOverview/Index.cshtml @@ -398,6 +398,7 @@ default: console.log(`Sorry, we are out of ${val.solarType}.`); } + $('#card_' + val.id).find('#editSolarUrl').find('#Solarimg').attr('src', val.mainDisplay); $('#card_' + val.id).find('#stationtype').html(type); var time = new Date(val.createdAt); $('#card_' + val.id).find('#editSolarUrl').attr('href', localurl + '/Info?stationId=' + val.id); diff --git a/SolarPower/Views/StationOverview/StationOverviewInfo.cshtml b/SolarPower/Views/StationOverview/StationOverviewInfo.cshtml index b101d7a..9980a74 100644 --- a/SolarPower/Views/StationOverview/StationOverviewInfo.cshtml +++ b/SolarPower/Views/StationOverview/StationOverviewInfo.cshtml @@ -303,7 +303,7 @@ label: '輸出功率', yAxisID: 'A', backgroundColor: 'rgb(103, 180, 172)', - order: 2, + order: 3, data: chartToday.powerDatas }, { type: 'line', @@ -317,8 +317,22 @@ pointRadius: 4, pointHoverRadius: 5, fill: false, - order: 1, + order: 2, data: chartToday.irradianceDatas, + }, { + type: 'line', + label: '模組溫度', + yAxisID: 'C', + borderColor: 'rgb(255, 192, 0)', + pointBackgroundColor: 'rgb(255, 192, 0)', + pointBorderColor: 'rgb(255, 192, 0)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + order: 1, + data: chartToday.temperatureDatas, }] }, options: { @@ -353,6 +367,17 @@ display: true, labelString: 'W/㎡' } + }, { + id: 'C', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: '℃' + } }] } } @@ -370,7 +395,7 @@ label: '輸出功率', yAxisID: 'A', backgroundColor: 'rgb(103, 180, 172)', - order: 2, + order: 3, data: chart7day.powerDatas }, { type: 'line', @@ -383,9 +408,23 @@ borderWidth: 2, pointRadius: 4, pointHoverRadius: 5, - order: 1, + order: 2, fill: false, data: chart7day.irradianceDatas, + }, { + type: 'line', + label: '模組溫度', + yAxisID: 'C', + borderColor: 'rgb(255, 192, 0)', + pointBackgroundColor: 'rgb(255, 192, 0)', + pointBorderColor: 'rgb(255, 192, 0)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + order: 1, + data: chart7day.temperatureDatas, }] }, options: { @@ -420,6 +459,17 @@ display: true, labelString: 'W/㎡' } + }, { + id: 'C', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: '℃' + } }] } } @@ -437,7 +487,7 @@ label: '輸出功率', yAxisID: 'A', backgroundColor: 'rgb(103, 180, 172)', - order: 2, + order: 3, data: chartMonth.powerDatas }, { type: 'line', @@ -450,9 +500,23 @@ borderWidth: 2, pointRadius: 4, pointHoverRadius: 5, - order: 1, + order: 2, fill: false, data: chartMonth.irradianceDatas, + }, { + type: 'line', + label: '模組溫度', + yAxisID: 'C', + borderColor: 'rgb(255, 192, 0)', + pointBackgroundColor: 'rgb(255, 192, 0)', + pointBorderColor: 'rgb(255, 192, 0)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + order: 1, + data: chartMonth.temperatureDatas, }] }, options: { @@ -487,6 +551,17 @@ display: true, labelString: 'W/㎡' } + }, { + id: 'C', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: '℃' + } }] } } @@ -520,6 +595,20 @@ order: 1, fill: false, data: chartYear.irradianceDatas, + }, { + type: 'line', + label: '模組溫度', + yAxisID: 'C', + borderColor: 'rgb(255, 192, 0)', + pointBackgroundColor: 'rgb(255, 192, 0)', + pointBorderColor: 'rgb(255, 192, 0)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + order: 1, + data: chartYear.temperatureDatas, }] }, options: { @@ -554,6 +643,17 @@ display: true, labelString: 'W/㎡' } + }, { + id: 'C', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: '℃' + } }] } } @@ -2216,6 +2316,9 @@ var listcolor = new Array(0); var listcolor2 = new Array(0); var listirradiance = new Array(0); + var listtemperature = new Array(0); + var listsolarhour = new Array(0); + var listpr = new Array(0); var color = rgba(1); var color2 = rgba(2); $.each(rel.data, function (index, val) { @@ -2241,10 +2344,13 @@ '' + val.temp.toFixed(2) + '' + ''); listmonth.push(val.timestamp); - listkwh.push(val.kwh); + listkwh.push(val.kwh.toFixed(2)); listcolor.push(color); listcolor2.push(color2); - listirradiance.push(val.irradiance); + listirradiance.push(val.irradiance.toFixed(2)); + listtemperature.push(val.temp.toFixed(2)); + listsolarhour.push(val.solarhour.toFixed(2)); + listpr.push(val.pr.toFixed(2)); } else { @@ -2259,10 +2365,13 @@ '' + val.temp.toFixed(2) + '' + ''); listmonth.push(val.timestamp); - listkwh.push(val.kwh); + listkwh.push(val.kwh.toFixed(2)); listcolor.push(color); listcolor2.push(color2); - listirradiance.push(val.irradiance); + listirradiance.push(val.irradiance.toFixed(2)); + listtemperature.push(val.temp.toFixed(2)); + listsolarhour.push(val.solarhour.toFixed(2)); + listpr.push(val.pr.toFixed(2)); } @@ -2280,12 +2389,57 @@ type: 'bar', data: { labels: listmonth, - datasets: [{ + datasets: [ + { + type: 'line', + label: '溫度(℃)', + yAxisID: 'E', + borderColor: 'rgb(255, 192, 0)', + pointBackgroundColor: 'rgb(255, 192, 0)', + pointBorderColor: 'rgb(255, 192, 0)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + data: listtemperature + },{ + type: 'line', + label: 'PR(%)', + yAxisID: 'D', + borderColor: 'rgba(68, 114, 196)', + pointBackgroundColor: 'rgb(68, 114, 196)', + pointBorderColor: 'rgb(68, 114, 196)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + data: listpr + },{ + type: 'line', + label: '發電小時', + yAxisID: 'C', + borderColor: 'rgba(165, 165, 165)', + pointBackgroundColor: 'rgb(165, 165, 165)', + pointBorderColor: 'rgb(165, 165, 165)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, + fill: false, + data: listsolarhour + },{ type: 'line', label: '日照度(kWh/㎡)', - borderColor: 'rgba(190, 45, 45,1)', - pointRadius: 4, yAxisID: 'B', + borderColor: 'rgba(190, 45, 45,1)', + pointBackgroundColor: 'rgb(190, 45, 45,1)', + pointBorderColor: 'rgb(190, 45, 45,1)', + pointBorderWidth: 1, + borderWidth: 2, + pointRadius: 4, + pointHoverRadius: 5, fill: false, data: listirradiance }, { @@ -2329,6 +2483,39 @@ display: true, labelString: 'kWh/㎡' } + }, { + id: 'C', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: 'hr' + } + }, { + id: 'D', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: 'PR(%)' + } + }, { + id: 'E', + type: 'linear', + position: 'right', + ticks: { + min: 0 + }, + scaleLabel: { + display: true, + labelString: '℃' + } }] } } diff --git a/SolarPower/Views/StationReport/Index.cshtml b/SolarPower/Views/StationReport/Index.cshtml index fa84ed5..12d5210 100644 --- a/SolarPower/Views/StationReport/Index.cshtml +++ b/SolarPower/Views/StationReport/Index.cshtml @@ -557,7 +557,7 @@ $.post(url, send_data, function (rel) { if (rel.code != "0000") { - toast_error(rel.data.msg); + toast_error(rel.msg); return; } diff --git a/SolarPower/appsettings.Development.json b/SolarPower/appsettings.Development.json index 626a1a5..226ca35 100644 --- a/SolarPower/appsettings.Development.json +++ b/SolarPower/appsettings.Development.json @@ -7,26 +7,26 @@ } }, "LoginExpireMinute": 60, //nJɶA() - //"DBConfig": { - // "Server": "MVgHWzR3rGDgD57TUoFunA==", - // "port": "r4AoXMUDodcQjIzofGNCcg==", - // "Database": "z8TVtiXZ6MwgWbUEAOXA/fiHzd7c0iUhFqn1mHzxhKo=", - // "Root": "mWlR2HshQNhRRE34jg4kdg==", - // "Password": "y4uPqlH9ncTgR/I07qpwaA==" - //}, "DBConfig": { - "Server": "AVXfxd+IRlLtJ0MCi9HU1g==", - "port": "CrEmevYrUsSo7Mkb7Gxn8A==", - "Database": "CEyYZnO8B5+yTXQcFSsiBA==", - "Root": "Aph7AzoiwAmmBHCfS1rqeQ==", - "Password": "8WMHBEWuT0XoAB4kzduQHA==" + "Server": "MVgHWzR3rGDgD57TUoFunA==", + "port": "r4AoXMUDodcQjIzofGNCcg==", + "Database": "z8TVtiXZ6MwgWbUEAOXA/fiHzd7c0iUhFqn1mHzxhKo=", + "Root": "mWlR2HshQNhRRE34jg4kdg==", + "Password": "y4uPqlH9ncTgR/I07qpwaA==" }, + //"DBConfig": { + // "Server": "AVXfxd+IRlLtJ0MCi9HU1g==", + // "port": "CrEmevYrUsSo7Mkb7Gxn8A==", + // "Database": "CEyYZnO8B5+yTXQcFSsiBA==", + // "Root": "Aph7AzoiwAmmBHCfS1rqeQ==", + // "Password": "8WMHBEWuT0XoAB4kzduQHA==" + //}, "BackgroundServiceCron": { "CalcPowerStationJob": "0 5 * * * ?", "CalcAvgPowerStationJob": "0 0 2 * * ?", "OperationScheduleJob": "0 0 2 * * ?", "CalcInverter15minJob": "0 2/15 * * * ?", - "SendEmailJob": "0/10 * * * * ?" + "SendEmailJob": "0 15 2 * * ?" }, "SMTPConfig": { "Host": "smtp.gmail.com", diff --git a/SolarPower/wwwroot/upload/power_station/1/738117f3-640f-43a0-924d-071bff9df54f.png b/SolarPower/wwwroot/upload/power_station/1/main.png similarity index 100% rename from SolarPower/wwwroot/upload/power_station/1/738117f3-640f-43a0-924d-071bff9df54f.png rename to SolarPower/wwwroot/upload/power_station/1/main.png diff --git a/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_120210803.xlsx b/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_120210803.xlsx index 1ba9b218e7bb6fbfd267c9ca8786b89b1f844834..edcf25b0f24d4b99e86d4113f5c9e1b6e1cb9a75 100644 GIT binary patch delta 2121 zcmZ8ic{CJy6rM4Y8C%B4ma#UKW$X&`Y?UlY$z+R?WymttWRS)(gG6K|G|V6q$reWO zl(B>;64_HsdDhHBhKK6$&UvTz`u%gy`JH>uz3034`@RBX#z8?_YY=!J004jjD5PpZ zDIgDpRC^d0{!gUyhybA!5*U+o_sA#mQ;-UQiD3|*)Y^hu@_`V_DCz5&l9BBUuf>f3 z_3KEt7Uob2yZ>S+C&Kv5%dG{M2IDT{DDwq$g-YfjirGVAAbQZ@^Xz)av7vBfW_#Ko zZw06Cq(Tuwv{(_s5dsCXV>26(FcsAL*r}zq!6%pN@ocr@=5tb(U!P6U+mup!JP63z z8j)N52%HJue&9%v*|ZG9ivMG|h3Z6poNsN$;bFCRnu1-Asr7wIq|V%hth*=?QRfAV`r7qHm<`$q~MSF`%^A#DmZY_{CgDPo+-|uD#E%}oO^acchN=~Ry+OS9R(YE<7 zSwk)&hnJVW8L?(2Nn5gn*})SZF=(Vmps7%SILsDWmyl?k%R4eL>RJgPg`Aci5m3@< z7I8N%rJ_AuMb32#P6iWX{b1VT3dY_fdF1)i+=Q2%u85*TUhZbW2?oUAj|nG<-F=O;W5ThmTla_V4E0+`_-`V`z}tBH__l6=^Rm+P)rhLR<7>>&4`$x z0+PT^ib>TYK~>$&SSh>>Z{^G81^D9>ugL)E)THMOLLT?yA?)xctEbsP&b|GLEzBRX z`S}OWX8)CU+W1Dy?V#Vg260hQa_LJe;@iJVqU7EsPtet$O|lm~#|NVYP1q|9hvk1(0MO!Y=yRgBORd?VukD0sw?}t{5Mn z5fK#X?-3N_ua3tBJRrY0!=nZ3aCZ_Px)GC(p;%TtBt3w;L%&=xu+APo?XT*|5%%<66T<8~QFwNtfj$RnTDBE-iL? zVy$JVM2fkYR_StLU)`4GYdoq!U+0s5(KPr1`a$jw&Vo*p?s3}sL ze4`=JgMp9Gf7?-mOt8*A2DvMK0c=#DNg&q2bFMKcpNI5yxH!`v;OAjKVl(A8$npKM zmgq#}YwTLQkP13O4Cj0fBrwbJ1>%CI;+VZz;_PCug?M#qE(U*6HBZ`VNx;ce%d?+j zFFS09at$jOQ+$(o>rtQw;@ky;OgFlJPn0=T`C;7Pz`{)1YUlX3;V+-&{|H=D`pzR) zR3kiaihs0{NRlbGfJr;M%u87^#5n}e|F+d5AP9u-ZfkQ{ly9B~0EiF(03-qAKSlNv zXjyZCMVk9aZhMwlKv8+Cy9~dvIc*)9!xt1wMzckw2D<8SZI8WEft|x#E?}YXy?+zgnwF`1Y(Zhnjd^Unry%Q=@5;tXq|}Y9ztYK4c~} zd3L%r^=`Minl-PMyVGsFx!uM=cDy@b52m`>>kxFWfT%U9^GVDtcPjPZlwDriM4Uv+hia5S4aDd~^mD_-(HDC7Fxr*-U(__PzPZzuZcE{*RmC_BXL@ly@lf;Vb5ysVunVhlm}2QM?aYdeF~`?qDM28a1>Lo+SjNC$3DByf z!h{z|YcdwLM5o0_We^a*`5*J3j?~)(yl*NQSQw1;(oS95Up~Bkb&R#r+p#G$#EC`^ z2TbRu(R4?wOx7oIeO3tN;i1vq_!IQUBYo%h^WALrN(U%(n{YkK@eZj4!v2+$+$tX} zL(sIa3Kz<4NDi|SEG3k)0NxhlRdkQ>9)fsV<-S1w4;7MUp`qw1o2PKuL}7yN15y=BD>omMFhd~ eT7WzufKdH)zW+1!XDt9QM&^j9@^0>mF5qv7=(Upo delta 1975 zcmZ8idpHwp8{fex7PH7PBNHLEInT(8Wh^m1#}4v3g+hfyHM}eqQNycj6hlrUBd2yT zYAWXNA#!?0ujH_oLPY7K?|Z-czUQC&xvuBFpZmIg_wWAwGBq9`AkGA^kPH9-5CZ_9 zk0A;`5CF>31V(+2`5zv7 z#(BMK2p>*ev^IsHb_=m?4%htit$^(bkCJ0QSh*1Ha0u3O(6GGvoX{L4?a#-ht18Qz-+=po1z_Q2itextL+u{nF&DJuqj_}UzVuM9Vu zgsS!Os=x(HG4q7#L5t2sYElQKmw7OZ;2Y#PH5t1Z{gCX7Cr3_Os{=DkhSyy`HyY(L zh^D36OBdWw9=vQDdr!NE&L^t(6Qb{98MAU@1ox^9hiBMZSDR(Mdaimp34eK&(O!Lh zseFt#F@)EZ6aMn0YTgw96anl4CH6N`tXUybpyVzz_7f+Mf});6m#*w&-r!w0tfxOdt9ZR}FFTFm=r z`gZ;Ni;ElYX9Cf6%~YLJX_%n-KvY2*{RtLzE;Yp#CmRa(sI*4=`RWvFgnjCi(&TPq zd(s$Gf}0HL6rKE-nfMhnk( zlaqhrCMluj*^v@sH5W`Se2x`ftNg$R%j-{CY#0`1OzAdOk|j8df_rmIN9iZb*~vZq z$1&BF_Q+6|G={XXTOf^J(Y3#fWU32qme_U{1; zEg86NP)eR#n(`+6y$zFwgjLDf9==WFUm3V@xYEJ~@+LvwQ|X9uofxJFS*NXm6ySq3 zXlv0j_v5$s#LjM~!MNLuvs03Y12(Y0@@pJL*#o2(lqZ#s$f(V5#UdkSlxh{bxIW@^ zBKYQp;fQMtPLmDSk}j!<|CP%aJ8Z$srfqFnHQ^GZ^j|gGN7x3>;cr}J8dWGLFdvGz zuUEsbNL7@s53LA>$9S_{>WKwJ%<6!PM3X0{eQiKp>~`gmA&8bs*_EFr1K!aM)`$cI z2-_VE9Juu;83X`W?#PKefO;0DNTO%I2^&K~aU>i+PS-0>&=#Fp9K7OOhi}HZ$^=NO z;Sw0XuP&Gu`g4sX22uRvtR)MBB8C2yJUX94*5>)MtlkonK%-Ev+Q53Nqa^GZN8*FM zVGi8^HgfONLn2wU@Z#7ZqvAsVQjy#v;}W){jbn&*jmpa$<7I+Ib{k3LNr>#cJMok^ zmG7&JyQ+l@b#`iWpGEq+p{(HuFNx7yl|rpfk=kLS(6#(SFU(96h8CLH2VLsowd8}| z@vMoeFV+Ui?}*DOmrtg<9#5nvdO()^;oLLp2lpJy8mvXDt4f(|&Gfc=rKGBtbs^u% zgtd{Q1aWrH`uaTfM^yhH2UjTThH>MyoT9GIvAcni#TYF0Xh!{&?onn^60PSdc@0AwMH)I+@R; zzZK&?RhqJXHLMp{nyT8>7jUt0GHCsr-E51vc;#W+&pZcLeNx{bj+8T|pH&qCR;y)N z;jPAct!lU>h~=Ie;c?-R)XaKg7f6j|=z0i$Wlo*2BJJ{*Q(Hcx&-fl;kqts z-?g2TSSIQ8@2*a-f zITCICSOfWIZ2 zDh4&#F+1un(4)H{5sLj`b=-eHeS;qTe~mvbZ3y2by4!R|ozH)WzIVqyf1E68fwc1X wod4?7&W=d^NZ7flP)DUzcDrs$D+4)HIoRRv1^>G}KUefpePB8wl<&X%3yz{)$N&HU diff --git a/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_220210803.xlsx b/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_220210803.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..74f9f240d60aad03108a683eb71598188966d2ce GIT binary patch literal 5636 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 RZWj;GgX$LMpGy$He*mSLisS$Q literal 0 HcmV?d00001 diff --git a/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_320210803.xlsx b/SolarPower/wwwroot/upload/report/20210803/FIC太陽能監控平台_日報表_320210803.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..82b96dff862d3b4c6f2e82d626fa22d80c2b9bbc GIT binary patch literal 4624 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 KC4X%P0RID4stl?C literal 0 HcmV?d00001