合併衝突

This commit is contained in:
b110212000 2021-07-16 16:24:11 +08:00
commit 14686ca5d9
20 changed files with 650 additions and 391 deletions

View File

@ -65,6 +65,26 @@ namespace SolarPower.Controllers
return apiResult; return apiResult;
} }
[HttpPost]
public ApiResult<List<MyPowerStationSummary>> GetPowerStationCollapse(string filter)
{
ApiResult<List<MyPowerStationSummary>> apiResult = new ApiResult<List<MyPowerStationSummary>>();
try
{
apiResult.Code = "0000";
var powerStationSummary = powerStationRepository.GetMyPowerStationSummary(myUser, filter);
apiResult.Data = powerStationSummary;
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = exception.ToString();
}
return apiResult;
}
[HttpPost] [HttpPost]
public async Task<ApiResult<MapOverview>> GetStationCard(StationIds post) public async Task<ApiResult<MapOverview>> GetStationCard(StationIds post)
{ {

View File

@ -1579,6 +1579,24 @@ ALTER TABLE `operation_plan_create`
ALTER TABLE `operation_record` ALTER TABLE `operation_record`
CHANGE COLUMN `FixDo` `FixDo` VARCHAR(50) NULL DEFAULT NULL COMMENT '維修項目' COLLATE 'utf8mb4_unicode_ci' AFTER `ErrorCode`; CHANGE COLUMN `FixDo` `FixDo` VARCHAR(50) NULL DEFAULT NULL COMMENT '維修項目' COLLATE 'utf8mb4_unicode_ci' AFTER `ErrorCode`;
-- 各電站每15min的逆變器歷史記錄 20210715
CREATE TABLE `inverter_history_15min` (
`Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`PowerStationId` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`INVERTERID` VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`TIMESTAMP` TIMESTAMP NULL DEFAULT NULL,
`KWH` DOUBLE NULL DEFAULT NULL,
`TODAYKWH` DOUBLE NULL DEFAULT NULL,
`KWHKWP` DOUBLE NULL DEFAULT NULL,
PRIMARY KEY (`Id`) USING BTREE,
INDEX `IDX_01` (`PowerStationId`) USING BTREE
)
COMMENT='各電站每15min的逆變器歷史記錄'
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
-- 新增發電金額及減碳量 20210716 -- 新增發電金額及減碳量 20210716
ALTER TABLE `power_station_history_hour` ALTER TABLE `power_station_history_hour`
ADD COLUMN `MONEY` DOUBLE(22,0) NULL DEFAULT NULL AFTER `SOLARHOUR`, ADD COLUMN `MONEY` DOUBLE(22,0) NULL DEFAULT NULL AFTER `SOLARHOUR`,

View File

@ -28,7 +28,10 @@ namespace SolarPower.Quartz.Jobs
try try
{ {
#region step1. #region step1.
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得電站資料】");
var powerStations = await powerStationRepository.GetAllAsync(); var powerStations = await powerStationRepository.GetAllAsync();
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功電站資料】");
logger.LogInformation("【CalcAvgPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
#endregion #endregion
List<PowerStation> calcAvgPowerStations = new List<PowerStation>(); List<PowerStation> calcAvgPowerStations = new List<PowerStation>();
@ -52,14 +55,16 @@ namespace SolarPower.Quartz.Jobs
var count = 0; var count = 0;
#region () #region ()
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得氣象觀測】");
var client = new HttpClient(); var client = new HttpClient();
var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&elementName=Wx,PoP&sort=time"; var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&elementName=Wx,PoP&sort=time";
HttpResponseMessage response = client.GetAsync(UVUri).Result; HttpResponseMessage response = client.GetAsync(UVUri).Result;
String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString(); String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs); Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs);
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功氣象觀測】");
#endregion #endregion
foreach(var location in observation.Records.Location) foreach (var location in observation.Records.Location)
{ {
WeatherForecast weatherForecast = new WeatherForecast(); WeatherForecast weatherForecast = new WeatherForecast();
weatherForecast.LocationName = location.LocationName; weatherForecast.LocationName = location.LocationName;
@ -149,10 +154,14 @@ namespace SolarPower.Quartz.Jobs
var dateNowDay = DateTimeNow.AddDays(-1).ToString("yyyy-MM-dd"); var dateNowDay = DateTimeNow.AddDays(-1).ToString("yyyy-MM-dd");
#region step2-1. 30 #region step2-1. 30
var table_name = String.Format("`{0}`.`{1}01_station`", powerStation.SiteDB, powerStation.Code); var table_name = String.Format("`{0}`.`s{1}01_station`", powerStation.SiteDB, powerStation.Code);
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
var history = await powerStationRepository.CalcAvgPowerStationHistory30day(dateNowDay, table_name); var history = await powerStationRepository.CalcAvgPowerStationHistory30day(dateNowDay, table_name);
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
logger.LogInformation("【CalcAvgPowerStationJob】【電站[{0}]在{1}的30天平均資料】 - {2}", powerStation.Code, dateNowDay, System.Text.Json.JsonSerializer.Serialize(history));
if (history != null) if (history != null)
{ {
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
history.PowerStationId = powerStation.Id; history.PowerStationId = powerStation.Id;
#region 30 kWh/kWp PR #region 30 kWh/kWp PR
@ -169,11 +178,15 @@ namespace SolarPower.Quartz.Jobs
#endregion #endregion
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
} }
#endregion #endregion
#region step2-2 30 #region step2-2 30
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的30天日照計平均資料】", powerStation.Code, dateNowDay);
var avgPyrheliometerHistory = await powerStationRepository.CalcAvgPyrheliometerHistory30day(dateNowDay, powerStation.Id); var avgPyrheliometerHistory = await powerStationRepository.CalcAvgPyrheliometerHistory30day(dateNowDay, powerStation.Id);
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功電站[{0}]在{1}的30天日照計平均資料】", powerStation.Code, dateNowDay);
logger.LogInformation("【CalcAvgPowerStationJob】【電站[{0}]在{1}的30天日照計平均資料】 - {2}", powerStation.Code, dateNowDay, System.Text.Json.JsonSerializer.Serialize(avgPyrheliometerHistory));
if (avgPyrheliometerHistory != null) if (avgPyrheliometerHistory != null)
{ {
calcPowerStation.Avg_irradiance = avgPyrheliometerHistory.AvgIrradiance; calcPowerStation.Avg_irradiance = avgPyrheliometerHistory.AvgIrradiance;
@ -184,7 +197,10 @@ namespace SolarPower.Quartz.Jobs
#region step2-3. #region step2-3.
//電站資訊 //電站資訊
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得電站[{0}]在{1}的所有值的總和】", powerStation.Code, dateNowDay);
var historyDay = await powerStationRepository.GetLastOnePowerStationHistoryByDay(dateNowDay, table_name); var historyDay = await powerStationRepository.GetLastOnePowerStationHistoryByDay(dateNowDay, table_name);
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功電站[{0}]在{1}的所有值的總和】", powerStation.Code, dateNowDay);
logger.LogInformation("【CalcAvgPowerStationJob】【電站[{0}]在{1}的所有值的總和】 - {2}", powerStation.Code, dateNowDay, System.Text.Json.JsonSerializer.Serialize(historyDay));
if (historyDay != null) if (historyDay != null)
{ {
historyDay.PowerStationId = powerStation.Id; historyDay.PowerStationId = powerStation.Id;
@ -192,14 +208,18 @@ namespace SolarPower.Quartz.Jobs
} }
//日照計 //日照計
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的日照計所有值的平均】", powerStation.Code, dateNowDay);
var pyrheliometerHistorDay = await powerStationRepository.CalcPyrheliometerHistoryDayDataByPowerStationId(dateNowDay, powerStation.Id); var pyrheliometerHistorDay = await powerStationRepository.CalcPyrheliometerHistoryDayDataByPowerStationId(dateNowDay, powerStation.Id);
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的日照計所有值的平均】", powerStation.Code, dateNowDay);
if (pyrheliometerHistorDay != null) if (pyrheliometerHistorDay != null)
{ {
pyrheliometerHistoryDays.Add(pyrheliometerHistorDay); pyrheliometerHistoryDays.Add(pyrheliometerHistorDay);
} }
//逆變器 //逆變器
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的逆變器所有值的平均】", powerStation.Code, dateNowDay);
var inverterHistoriesDay = await powerStationRepository.CalcInverterHistoryDayDataByPowerStationId(dateNowDay, powerStation.SiteDB, powerStation.Id); var inverterHistoriesDay = await powerStationRepository.CalcInverterHistoryDayDataByPowerStationId(dateNowDay, powerStation.SiteDB, powerStation.Id);
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的逆變器所有值的平均】", powerStation.Code, dateNowDay);
if (inverterHistoriesDay != null) if (inverterHistoriesDay != null)
{ {
foreach(var inverterHistoryDay in inverterHistoriesDay) foreach(var inverterHistoryDay in inverterHistoriesDay)
@ -214,6 +234,7 @@ namespace SolarPower.Quartz.Jobs
var dateNowMonth = DateTimeNow.ToString("yyyy-MM"); var dateNowMonth = DateTimeNow.ToString("yyyy-MM");
//電站該月份的歷史資料 //電站該月份的歷史資料
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}月份的歷史資料總和】", powerStation.Code, dateNowMonth);
var exist_history = await powerStationRepository.GetOnePowerStationHistoryByPowerStationIdAndMonth(powerStation.Id, dateNowMonth); var exist_history = await powerStationRepository.GetOnePowerStationHistoryByPowerStationIdAndMonth(powerStation.Id, dateNowMonth);
if (exist_history == null) if (exist_history == null)
{ //新增 { //新增
@ -224,6 +245,7 @@ namespace SolarPower.Quartz.Jobs
insertPowerStationHistoryMonths.Add(historyMonth); insertPowerStationHistoryMonths.Add(historyMonth);
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的歷史資料總和】", powerStation.Code, dateNowMonth);
} }
else else
{ //修改 { //修改
@ -232,9 +254,12 @@ namespace SolarPower.Quartz.Jobs
{ {
updatePowerStationHistoryMonths.Add(historyMonth); updatePowerStationHistoryMonths.Add(historyMonth);
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的歷史資料總和】", powerStation.Code, dateNowMonth);
} }
//電站該月份的的日照度歷史資料 //電站該月份的的日照度歷史資料
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}月份的日照度歷史資料】", powerStation.Code, dateNowMonth);
var exist_pyrheliometer_history = await powerStationRepository.GetOnePyrheliometerHistoryByMonth(dateNowMonth, powerStation.Id); var exist_pyrheliometer_history = await powerStationRepository.GetOnePyrheliometerHistoryByMonth(dateNowMonth, powerStation.Id);
if (exist_pyrheliometer_history == null) if (exist_pyrheliometer_history == null)
{ //新增 { //新增
@ -244,6 +269,7 @@ namespace SolarPower.Quartz.Jobs
pyrheliometerHistoryMonth.Timestamp = Convert.ToDateTime(pyrheliometerHistoryMonth.Timestamp).ToString("yyyy-MM-dd"); pyrheliometerHistoryMonth.Timestamp = Convert.ToDateTime(pyrheliometerHistoryMonth.Timestamp).ToString("yyyy-MM-dd");
insertPyrheliometerHistoryMonths.Add(pyrheliometerHistoryMonth); insertPyrheliometerHistoryMonths.Add(pyrheliometerHistoryMonth);
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的日照度歷史資料】", powerStation.Code, dateNowMonth);
} }
else else
{ //修改 { //修改
@ -252,9 +278,11 @@ namespace SolarPower.Quartz.Jobs
{ {
updatePyrheliometerHistoryMonths.Add(pyrheliometerHistoryMonth); updatePyrheliometerHistoryMonths.Add(pyrheliometerHistoryMonth);
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的日照度歷史資料】", powerStation.Code, dateNowMonth);
} }
//電站該月份的的逆變器歷史資料 //電站該月份的的逆變器歷史資料
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}月份的逆變器歷史資料】", powerStation.Code, dateNowMonth);
var exist_inverter_histories = await powerStationRepository.GetInverterHistoryByPowerStationIdAndMonth(dateNowMonth, powerStation.Id); var exist_inverter_histories = await powerStationRepository.GetInverterHistoryByPowerStationIdAndMonth(dateNowMonth, powerStation.Id);
if (exist_inverter_histories.Count == 0 ) if (exist_inverter_histories.Count == 0 )
{ //新增 { //新增
@ -267,6 +295,7 @@ namespace SolarPower.Quartz.Jobs
insertInverterHistoryMonths.Add(inverterHistoryMonth); insertInverterHistoryMonths.Add(inverterHistoryMonth);
} }
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的逆變器歷史資料】", powerStation.Code, dateNowMonth);
} }
else else
{ //修改 { //修改
@ -279,6 +308,7 @@ namespace SolarPower.Quartz.Jobs
updateInverterHistoryMonths.Add(inverterHistoryMonth); updateInverterHistoryMonths.Add(inverterHistoryMonth);
} }
} }
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的逆變器歷史資料】", powerStation.Code, dateNowMonth);
} }
#endregion #endregion

View File

@ -25,9 +25,11 @@ namespace SolarPower.Quartz.Jobs
{ {
try try
{ {
/*
#region step1. #region step1.
logger.LogInformation("【CalcInverter15minJob】【開始取得電站資料】");
var powerStations = await powerStationRepository.GetAllAsync(); var powerStations = await powerStationRepository.GetAllAsync();
logger.LogInformation("【CalcPowerStationJob】【取得成功電站資料】");
logger.LogInformation("【CalcPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
#endregion #endregion
List<InverterHistory> calcInverter15mins = new List<InverterHistory>(); List<InverterHistory> calcInverter15mins = new List<InverterHistory>();
@ -44,47 +46,28 @@ namespace SolarPower.Quartz.Jobs
break; break;
} }
//取得所有該電站的逆變器
var controllers = await powerStationRepository.GetAllDeviceControllerId(powerStation.Id, powerStation.SiteDB);
var inverters = await powerStationRepository.InverterTable(controllers, powerStation.SiteDB);
var inverterIds = inverters.Select(x => x.InverterId.Replace("s", "")).ToList();
var calcInverter15min = new InverterHistory();
var dateNowTime = DateTimeNow.ToString("yyyy-MM-dd HH:mm"); var dateNowTime = DateTimeNow.ToString("yyyy-MM-dd HH:mm");
#region step2-1. 30 //取得所有該電站的逆變器
var table_name = String.Format("`{0}`.`{1}01_inv`", powerStation.SiteDB, powerStation.Code); logger.LogInformation("【CalcInverter15minJob】【開始取得電站[{0}]在{1}的逆變器設備資訊】", powerStation.Code, dateNowTime);
var history = await powerStationRepository.CalcInverterHisyort15minData(dateNowTime, table_name, inverterIds); var controllers = await powerStationRepository.GetAllDeviceControllerId(powerStation.Id, powerStation.SiteDB);
if (history != null) var inverters = await powerStationRepository.InverterTable(controllers, powerStation.SiteDB);
var inverterIds = inverters.Where(x => x.Enabled == 1 && x.Status != 0).Select(x => x.InverterId).ToList();
logger.LogInformation("【CalcInverter15minJob】【取得成功電站[{0}]在{1}的逆變器設備資訊】", powerStation.Code, dateNowTime);
var calcInverter15min = new InverterHistory();
#region step2-1. 15min
var table_name = String.Format("`{0}`.`s{1}01_inv`", powerStation.SiteDB, powerStation.Code);
logger.LogInformation("【CalcInverter15minJob】【開始計算電站[{0}]在{1}的每15分鐘逆變器資訊】", powerStation.Code, dateNowTime);
calcInverter15mins = await powerStationRepository.CalcInverterHisyort15minData(dateNowTime, powerStation.SiteDB, table_name, inverterIds);
logger.LogInformation("【CalcInverter15minJob】【計算完成電站[{0}]在{1}的每15分鐘逆變器資訊】", powerStation.Code, dateNowTime);
if (calcInverter15mins.Count() > 0)
{ {
history.PowerStationId = powerStation.Id; foreach (var inverterHistory in calcInverter15mins)
#region 30 kWh/kWp PR
#region kWh/kWp
//直接填寫
calcPowerStation.Avg_kwhkwp = history.AvgKWHKWP;
#endregion
#region PR
//直接填寫
calcPowerStation.Avg_PR = history.AvgPR;
#endregion
#endregion
}
#endregion
#region step2-2.
//逆變器
var inverterHistoriesDay = await powerStationRepository.CalcInverterHistoryDayDataByPowerStationId(dateNowDay, powerStation.SiteDB, powerStation.Id);
if (inverterHistoriesDay != null)
{
foreach (var inverterHistoryDay in inverterHistoriesDay)
{ {
allofInverterHistorDays.Add(inverterHistoryDay); inverterHistory.TIMESTAMP = Convert.ToDateTime(inverterHistory.TIMESTAMP + ":00").ToString("yyyy-MM-dd HH:mm:ss");
inverterHistory.PowerStationId = powerStation.Id;
} }
} }
#endregion #endregion
@ -93,115 +76,24 @@ namespace SolarPower.Quartz.Jobs
} }
#endregion #endregion
#region step3. calcPowerStations UPDATE power_station #region step3. inverter INSERT inverter_history_hour
List<string> power_station_properties = new List<string>()
{
"Id",
"avg_kwhkwp",
"avg_PR",
"avg_irradiance"
};
await powerStationRepository.UpdateList(calcAvgPowerStations, power_station_properties);
#endregion
#region step4. insert or update
//每日
List<string> history_properties_day = new List<string>()
{
"PowerStationId",
"TIMESTAMP",
"SITEID",
"SITETYPE",
"TODAYKWH",
"TOTALKWH",
"KWHKWP",
"PR",
"MP",
"SolarHour"
};
await powerStationRepository.AddPowerStationHistoryDayList(powerStationHistoryDays, history_properties_day);
//每月
List<string> history_properties_month = new List<string>()
{
"PowerStationId",
"TIMESTAMP",
"SITEID",
"SITETYPE",
"MonthKWh",
"TOTALKWH",
"KWHKWP",
"PR",
"MP",
"SolarHour"
};
if (insertPowerStationHistoryMonths.Count > 0)
{
await powerStationRepository.AddPowerStationHistoryMonthList(insertPowerStationHistoryMonths, history_properties_month);
}
if (updatePowerStationHistoryMonths.Count > 0)
{
await powerStationRepository.UpdatePowerStationHistoryMonthList(updatePowerStationHistoryMonths);
}
#endregion
#region step5. insert or update
List<string> pyrheliometer_history_properties = new List<string>()
{
"PowerStationId",
"Timestamp",
"Irradiance",
"Temperature"
};
//每日
await powerStationRepository.AddPyrheliometerHistoryDayList(pyrheliometerHistoryDays, pyrheliometer_history_properties);
//每月
if (insertPyrheliometerHistoryMonths.Count > 0)
{
await powerStationRepository.AddPyrheliometerHistoryMonthList(insertPyrheliometerHistoryMonths, pyrheliometer_history_properties);
}
if (updatePyrheliometerHistoryMonths.Count > 0)
{
await powerStationRepository.UpdatePyrheliometerHistoryMonthList(updatePyrheliometerHistoryMonths);
}
#endregion
#region step6. insert or update
List<string> inverter_history_properties = new List<string>() List<string> inverter_history_properties = new List<string>()
{ {
"PowerStationId", "PowerStationId",
"TIMESTAMP",
"INVERTERID", "INVERTERID",
"TIMESTAMP",
"KWH", "KWH",
"TODAYKWH", "TODAYKWH",
"KWHKWP", "KWHKWP",
}; };
//每日
await powerStationRepository.AddInverterHistoryDayList(allofInverterHistorDays, inverter_history_properties);
//每月 await powerStationRepository.AddInverter15minHistory(calcInverter15mins, inverter_history_properties);
if (insertInverterHistoryMonths.Count > 0)
{
await powerStationRepository.AddInverterHistoryMonthList(insertInverterHistoryMonths, inverter_history_properties);
}
if (updateInverterHistoryMonths.Count > 0)
{
await powerStationRepository.UpdateInverterHistoryMonthList(updateInverterHistoryMonths);
}
#endregion #endregion
*/
} }
catch (Exception exception) catch (Exception exception)
{ {
logger.LogError("【{0}】{1}", "CalcAvgPowerStationJob", exception.Message); logger.LogError("【{0}】{1}", "CalcInverter15minJob", exception.Message);
} }
} }
} }

View File

@ -30,10 +30,10 @@ namespace SolarPower.Quartz.Jobs
try try
{ {
#region step1. #region step1.
logger.LogInformation("【CalcPowerStationJob】【開始取得電站資料】");
var powerStations = await powerStationRepository.GetAllAsync(); var powerStations = await powerStationRepository.GetAllAsync();
logger.LogInformation("【CalcPowerStationJob】【取得成功電站資料】");
string json = System.Text.Json.JsonSerializer.Serialize(powerStations); logger.LogInformation("【CalcPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
logger.LogError("【{0}】{1}", "CalcPowerStationJob - step1", json);
#endregion #endregion
List<PowerStationHistory> powerStationHistoriesHour = new List<PowerStationHistory>(); List<PowerStationHistory> powerStationHistoriesHour = new List<PowerStationHistory>();
@ -47,11 +47,13 @@ namespace SolarPower.Quartz.Jobs
var count = 0; var count = 0;
#region () #region ()
logger.LogInformation("【CalcPowerStationJob】【開始取得氣象觀測】");
var client = new HttpClient(); var client = new HttpClient();
var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/O-A0003-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80"; var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/O-A0003-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80";
HttpResponseMessage response = client.GetAsync(UVUri).Result; HttpResponseMessage response = client.GetAsync(UVUri).Result;
String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString(); String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs); Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs);
logger.LogInformation("【CalcPowerStationJob】【取得成功氣象觀測】");
#endregion #endregion
@ -69,15 +71,16 @@ namespace SolarPower.Quartz.Jobs
var dateTime = DateTimeNow.AddHours(-1).ToString("yyyy-MM-dd HH"); var dateTime = DateTimeNow.AddHours(-1).ToString("yyyy-MM-dd HH");
#region step2-1. #region step2-1.
var table_name = String.Format("`{0}`.{1}01_station", powerStation.SiteDB, powerStation.Code); var table_name = String.Format("`{0}`.s{1}01_station", powerStation.SiteDB, powerStation.Code);
logger.LogError("【{0}】{1}", "CalcPowerStationJob - time & dataTable", dateTime + "======" + table_name);
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
var history = await powerStationRepository.GetPowerStationHistoryPerHour(dateTime, table_name); var history = await powerStationRepository.GetPowerStationHistoryPerHour(dateTime, table_name);
json = System.Text.Json.JsonSerializer.Serialize(history); logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
logger.LogError("【{0}】{1}", "CalcPowerStationJob - history", json); logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的每小時歷史資料】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(history));
if (history != null) if (history != null)
{ {
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
history.PowerStationId = powerStation.Id; history.PowerStationId = powerStation.Id;
history.Timestamp = Convert.ToDateTime(history.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss"); history.Timestamp = Convert.ToDateTime(history.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
@ -153,17 +156,22 @@ namespace SolarPower.Quartz.Jobs
#endregion #endregion
powerStationHistoriesHour.Add(history); powerStationHistoriesHour.Add(history);
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
} }
#endregion #endregion
#region step2-2. #region step2-2.
//1. 找出該電站所有日照計設備(包含共享 //1. 找出該電站所有日照計設備(包含共享
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的日照計設備資訊】", powerStation.Code, dateTime);
var deviceInfos = await powerStationRepository.GetListPyrheliometerByPowerStationId(powerStation.Id, powerStation.SiteDB); var deviceInfos = await powerStationRepository.GetListPyrheliometerByPowerStationId(powerStation.Id, powerStation.SiteDB);
// 找出該電站所有溫度計設備(包含共享 logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的日照計設備資訊】", powerStation.Code, dateTime);
var tempdeviceInfos = await powerStationRepository.GetListTempByPowerStationId(powerStation.Id, powerStation.SiteDB); logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的日照計設備資訊】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(deviceInfos));
if (deviceInfos != null) if (deviceInfos != null)
{ {
//2. 計算該電站所有日照計設的每小時的平均在依照日照計數量平均 //2. 計算該電站所有日照計設的每小時的平均在依照日照計數量平均
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的日照計的日照度】", powerStation.Code, dateTime);
var pyrheliometerHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, deviceInfos, 0); var pyrheliometerHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, deviceInfos, 0);
if (pyrheliometerHistory != null) if (pyrheliometerHistory != null)
@ -174,32 +182,47 @@ namespace SolarPower.Quartz.Jobs
pyrheliometerHistory.PowerStationId = powerStation.Id; pyrheliometerHistory.PowerStationId = powerStation.Id;
pyrheliometerHistoriesHour.Add(pyrheliometerHistory); pyrheliometerHistoriesHour.Add(pyrheliometerHistory);
} }
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的日照計的日照度】", powerStation.Code, dateTime);
} }
//2. 計算該電站所有溫度計設的每小時的平均在依照溫度計數量平均 //2. 計算該電站所有溫度計設的每小時的平均在依照溫度計數量平均
// 找出該電站所有溫度計設備(包含共享
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的溫度計設備資訊】", powerStation.Code, dateTime);
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)
{ {
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的溫度計的平均溫度】", powerStation.Code, dateTime);
var tempHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, tempdeviceInfos, 1); var tempHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, tempdeviceInfos, 1);
if (tempHistory != null) if (tempHistory != null)
{ {
tempHistory.Timestamp = Convert.ToDateTime(tempHistory.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss"); tempHistory.Timestamp = Convert.ToDateTime(tempHistory.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
tempHistory.PowerStationId = powerStation.Id; tempHistory.PowerStationId = powerStation.Id;
TempHistoriesHour.Add(tempHistory); TempHistoriesHour.Add(tempHistory);
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的溫度計的平均溫度】", powerStation.Code, dateTime);
} }
} }
#endregion #endregion
#region step2-3. #region step2-3.
var inverter_table_name = String.Format("`{0}`.{1}01_inv", powerStation.SiteDB, powerStation.Code); logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的逆變器設備資訊】", powerStation.Code, dateTime);
var controllers = await powerStationRepository.GetAllDeviceControllerId(powerStation.Id, powerStation.SiteDB);
var inverters = await powerStationRepository.InverterTable(controllers, powerStation.SiteDB);
var inverterIds = inverters.Select(x => x.InverterId).ToList();
logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的逆變器設備資訊】", powerStation.Code, dateTime);
logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的逆變器設備資訊】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(inverterIds));
inverterHistories = await powerStationRepository.CalcInverterHisyortHourData(dateTime, powerStation.SiteDB, inverter_table_name); var inverter_table_name = String.Format("`{0}`.s{1}01_inv", powerStation.SiteDB, powerStation.Code);
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的逆變器的資訊】", powerStation.Code, dateTime);
inverterHistories = await powerStationRepository.CalcInverterHisyortHourData(dateTime, powerStation.SiteDB, inverter_table_name, inverterIds);
foreach (var inverterHistory in inverterHistories) foreach (var inverterHistory in inverterHistories)
{ {
inverterHistory.TIMESTAMP = Convert.ToDateTime(inverterHistory.TIMESTAMP + ":00:00").ToString("yyyy-MM-dd HH:mm:ss"); inverterHistory.TIMESTAMP = Convert.ToDateTime(inverterHistory.TIMESTAMP + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
inverterHistory.PowerStationId = powerStation.Id; inverterHistory.PowerStationId = powerStation.Id;
} }
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的逆變器的資訊】", powerStation.Code, dateTime);
#endregion #endregion
#region () #region ()
@ -226,9 +249,9 @@ namespace SolarPower.Quartz.Jobs
WeatherObservation weatherObservation = new WeatherObservation(); WeatherObservation weatherObservation = new WeatherObservation();
if (powerStation.WeathersStationId != null) if (powerStation.WeathersStationId != null)
{ {
foreach(var Location in observation.Records.Location) foreach (var Location in observation.Records.Location)
{ {
if(Location.StationId == powerStation.WeathersStationId) if (Location.StationId == powerStation.WeathersStationId)
{ {
calcPowerStation.TodayWeatherTemp = Convert.ToDouble(Location.WeatherElement[0].ElementValue); calcPowerStation.TodayWeatherTemp = Convert.ToDouble(Location.WeatherElement[0].ElementValue);
weatherObservation.PowerStationId = powerStation.Id; weatherObservation.PowerStationId = powerStation.Id;
@ -240,15 +263,19 @@ namespace SolarPower.Quartz.Jobs
} }
} }
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的天氣預報的資訊】", powerStation.Code, dateTime);
var weather = await powerStationRepository.SelectNowWeather(powerStation.CityId); var weather = await powerStationRepository.SelectNowWeather(powerStation.CityId);
calcPowerStation.TodayWeather = weather.WeatherKey; logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的天氣預報的資訊】", powerStation.Code, dateTime);
calcPowerStation.RateOfRain = weather.PoP; if(weather != null)
{
calcPowerStation.TodayWeather = weather.WeatherKey;
calcPowerStation.RateOfRain = weather.PoP;
}
weatherObservations.Add(weatherObservation); weatherObservations.Add(weatherObservation);
calcPowerStations.Add(calcPowerStation); calcPowerStations.Add(calcPowerStation);
count++; count++;
} }
#endregion #endregion
@ -268,9 +295,6 @@ namespace SolarPower.Quartz.Jobs
"SolarHour" "SolarHour"
}; };
json = System.Text.Json.JsonSerializer.Serialize(powerStationHistoriesHour);
logger.LogError("【{0}】{1}", "CalcPowerStationJob - step3", json);
await powerStationRepository.AddPowerStationHistory(powerStationHistoriesHour, history_properties); await powerStationRepository.AddPowerStationHistory(powerStationHistoriesHour, history_properties);
#endregion #endregion
@ -328,7 +352,7 @@ namespace SolarPower.Quartz.Jobs
"KWHKWP", "KWHKWP",
}; };
await powerStationRepository.AddInverterHisyort(inverterHistories, inverter_history_properties); await powerStationRepository.AddInverterHistory(inverterHistories, inverter_history_properties);
#endregion #endregion
List<string> weather_observation_properties = new List<string>() List<string> weather_observation_properties = new List<string>()
@ -338,10 +362,6 @@ namespace SolarPower.Quartz.Jobs
"Temp" "Temp"
}; };
await powerStationRepository.AddWeatherObservation(weatherObservations, weather_observation_properties); await powerStationRepository.AddWeatherObservation(weatherObservations, weather_observation_properties);
} }
catch (Exception exception) catch (Exception exception)
{ {

View File

@ -315,7 +315,7 @@ namespace SolarPower.Repository.Implement
{ {
try try
{ {
var sql = @$"SELECT * FROM inverter_history_hour WHERE PowerStationId = @PowerStationId AND DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') = @DateTime"; var sql = @$"SELECT * FROM inverter_history_15min WHERE PowerStationId = @PowerStationId AND DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') = @DateTime";
result = (await conn.QueryAsync<InverterHistory>(sql, new { PowerStationId = powerStationId, DateTime = dateTime })).ToList(); result = (await conn.QueryAsync<InverterHistory>(sql, new { PowerStationId = powerStationId, DateTime = dateTime })).ToList();
} }

View File

@ -23,7 +23,7 @@ namespace SolarPower.Repository.Implement
} }
public List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser) public List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser, string filter = "")
{ {
List<MyPowerStationSummary> results = new List<MyPowerStationSummary>(); List<MyPowerStationSummary> results = new List<MyPowerStationSummary>();
@ -35,7 +35,7 @@ namespace SolarPower.Repository.Implement
FROM power_station ps FROM power_station ps
LEFT JOIN city c ON ps.CityId = c.Id"; LEFT JOIN city c ON ps.CityId = c.Id";
if(myUser.Role.Layer == 2) if (myUser.Role.Layer == 2)
{ //公司管理員 { //公司管理員
sql += @" WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId"; sql += @" WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId";
} }
@ -49,7 +49,12 @@ namespace SolarPower.Repository.Implement
sql += @" WHERE ps.Deleted = 0"; sql += @" WHERE ps.Deleted = 0";
} }
var myPowerStationInfos = conn.Query<MyPowerStationInfo>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id }).ToList(); if (!string.IsNullOrEmpty(filter))
{
sql += @" AND ps.Name LIKE CONCAT('%', @Filter, '%')";
}
var myPowerStationInfos = conn.Query<MyPowerStationInfo>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id, Filter = filter }).ToList();
var myPowerStationInfos_group = myPowerStationInfos.GroupBy(x => x.CityId); var myPowerStationInfos_group = myPowerStationInfos.GroupBy(x => x.CityId);
@ -2290,10 +2295,10 @@ namespace SolarPower.Repository.Implement
} }
} }
//(有修改) //(有修改)
public async Task<PyrheliometerHistory> GetPyrheliometerHistoryPerHour(string dateTime, List<DeviceInfo> deviceInfos,int type) public async Task<PyrheliometerHistory> GetPyrheliometerHistoryPerHour(string dateTime, List<DeviceInfo> deviceInfos, int type)
{ {
var typename = ""; var typename = "";
if(type == 1) if (type == 1)
{ {
typename = "Temperature";//1為溫度計 typename = "Temperature";//1為溫度計
} }
@ -2594,62 +2599,113 @@ namespace SolarPower.Repository.Implement
} }
} }
//public async Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string table_name, List<string> inverterIds) public async Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string db_name, string table_name, List<string> inverterIds)
//{
// List<InverterHistory> result;
// using (IDbConnection conn = this._databaseHelper.GetConnection())
// {
// try
// {
// var stratDateTime = Convert.ToDateTime(dateTime + ":00").AddMinutes(-15).ToString("yyyy-MM-dd HH:mm");
// var sql = $@"SELECT
// MAX(DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H:%i')) AS TIMESTAMP,
// s.INVERTERID,
// a.KWH, MAX(s.TODAYKWH) AS TODAYKWH, i.Capacity, (a.KWH/i.Capacity) AS KWHKWP
// FROM {table_name} s
// LEFT JOIN (
// SELECT DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H:%i') AS TIMESTAMP, inv.INVERTERID, SUM(inv.WH)/1000 AS KWH
// FROM {table_name} inv
// WHERE DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H:%i') BETWEEN @StartDateTiime AND @EndDateTime
// GROUP BY DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H'), inv.INVERTERID) a
// ON DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID
// LEFT JOIN {db_name}.inverter i ON CONCAT('s', s.INVERTERID) = i.InverterId
// WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') = @DateTime
// GROUP BY DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H'), s.INVERTERID
// ";
// result = (await conn.QueryAsync<InverterHistory>(sql, new { DateTime = dateTime })).ToList();
// }
// catch (Exception exception)
// {
// throw exception;
// }
// return result;
// }
//}
public async Task<List<InverterHistory>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name)
{ {
List<InverterHistory> result; List<InverterHistory> result;
using (IDbConnection conn = this._databaseHelper.GetConnection()) using (IDbConnection conn = this._databaseHelper.GetConnection())
{ {
try try
{ {
var sql = $@"SELECT MAX(DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H')) AS TIMESTAMP, s.INVERTERID, a.KWH, MAX(s.TODAYKWH) AS TODAYKWH, i.Capacity, (a.KWH/i.Capacity) AS KWHKWP var stratDateTime = Convert.ToDateTime(dateTime + ":00").AddMinutes(-15).ToString("yyyy-MM-dd HH:mm");
var sql = $@"SELECT
s.TIMESTAMP,
s.INVERTERID,
a.KWH,
s.TODAYKWH,
i.Capacity,
(a.KWH/i.Capacity) AS KWHKWP
FROM (SELECT
MAX(FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i')) AS TIMESTAMP,
sub_inv.INVERTERID,
MAX(sub_inv.TODAYKWH) AS TODAYKWH
FROM {table_name} sub_inv
WHERE FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i') BETWEEN @StartDateTime AND @EndDateTime
AND sub_inv.INVERTERID IN @InverterIds
GROUP BY sub_inv.INVERTERID) s
LEFT JOIN (
SELECT MAX(FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i')) AS TIMESTAMP,
sub_inv.INVERTERID,
SUM(sub_inv.WH)/1000 AS KWH
FROM {table_name} sub_inv
WHERE FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i') BETWEEN @StartDateTime AND @EndDateTime
AND sub_inv.INVERTERID IN @InverterIds
GROUP BY sub_inv.INVERTERID) a
ON s.TIMESTAMP = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID
LEFT JOIN {db_name}.inverter i ON s.INVERTERID = REPLACE(i.InverterId, 's', '');";
result = (await conn.QueryAsync<InverterHistory>(sql, new { StartDateTime = stratDateTime, EndDateTime = dateTime, InverterIds = inverterIds })).ToList();
}
catch (Exception exception)
{
throw exception;
}
return result;
}
}
public async Task<int> AddInverter15minHistory(List<InverterHistory> entity, List<string> properties)
{
int count;
using (IDbConnection conn = _databaseHelper.GetConnection())
{
conn.Open();
using (var trans = conn.BeginTransaction())
{
try
{
string sql = GenerateInsertQueryWithCustomTable(properties, "inverter_history_15min");
count = await conn.ExecuteAsync(sql, entity, trans);
trans.Commit();
}
catch (Exception exception)
{
trans.Rollback();
throw exception;
}
finally
{
conn.Close();
}
}
return count;
}
}
public async Task<List<InverterHistory>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name, List<string> inverterIds)
{
List<InverterHistory> result;
using (IDbConnection conn = this._databaseHelper.GetConnection())
{
try
{
var sql = $@"SELECT
MAX(FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H')) AS TIMESTAMP,
s.INVERTERID,
a.KWH,
MAX(s.TODAYKWH) AS TODAYKWH,
i.Capacity,
(a.KWH/i.Capacity) AS KWHKWP
FROM {table_name} s FROM {table_name} s
LEFT JOIN ( LEFT JOIN (
SELECT DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H') AS TIMESTAMP, inv.INVERTERID, SUM(inv.WH)/1000 AS KWH SELECT
FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H') AS TIMESTAMP,
inv.INVERTERID,
SUM(inv.WH)/1000 AS KWH
FROM {table_name} inv FROM {table_name} inv
WHERE DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H') = @DateTime WHERE DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H') = @DateTime
GROUP BY DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H'), inv.INVERTERID) a AND inv.INVERTERID IN @InverterIds
ON DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID GROUP BY FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H'), inv.INVERTERID) a
LEFT JOIN {db_name}.inverter i ON CONCAT('s', s.INVERTERID) = i.InverterId ON FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H') = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID
WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') = @DateTime LEFT JOIN {db_name}.inverter i ON s.INVERTERID = i.InverterId
WHERE FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H') = @DateTime
AND s.INVERTERID IN @InverterIds
GROUP BY DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H'), s.INVERTERID GROUP BY DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H'), s.INVERTERID
"; ";
result = (await conn.QueryAsync<InverterHistory>(sql, new { DateTime = dateTime })).ToList(); result = (await conn.QueryAsync<InverterHistory>(sql, new { DateTime = dateTime, InverterIds = inverterIds })).ToList();
} }
catch (Exception exception) catch (Exception exception)
{ {
@ -2786,7 +2842,7 @@ namespace SolarPower.Repository.Implement
} }
} }
public async Task<int> AddInverterHisyort(List<InverterHistory> entity, List<string> properties) public async Task<int> AddInverterHistory(List<InverterHistory> entity, List<string> properties)
{ {
int count; int count;
using (IDbConnection conn = _databaseHelper.GetConnection()) using (IDbConnection conn = _databaseHelper.GetConnection())
@ -2974,7 +3030,7 @@ namespace SolarPower.Repository.Implement
} }
} }
public async Task<NowWeather> SelectNowWeather (int CityId) public async Task<NowWeather> SelectNowWeather(int CityId)
{ {
NowWeather result = new NowWeather(); NowWeather result = new NowWeather();
using (IDbConnection conn = this._databaseHelper.GetConnection()) using (IDbConnection conn = this._databaseHelper.GetConnection())

View File

@ -16,7 +16,7 @@ namespace SolarPower.Repository.Interface
/// </summary> /// </summary>
/// <param name="myUser"></param> /// <param name="myUser"></param>
/// <returns></returns> /// <returns></returns>
List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser); List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser, string filter = "");
/// <summary> /// <summary>
/// 查詢縣市列表 /// 查詢縣市列表
@ -518,9 +518,10 @@ namespace SolarPower.Repository.Interface
Task<A> Getonediv<A>(string where, string db_name, string table_name); Task<A> Getonediv<A>(string where, string db_name, string table_name);
//Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string table_name, List<string> inverterIds); Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string db_name, string table_name, List<string> inverterIds);
Task<List<InverterHistory>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name); Task<int> AddInverter15minHistory(List<InverterHistory> entity, List<string> properties);
Task<int> AddInverterHisyort(List<InverterHistory> entity, List<string> properties); Task<List<InverterHistory>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name, List<string> inverterIds);
Task<int> AddInverterHistory(List<InverterHistory> entity, List<string> properties);
Task<List<InverterHistory>> CalcInverterHistoryDayDataByPowerStationId(string nowDay, string db_name, int powerStationId); Task<List<InverterHistory>> CalcInverterHistoryDayDataByPowerStationId(string nowDay, string db_name, int powerStationId);
Task<int> AddInverterHistoryDayList(List<InverterHistory> entity, List<string> properties); Task<int> AddInverterHistoryDayList(List<InverterHistory> entity, List<string> properties);
Task<List<InverterHistory>> GetInverterHistoryByPowerStationIdAndMonth(string month, int powerStationId); Task<List<InverterHistory>> GetInverterHistoryByPowerStationIdAndMonth(string month, int powerStationId);

View File

@ -99,6 +99,13 @@ namespace SolarPower
); );
#endregion #endregion
#region (215)
services.AddSingleton<CalcInverter15minJob>();
services.AddSingleton(
new JobSchedule(jobType: typeof(CalcInverter15minJob), cronExpression: Configuration.GetValue<string>("BackgroundServiceCron:CalcInverter15minJob"))
);
#endregion
#region (5) #region (5)
services.AddSingleton<CalcPowerStationJob>(); services.AddSingleton<CalcPowerStationJob>();
services.AddSingleton( services.AddSingleton(

View File

@ -12,7 +12,7 @@
<!-- Your main content goes below here: --> <!-- Your main content goes below here: -->
<div class="row mb-5"> <div class="row mb-5">
<div class="card-columns col-xl-12"> <div class="card-columns">
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4>

View File

@ -4,7 +4,7 @@
<!-- we wrap header title inside a div tag with utility padding --> <!-- we wrap header title inside a div tag with utility padding -->
<div class="card-title font-weight-bold">控制器</div> <div class="card-title font-weight-bold">控制器</div>
<div class="text-right "> <div class="text-right ">
<a href="javascript:;" class="btn btn-success waves-effect waves-themed" id="addController-btn" onclick="AddController()"> <a href="javascript:;" class="btn btn-sm btn-success ml-auto waves-effect waves-themed" id="addController-btn" onclick="AddController()">
<span class="fal fa-plus mr-1"></span> 新增 <span class="fal fa-plus mr-1"></span> 新增
</a> </a>
</div> </div>
@ -32,7 +32,7 @@
<!-- we wrap header title inside a div tag with utility padding --> <!-- we wrap header title inside a div tag with utility padding -->
<div class="card-title font-weight-bold">逆變器</div> <div class="card-title font-weight-bold">逆變器</div>
<div class="text-right"> <div class="text-right">
<a href="javascript:;" class="btn btn-success waves-effect waves-themed" id="addInverter-btn" onclick="AddInverter()"> <a href="javascript:;" class="btn btn-sm btn-success ml-auto waves-effect waves-themed" id="addInverter-btn" onclick="AddInverter()">
<span class="fal fa-plus mr-1"></span> 新增 <span class="fal fa-plus mr-1"></span> 新增
</a> </a>
</div> </div>
@ -67,7 +67,7 @@
<!-- we wrap header title inside a div tag with utility padding --> <!-- we wrap header title inside a div tag with utility padding -->
<div class="card-title font-weight-bold">裝置設定</div> <div class="card-title font-weight-bold">裝置設定</div>
<div class="text-right"> <div class="text-right">
<a href="javascript:;" class="btn btn-success waves-effect waves-themed" id="addDevice-btn" onclick="AddDevice()"> <a href="javascript:;" class="btn btn-sm btn-success ml-auto waves-effect waves-themed" id="addDevice-btn" onclick="AddDevice()">
<span class="fal fa-plus mr-1"></span> 新增 <span class="fal fa-plus mr-1"></span> 新增
</a> </a>
</div> </div>
@ -105,7 +105,7 @@
<!-- we wrap header title inside a div tag with utility padding --> <!-- we wrap header title inside a div tag with utility padding -->
<div class="card-title font-weight-bold">共用裝置</div> <div class="card-title font-weight-bold">共用裝置</div>
<div class="text-right"> <div class="text-right">
<a href="javascript:;" class="btn btn-success waves-effect waves-themed" id="addShareDevice-btn" onclick="AddShareDevice()"> <a href="javascript:;" class="btn btn-sm btn-success ml-auto waves-effect waves-themed" id="addShareDevice-btn" onclick="AddShareDevice()">
<span class="fal fa-plus mr-1"></span> 新增 <span class="fal fa-plus mr-1"></span> 新增
</a> </a>
</div> </div>

View File

@ -17,7 +17,7 @@
<link id="vendorsbundle" rel="stylesheet" media="screen, print" href="~/css/vendors.bundle.css" asp-append-version="true"> <link id="vendorsbundle" rel="stylesheet" media="screen, print" href="~/css/vendors.bundle.css" asp-append-version="true">
<link id="appbundle" rel="stylesheet" media="screen, print" href="~/css/app.bundle.css" asp-append-version="true"> <link id="appbundle" rel="stylesheet" media="screen, print" href="~/css/app.bundle.css" asp-append-version="true">
<link id="mytheme" rel="stylesheet" media="screen, print" href="~/css/themes/cust-theme-15.css" asp-append-version="true"> <link id="mytheme" rel="stylesheet" media="screen, print" href="~/css/themes/cust-theme-15.css" asp-append-version="true">
<link id="myskin" rel="stylesheet" media="screen, print" href="~/css/skins/skin-master.css"> <link id="myskin" rel="stylesheet" media="screen, print" href="~/css/skins/skin-master.css" asp-append-version="true">
<!-- Place favicon.ico in the root directory --> <!-- Place favicon.ico in the root directory -->
<link rel="apple-touch-icon" sizes="180x180" href="~/img/favicon/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="~/img/favicon/apple-touch-icon.png">
@ -45,6 +45,62 @@
</head> </head>
<body class="mod-bg-1 mod-nav-link"> <body class="mod-bg-1 mod-nav-link">
<script>
/**
* This script should be placed right after the body tag for fast execution
* Note: the script is written in pure javascript and does not depend on thirdparty library
**/
'use strict';
var classHolder = document.getElementsByTagName("BODY")[0],
/**
* Load from localstorage
**/
themeSettings = (localStorage.getItem('themeSettings')) ? JSON.parse(localStorage.getItem('themeSettings')) :
{},
themeURL = themeSettings.themeURL || '',
themeOptions = themeSettings.themeOptions || '';
/**
* Load theme options
**/
if (themeSettings.themeOptions) {
classHolder.className = themeSettings.themeOptions;
console.log("%c✔ Theme settings loaded", "color: #148f32");
}
else {
console.log("%c✔ Heads up! Theme settings is empty or does not exist, loading default settings...", "color: #ed1c24");
}
if (themeSettings.themeURL && !document.getElementById('mytheme')) {
var cssfile = document.createElement('link');
cssfile.id = 'mytheme';
cssfile.rel = 'stylesheet';
cssfile.href = themeURL;
document.getElementsByTagName('head')[0].appendChild(cssfile);
}
else if (themeSettings.themeURL && document.getElementById('mytheme')) {
document.getElementById('mytheme').href = themeSettings.themeURL;
}
/**
* Save to localstorage
**/
var saveSettings = function () {
themeSettings.themeOptions = String(classHolder.className).split(/[^\w-]+/).filter(function (item) {
return /^(nav|header|footer|mod|display)-/i.test(item);
}).join(' ');
if (document.getElementById('mytheme')) {
themeSettings.themeURL = document.getElementById('mytheme').getAttribute("href");
};
localStorage.setItem('themeSettings', JSON.stringify(themeSettings));
}
/**
* Reset settings
**/
var resetSettings = function () {
localStorage.setItem("themeSettings", "");
}
</script>
<!-- BEGIN Page Wrapper --> <!-- BEGIN Page Wrapper -->
<div class="page-wrapper"> <div class="page-wrapper">

View File

@ -78,11 +78,11 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="card-columns"> <div class="card-columns">
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4>
<div class="ml-auto">kWh</div> <div class="ml-auto">kWh</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>今日發電量</p> <p>今日發電量</p>
<p><span class="color-info-700" id="today_kwh">126,161.72</span></p> <p><span class="color-info-700" id="today_kwh">126,161.72</span></p>
@ -94,11 +94,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> 日照度</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> 日照度</h4>
<div class="ml-auto">kW/m<sup>2</sup></div> <div class="ml-auto">kW/m<sup>2</sup></div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均日照度</p> <p>即時平均日照度</p>
<p><span class="color-info-700" id="today_irradiance">126,161.72</span></p> <p><span class="color-info-700" id="today_irradiance">126,161.72</span></p>
@ -110,11 +110,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> PR值</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> PR值</h4>
<div class="ml-auto">%</div> <div class="ml-auto">%</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均 PR 值</p> <p>即時平均 PR 值</p>
<p><span class="color-info-700" id="today_PR">119.04</span></p> <p><span class="color-info-700" id="today_PR">119.04</span></p>
@ -126,11 +126,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> kWh / kWp</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> kWh / kWp</h4>
<div class="ml-auto">hr</div> <div class="ml-auto">hr</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均 kWh / kWp</p> <p>即時平均 kWh / kWp</p>
<p><span class="color-info-700" id="today_kwhkwp">140.39</span></p> <p><span class="color-info-700" id="today_kwhkwp">140.39</span></p>
@ -142,11 +142,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 減碳量</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 減碳量</h4>
<div class="ml-auto">kG</div> <div class="ml-auto">kG</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>今日減碳量</p> <p>今日減碳量</p>
<p><span class="color-info-700" id="today_carbon">6,091.78</span></p> <p><span class="color-info-700" id="today_carbon">6,091.78</span></p>

View File

@ -5,144 +5,166 @@
} }
@using SolarPower.Models.Role @using SolarPower.Models.Role
@model RoleLayerEnum @model RoleLayerEnum
@*<ol class="breadcrumb page-breadcrumb" >
<ol class="breadcrumb page-breadcrumb" > <li class="breadcrumb-item"><a href="javascript:void(0);">總覽</a></li>
<li class="breadcrumb-item"><a href="javascript:void(0);">總覽</a></li> <li class="breadcrumb-item">@ViewData["Title"]</li>
<li class="breadcrumb-item">@ViewData["Title"]</li> <li class="breadcrumb-item city-name" id="breadcrumbcity">新竹市</li>
<li class="breadcrumb-item city-name" id="breadcrumbcity">新竹市</li> <li class="breadcrumb-item power-station-name active" id="breadcrumbname">新竹巨城站</li>
<li class="breadcrumb-item power-station-name active" id="breadcrumbname">新竹巨城站</li> <li class="position-absolute pos-top pos-right d-none d-sm-block"><span class="js-get-date"></span></li>
<li class="position-absolute pos-top pos-right d-none d-sm-block"><span class="js-get-date"></span></li> </ol>*@
</ol> <div class="container-fluid">
<div class="row"> <div class="row flex-nowrap wrapper">
<div class="col-xl-12"> <div class="col-md-2 col-1 pl-0 pr-0 collapse width border-right sidebar vh-100">
<div id="panel-5" class="panel"> <div class="list-group border-0 card text-center text-md-left" id="sidebar">
<div class="panel-container show"> <div class="border bg-light rounded-top">
<div class="panel-content"> <div class="form-group p-2 m-0 rounded-top">
<div class="row subheader"> <input type="text" class="form-control form-control-lg shadow-inset-2 m-0" id="js_list_accordion_filter" placeholder="">
<div class="col-xl-2">
<h1 class="subheader-title">
<span class="icon-stack fa-1x">
<i class="base-7 icon-stack-3x color-info-500"></i>
<i class="base-7 icon-stack-2x color-info-700"></i>
<i class="ni ni-graph icon-stack-1x text-white"></i>
</span>
<span id="power-station-title" >新竹巨城站</span>
</h1>
</div>
<div class="col-xl-3 d-flex justify-content-start">
<p class="card-text px-3"><i class="fal fa-cloud-sun-rain fa-3x" id="weather-icon"></i></p>
<p class="font-weight-bold" id="weather-temp">27°C<br>降雨幾率: 15%</p>
</div>
</div> </div>
<ul class="nav nav-tabs mb-5" role="tablist"> <div id="js_list_accordion" class="accordion accordion-hover accordion-clean js-list-filter">
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_UpToDate"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4 active" data-toggle="tab" href="#tab-overview-uptodate" role="tab">
<i class="fal fa-monitor-heart-rate text-success"></i> <span class="hidden-sm-down ml-1">即時資訊</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Info"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-info" role="tab">
<i class="fal fa-info-square text-success"></i> <span class="hidden-sm-down ml-1">基本資料</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_History"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-history" role="tab">
<i class="fal fa-history text-success"></i> <span class="hidden-sm-down ml-1">歷史資料</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Inverter"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-inverter" role="tab">
<i class="fal fa-analytics text-success"></i> <span class="hidden-sm-down ml-1">逆變器分析</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Exception"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-exception" role="tab">
<i class="fal fa-sensor-alert text-success"></i> <span class="hidden-sm-down ml-1">異常記錄</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_OperationRecord"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-operationRecord" role="tab">
<i class="fal fa-digital-tachograph text-success"></i> <span class="hidden-sm-down ml-1">運維記錄</span>
</a>
</li>
}
</ul>
<div class="tab-content p-3">
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_UpToDate"))
{
<div class="tab-pane fade show active" id="tab-overview-uptodate" role="tabpanel" aria-labelledby="tab-overview-uptodate">
@Html.Partial("_UpToDate")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Info"))
{
<div class="tab-pane fade" id="tab-overview-info" role="tabpanel" aria-labelledby="tab-overview-info">
@Html.Partial("_Info")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_History"))
{
<div class="tab-pane fade" id="tab-overview-history" role="tabpanel" aria-labelledby="tab-overview-history">
@Html.Partial("_History")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Inverter"))
{
<div class="tab-pane fade" id="tab-overview-inverter" role="tabpanel" aria-labelledby="tab-overview-inverter">
@Html.Partial("_Inverter")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Exception"))
{
<div class="tab-pane fade" id="tab-overview-exception" role="tabpanel" aria-labelledby="tab-overview-exception">
@Html.Partial("_Exception")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_OperationRecord"))
{
<div class="tab-pane fade" id="tab-overview-operationRecord" role="tabpanel" aria-labelledby="tab-overview-operationRecord">
@Html.Partial("_OperationRecord")
</div>
}
</div> </div>
<span class="filter-message js-filter-message"></span>
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto px-0">
<a href="javascript:;" data-target=".sidebar" data-toggle="collapse" class="btn btn-default btn-xs btn-icon waves-effect waves-themed" style="border-radius: 0;" onclick="ChangePowerStationCollapse(this)"><i class="fal fa-angle-right fa-lg py-3"></i></a>
</div>
<main class="col px-5 pl-md-2 main">
<div class="row">
<div class="col-xl-12">
<div id="panel-5" class="panel">
<div class="panel-container show">
<div class="panel-content">
<div class="row subheader">
<div class="col-xl-2">
<h1 class="subheader-title">
<span class="icon-stack fa-1x">
<i class="base-7 icon-stack-3x color-info-500"></i>
<i class="base-7 icon-stack-2x color-info-700"></i>
<i class="ni ni-graph icon-stack-1x text-white"></i>
</span>
<span id="power-station-title">新竹巨城站</span>
</h1>
</div>
<div class="col-xl-3 d-flex justify-content-start">
<p class="card-text px-3"><i class="fal fa-cloud-sun-rain fa-3x" id="weather-icon"></i></p>
<p class="font-weight-bold" id="weather-temp">27°C<br>降雨幾率: 15%</p>
</div>
</div>
<ul class="nav nav-tabs mb-5" role="tablist">
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_UpToDate"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4 active" data-toggle="tab" href="#tab-overview-uptodate" role="tab">
<i class="fal fa-monitor-heart-rate text-success"></i> <span class="hidden-sm-down ml-1">即時資訊</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Info"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-info" role="tab">
<i class="fal fa-info-square text-success"></i> <span class="hidden-sm-down ml-1">基本資料</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_History"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-history" role="tab">
<i class="fal fa-history text-success"></i> <span class="hidden-sm-down ml-1">歷史資料</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Inverter"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-inverter" role="tab">
<i class="fal fa-analytics text-success"></i> <span class="hidden-sm-down ml-1">逆變器分析</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Exception"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-exception" role="tab">
<i class="fal fa-sensor-alert text-success"></i> <span class="hidden-sm-down ml-1">異常記錄</span>
</a>
</li>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_OperationRecord"))
{
<li class="nav-item">
<a class="nav-link fs-lg px-4" data-toggle="tab" href="#tab-overview-operationRecord" role="tab">
<i class="fal fa-digital-tachograph text-success"></i> <span class="hidden-sm-down ml-1">運維記錄</span>
</a>
</li>
}
</ul>
<div class="tab-content p-3">
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_UpToDate"))
{
<div class="tab-pane fade show active" id="tab-overview-uptodate" role="tabpanel" aria-labelledby="tab-overview-uptodate">
@Html.Partial("_UpToDate")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Info"))
{
<div class="tab-pane fade" id="tab-overview-info" role="tabpanel" aria-labelledby="tab-overview-info">
@Html.Partial("_Info")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_History"))
{
<div class="tab-pane fade" id="tab-overview-history" role="tabpanel" aria-labelledby="tab-overview-history">
@Html.Partial("_History")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Inverter"))
{
<div class="tab-pane fade" id="tab-overview-inverter" role="tabpanel" aria-labelledby="tab-overview-inverter">
@Html.Partial("_Inverter")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_Exception"))
{
<div class="tab-pane fade" id="tab-overview-exception" role="tabpanel" aria-labelledby="tab-overview-exception">
@Html.Partial("_Exception")
</div>
}
@if (ViewBag.myUser.Role.Layer == (int)RoleLayerEnum.PlatformAdmin || ViewBag.auths.Contains("StationOverview_OperationRecord"))
{
<div class="tab-pane fade" id="tab-overview-operationRecord" role="tabpanel" aria-labelledby="tab-overview-operationRecord">
@Html.Partial("_OperationRecord")
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div> </div>
</div> </div>
@section Scripts{ @section Scripts{
<script src="https://code.highcharts.com/highcharts.js"></script> <script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/heatmap.js"></script> <script src="https://code.highcharts.com/modules/heatmap.js"></script>
<script> <script>
var localurl = this.location.href;
var powerids = new Array(0);//當前選擇電站 var powerids = new Array(0);//當前選擇電站
var Type = 0; // 項目 var Type = 0; // 項目
var stationId; var stationId;
@ -160,6 +182,13 @@
var url = new URL(location.href); var url = new URL(location.href);
stationId = url.searchParams.get('stationId'); stationId = url.searchParams.get('stationId');
GetPowerStationCollapse();
$('#js_list_accordion_filter').change(function () {
var filter = $(this).val();
GetPowerStationCollapse(filter);
});
//#region 即時資訊tab //#region 即時資訊tab
var url = "/StationOverview/GetOneStationUpToDateInfo"; var url = "/StationOverview/GetOneStationUpToDateInfo";
var send_data = { var send_data = {
@ -795,7 +824,7 @@
//#region 逆變器分析 tab //#region 逆變器分析 tab
ChangeInverterkwhBarDaily(); ChangeInverterkwhBarDaily('');
//#region 載入電站逆變器資料 //#region 載入電站逆變器資料
var url = "/StationOverview/GetInverterCheckBox"; var url = "/StationOverview/GetInverterCheckBox";
@ -928,6 +957,72 @@
getTable(); getTable();
}); });
//#region 變更左邊電站Collapse選單箭頭
function ChangePowerStationCollapse(div) {
var className = $(div).children("i").attr("class");
if (className == "fal fa-angle-left fa-lg py-3") {
$(div).children("i").attr("class", "fal fa-angle-right fa-lg py-3");
}
else {
$(div).children("i").attr("class", "fal fa-angle-left fa-lg py-3");
}
}
//#endregion
function GetPowerStationCollapse(filter) {
var url = "/StationOverview/GetPowerStationCollapse"
var send_data = {
Filter: filter
}
$.post(url, send_data, function (rel) {
if (rel.code != "0000") {
toast_error(rel.data.msg);
return;
}
$('#js_list_accordion').empty();
if (rel.data.length <= 0) {
$('#js_list_accordion').append("<div>查無結果</div>");
}
var str = "";
$.each(rel.data, function (index, item) {
str += '<div class="card border-top-left-radius-0 border-top-right-radius-0" id="templateCard">' +
'<div class="card-header">' +
'<a href="javascript:void(0);" class="card-title collapsed" data-toggle="collapse" data-target="#js_list_accordion-' + index + '" aria-expanded="false" data-filter-tags="settings">' +
'<i class="fal fa-globe width-2 fs-xl"></i>' +
'<span class="city-name">' + item.cityName + '</span>' +
'<span class="ml-auto">' +
'<span class="collapsed-reveal"><i class="fal fa-chevron-up fs-xl"></i></span>' +
'<span class="collapsed-hidden"><i class="fal fa-chevron-down fs-xl"></i></span>' +
'</span>' +
'</a>' +
'</div>' +
'<div id="js_list_accordion-' + index + '" class="collapse" data-parent="#js_list_accordion" style="">' +
'<div class="card-body">' +
'<ul class="list-group">';
$.each(item.myPowerStations, function (index, power_station) {
str += '<li class="list-group-item">' +
'<a href="/StationOverview/Info?stationId=' + power_station.powerStationId + '">' + power_station.powerStationName + '</a>' +
'</li>';
});
str += '</ul>';
str += '</div>';
str += '</div>';
});
$('#js_list_accordion').append(str);
$('#js_list_accordion').find('.card').first().addClass(" border-top-left-radius-0 border-top-right-radius-0");
}, 'json');
}
//#region 產生檔案html //#region 產生檔案html

View File

@ -1,11 +1,11 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="card-columns"> <div class="card-columns">
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> 發電量</h4>
<div class="ml-auto">kwh</div> <div class="ml-auto">kwh</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>今日發電量</p> <p>今日發電量</p>
<p><span class="color-info-700" id="today_kwh">126,161.72</span></p> <p><span class="color-info-700" id="today_kwh">126,161.72</span></p>
@ -17,11 +17,11 @@
</div> </div>
</div> </div>
<div class="card money-card"> <div class="card money-card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-dollar-sign mr-1"></span> <span id="money-card-title">發電金額</span></h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-dollar-sign mr-1"></span> <span id="money-card-title">發電金額</span></h4>
<div class="ml-auto">NTD</div> <div class="ml-auto">NTD</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p id="money-card-subtitle-total">總發金額</p> <p id="money-card-subtitle-total">總發金額</p>
<p><span class="color-info-700" id="total_money">126,161.72</span></p> <p><span class="color-info-700" id="total_money">126,161.72</span></p>
@ -33,11 +33,11 @@
</div> </div>
</div> </div>
<div class="card irradiance-card"> <div class="card irradiance-card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> 日照度</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> 日照度</h4>
<div class="ml-auto">kw/m<sup>2</sup></div> <div class="ml-auto">kw/m<sup>2</sup></div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均日照度</p> <p>即時平均日照度</p>
<p><span class="color-info-700" id="today_irradiance">126,161.72</span></p> <p><span class="color-info-700" id="today_irradiance">126,161.72</span></p>
@ -49,10 +49,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> PR值</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-bolt mr-1"></span> PR值</h4>
<div class="ml-auto">%</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均 PR 值</p> <p>即時平均 PR 值</p>
<p><span class="color-info-700" id="today_PR">119.04</span></p> <p><span class="color-info-700" id="today_PR">119.04</span></p>
@ -64,10 +65,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> kWh / kWp</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-sun mr-1"></span> kWh / kWp</h4>
<div class="ml-auto">hr</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>即時平均 kWh / kWp</p> <p>即時平均 kWh / kWp</p>
<p><span class="color-info-700" id="today_kwhkwp">140.39</span></p> <p><span class="color-info-700" id="today_kwhkwp">140.39</span></p>
@ -79,11 +81,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="card-header bg-fusion-25 pr-3 d-flex align-items-center flex-wrap"> <div class="card-header bg-fusion-25 py-2 pr-3 d-flex align-items-center flex-wrap">
<h4 class="mb-0 font-weight-bold"><span class="fal fa-cow mr-1"></span> 減碳量</h4> <h4 class="mb-0 font-weight-bold"><span class="fal fa-cow mr-1"></span> 減碳量</h4>
<div class="ml-auto">kG</div> <div class="ml-auto">kG</div>
</div> </div>
<div class="card-body" style="min-height: 148px;"> <div class="card-body">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<p>今日減碳量</p> <p>今日減碳量</p>
<p><span class="color-info-700" id="today_carbon">6,091.78</span></p> <p><span class="color-info-700" id="today_carbon">6,091.78</span></p>

View File

@ -6,7 +6,7 @@
"Microsoft.Hosting.Lifetime": "Information" "Microsoft.Hosting.Lifetime": "Information"
} }
}, },
"LoginExpireMinute": 60, //() "LoginExpireMinute": 60, //?n?J???????A???(??)
"DBConfig": { "DBConfig": {
"Server": "MVgHWzR3rGDgD57TUoFunA==", "Server": "MVgHWzR3rGDgD57TUoFunA==",
"port": "r4AoXMUDodcQjIzofGNCcg==", "port": "r4AoXMUDodcQjIzofGNCcg==",
@ -24,8 +24,8 @@
"BackgroundServiceCron": { "BackgroundServiceCron": {
"CalcPowerStationJob": "0 5 * * * ?", "CalcPowerStationJob": "0 5 * * * ?",
"CalcAvgPowerStationJob": "0 0 2 * * ?", "CalcAvgPowerStationJob": "0 0 2 * * ?",
//"CalcAvgPowerStationJob": "0/3 * * * * ?", "OperationScheduleJob": "0 0 2 * * ?",
"OperationScheduleJob": "0 0 2 * * ?" "CalcInverter15minJob": "0 2/15 * * * ?"
}, },
"SMTPConfig": { "SMTPConfig": {
"Host": "smtp.gmail.com", "Host": "smtp.gmail.com",

View File

@ -25,7 +25,8 @@
"BackgroundServiceCron": { "BackgroundServiceCron": {
"CalcPowerStationJob": "0 5 * * * ?", "CalcPowerStationJob": "0 5 * * * ?",
"CalcAvgPowerStationJob": "0 0 2 * * ?", "CalcAvgPowerStationJob": "0 0 2 * * ?",
"OperationScheduleJob": "0 0 2 * * ?" "OperationScheduleJob": "0 0 2 * * ?",
"CalcInverter15minJob": "0 2/15 * * * ?"
}, },
"SMTPConfig": { "SMTPConfig": {
"Host": "smtp.gmail.com", "Host": "smtp.gmail.com",

View File

@ -866,7 +866,7 @@ html {
/* app logo */ /* app logo */
.page-logo { .page-logo {
height: 4.125rem; height: 4.125rem;
width: 16.875rem; width: 15.29rem;
-webkit-box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.13); -webkit-box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.13);
box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.13); box-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.13);
overflow: hidden; overflow: hidden;
@ -885,8 +885,9 @@ html {
min-height: 1px; min-height: 1px;
padding: 0 2rem; } padding: 0 2rem; }
.page-logo img { .page-logo img {
/*width: 28px;*/ /*width: 28px;
height: 28px; } height: 28px; */
}
.page-logo .page-logo-link { .page-logo .page-logo-link {
-webkit-box-flex: 1; -webkit-box-flex: 1;
-ms-flex: 1 0 auto; -ms-flex: 1 0 auto;
@ -1153,8 +1154,8 @@ html {
-webkit-box-flex: 1; -webkit-box-flex: 1;
-ms-flex: 1 0 auto; -ms-flex: 1 0 auto;
flex: 1 0 auto; flex: 1 0 auto;
width: 16.875rem; width: 15.29rem;
max-width: 16.875rem; max-width: 15.29rem;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-box-direction: normal; -webkit-box-direction: normal;
-ms-flex-direction: column; -ms-flex-direction: column;
@ -1524,7 +1525,7 @@ html {
}*/ }*/
@media (min-width: 1399px) { @media (min-width: 1399px) {
.page-sidebar .primary-nav .nav-menu > li > a { .page-sidebar .primary-nav .nav-menu > li > a {
font-size: 1.125rem; } } font-size: 1rem; } }
/* app navigation filter */ /* app navigation filter */
.nav-filter { .nav-filter {
@ -2431,7 +2432,7 @@ html {
/* app content heading */ /* app content heading */
.subheader:not(:empty) { .subheader:not(:empty) {
margin-bottom: calc(1.5rem + 0.625rem); margin-bottom: calc(.5rem + 0.625rem);
position: relative; position: relative;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
@ -2738,7 +2739,7 @@ html {
.page-breadcrumb { .page-breadcrumb {
padding: 0; padding: 0;
background: transparent; background: transparent;
margin: 0 0 1.5rem; margin: 0 0 1rem;
position: relative; position: relative;
text-shadow: #fff 0 1px; } text-shadow: #fff 0 1px; }

View File

@ -3033,3 +3033,63 @@ body:not(.mod-pace-custom) .pace .pace-progress {
background: #fff; } background: #fff; }
/*# sourceMappingURL=cust-theme-15.css.map */ /*# sourceMappingURL=cust-theme-15.css.map */
.map-responsive{
overflow:hidden;
padding-bottom:50%;
position:relative;
height:0;
}
.map-responsive iframe{
left:0;
top:0;
height:100%;
width:100%;
position:absolute;
}
.collapse.width {
width: 0;
max-width: 0;
height: 100%;
transition: right 0.3s linear, max-width 0.3s linear;
position: relative;
top: 0;
right: 100%;
left: 0;
display: block;
overflow: hidden;
}
.vh-100 {
min-height: 100vh;
}
.collapsing.width {
transition: right 0.3s linear, max-width 0.7s linear;
width: 0% !important;
height: 100%;
max-width: 0% !important;
min-width: 0;
right: 0;
position: relative;
display: block;
}
.collapse .list-group-item {
white-space:nowrap
}
.collapse.width.show {
transition: right 0.3s linear, max-width 0.3s linear;
width: 100%;
height: 100%;
max-width: 100%;
min-width: 50px;
right: 0;
position: relative;
display: block;
}

View File

@ -6927,7 +6927,7 @@ button.bg-dark:focus {
.mb-5, .mb-5,
.my-5 { .my-5 {
margin-bottom: 2rem !important; } margin-bottom: 1rem !important; }
.ml-5, .ml-5,
.mx-5 { .mx-5 {