1. 電站總覽 單一電站內容加入左邊選單
2. 背景執行加入 log說明 3. bug fix
This commit is contained in:
parent
3e04132b06
commit
2490884c8a
@ -65,6 +65,26 @@ namespace SolarPower.Controllers
|
||||
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]
|
||||
public async Task<ApiResult<MapOverview>> GetStationCard(StationIds post)
|
||||
{
|
||||
|
||||
@ -1579,6 +1579,24 @@ ALTER TABLE `operation_plan_create`
|
||||
ALTER TABLE `operation_record`
|
||||
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
|
||||
;
|
||||
|
||||
|
||||
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
|
||||
@ -28,7 +28,10 @@ namespace SolarPower.Quartz.Jobs
|
||||
try
|
||||
{
|
||||
#region step1. 找出所有電站
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得電站資料】");
|
||||
var powerStations = await powerStationRepository.GetAllAsync();
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功電站資料】");
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
|
||||
#endregion
|
||||
|
||||
List<PowerStation> calcAvgPowerStations = new List<PowerStation>();
|
||||
@ -52,14 +55,16 @@ namespace SolarPower.Quartz.Jobs
|
||||
var count = 0;
|
||||
|
||||
#region 氣象觀測(取資料)
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得氣象觀測】");
|
||||
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";
|
||||
HttpResponseMessage response = client.GetAsync(UVUri).Result;
|
||||
String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
|
||||
Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs);
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【取得成功氣象觀測】");
|
||||
#endregion
|
||||
|
||||
foreach(var location in observation.Records.Location)
|
||||
foreach (var location in observation.Records.Location)
|
||||
{
|
||||
WeatherForecast weatherForecast = new WeatherForecast();
|
||||
weatherForecast.LocationName = location.LocationName;
|
||||
@ -149,10 +154,14 @@ namespace SolarPower.Quartz.Jobs
|
||||
var dateNowDay = DateTimeNow.AddDays(-1).ToString("yyyy-MM-dd");
|
||||
|
||||
#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);
|
||||
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)
|
||||
{
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
|
||||
history.PowerStationId = powerStation.Id;
|
||||
|
||||
#region 計算電站30天的 kWh/kWp 與 PR 值
|
||||
@ -169,11 +178,15 @@ namespace SolarPower.Quartz.Jobs
|
||||
|
||||
#endregion
|
||||
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的30天平均資料】", powerStation.Code, dateNowDay);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region step2-2 計算電站30天的日照計平均值
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的30天日照計平均資料】", powerStation.Code, dateNowDay);
|
||||
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)
|
||||
{
|
||||
calcPowerStation.Avg_irradiance = avgPyrheliometerHistory.AvgIrradiance;
|
||||
@ -184,7 +197,10 @@ namespace SolarPower.Quartz.Jobs
|
||||
|
||||
#region step2-3. 計算昨天的所有值總和
|
||||
//電站資訊
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始取得電站[{0}]在{1}的所有值的總和】", powerStation.Code, dateNowDay);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的日照計所有值的平均】", powerStation.Code, dateNowDay);
|
||||
if (pyrheliometerHistorDay != null)
|
||||
{
|
||||
pyrheliometerHistoryDays.Add(pyrheliometerHistorDay);
|
||||
}
|
||||
|
||||
//逆變器
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}的逆變器所有值的平均】", powerStation.Code, dateNowDay);
|
||||
var inverterHistoriesDay = await powerStationRepository.CalcInverterHistoryDayDataByPowerStationId(dateNowDay, powerStation.SiteDB, powerStation.Id);
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}的逆變器所有值的平均】", powerStation.Code, dateNowDay);
|
||||
if (inverterHistoriesDay != null)
|
||||
{
|
||||
foreach(var inverterHistoryDay in inverterHistoriesDay)
|
||||
@ -214,6 +234,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
var dateNowMonth = DateTimeNow.ToString("yyyy-MM");
|
||||
|
||||
//電站該月份的歷史資料
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【開始計算電站[{0}]在{1}月份的歷史資料總和】", powerStation.Code, dateNowMonth);
|
||||
var exist_history = await powerStationRepository.GetOnePowerStationHistoryByPowerStationIdAndMonth(powerStation.Id, dateNowMonth);
|
||||
if (exist_history == null)
|
||||
{ //新增
|
||||
@ -224,6 +245,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
|
||||
insertPowerStationHistoryMonths.Add(historyMonth);
|
||||
}
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的歷史資料總和】", powerStation.Code, dateNowMonth);
|
||||
}
|
||||
else
|
||||
{ //修改
|
||||
@ -232,9 +254,12 @@ namespace SolarPower.Quartz.Jobs
|
||||
{
|
||||
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);
|
||||
if (exist_pyrheliometer_history == null)
|
||||
{ //新增
|
||||
@ -244,6 +269,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
pyrheliometerHistoryMonth.Timestamp = Convert.ToDateTime(pyrheliometerHistoryMonth.Timestamp).ToString("yyyy-MM-dd");
|
||||
insertPyrheliometerHistoryMonths.Add(pyrheliometerHistoryMonth);
|
||||
}
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的日照度歷史資料】", powerStation.Code, dateNowMonth);
|
||||
}
|
||||
else
|
||||
{ //修改
|
||||
@ -252,9 +278,11 @@ namespace SolarPower.Quartz.Jobs
|
||||
{
|
||||
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);
|
||||
if (exist_inverter_histories.Count == 0 )
|
||||
{ //新增
|
||||
@ -267,6 +295,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
insertInverterHistoryMonths.Add(inverterHistoryMonth);
|
||||
}
|
||||
}
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的逆變器歷史資料】", powerStation.Code, dateNowMonth);
|
||||
}
|
||||
else
|
||||
{ //修改
|
||||
@ -279,6 +308,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
updateInverterHistoryMonths.Add(inverterHistoryMonth);
|
||||
}
|
||||
}
|
||||
logger.LogInformation("【CalcAvgPowerStationJob】【計算完成電站[{0}]在{1}月份的逆變器歷史資料】", powerStation.Code, dateNowMonth);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@ -25,9 +25,11 @@ namespace SolarPower.Quartz.Jobs
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
#region step1. 找出所有電站
|
||||
logger.LogInformation("【CalcInverter15minJob】【開始取得電站資料】");
|
||||
var powerStations = await powerStationRepository.GetAllAsync();
|
||||
logger.LogInformation("【CalcPowerStationJob】【取得成功電站資料】");
|
||||
logger.LogInformation("【CalcPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
|
||||
#endregion
|
||||
|
||||
List<InverterHistory> calcInverter15mins = new List<InverterHistory>();
|
||||
@ -44,47 +46,28 @@ namespace SolarPower.Quartz.Jobs
|
||||
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");
|
||||
|
||||
#region step2-1. 計算該電站的30天平均資料
|
||||
var table_name = String.Format("`{0}`.`{1}01_inv`", powerStation.SiteDB, powerStation.Code);
|
||||
var history = await powerStationRepository.CalcInverterHisyort15minData(dateNowTime, table_name, inverterIds);
|
||||
if (history != null)
|
||||
//取得所有該電站的逆變器
|
||||
logger.LogInformation("【CalcInverter15minJob】【開始取得電站[{0}]在{1}的逆變器設備資訊】", powerStation.Code, dateNowTime);
|
||||
var controllers = await powerStationRepository.GetAllDeviceControllerId(powerStation.Id, powerStation.SiteDB);
|
||||
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;
|
||||
|
||||
#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)
|
||||
foreach (var inverterHistory in calcInverter15mins)
|
||||
{
|
||||
allofInverterHistorDays.Add(inverterHistoryDay);
|
||||
inverterHistory.TIMESTAMP = Convert.ToDateTime(inverterHistory.TIMESTAMP + ":00").ToString("yyyy-MM-dd HH:mm:ss");
|
||||
inverterHistory.PowerStationId = powerStation.Id;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@ -93,115 +76,24 @@ namespace SolarPower.Quartz.Jobs
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region step3. calcPowerStations UPDATE 到 power_station 資料表
|
||||
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 各資料表
|
||||
#region step3. 將 inverter INSERT 到 inverter_history_hour 資料表
|
||||
List<string> inverter_history_properties = new List<string>()
|
||||
{
|
||||
"PowerStationId",
|
||||
"TIMESTAMP",
|
||||
"INVERTERID",
|
||||
"TIMESTAMP",
|
||||
"KWH",
|
||||
"TODAYKWH",
|
||||
"KWHKWP",
|
||||
};
|
||||
//每日
|
||||
await powerStationRepository.AddInverterHistoryDayList(allofInverterHistorDays, inverter_history_properties);
|
||||
|
||||
//每月
|
||||
if (insertInverterHistoryMonths.Count > 0)
|
||||
{
|
||||
await powerStationRepository.AddInverterHistoryMonthList(insertInverterHistoryMonths, inverter_history_properties);
|
||||
}
|
||||
|
||||
if (updateInverterHistoryMonths.Count > 0)
|
||||
{
|
||||
await powerStationRepository.UpdateInverterHistoryMonthList(updateInverterHistoryMonths);
|
||||
}
|
||||
await powerStationRepository.AddInverter15minHistory(calcInverter15mins, inverter_history_properties);
|
||||
#endregion
|
||||
*/
|
||||
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
logger.LogError("【{0}】{1}", "CalcAvgPowerStationJob", exception.Message);
|
||||
logger.LogError("【{0}】{1}", "CalcInverter15minJob", exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,10 +30,10 @@ namespace SolarPower.Quartz.Jobs
|
||||
try
|
||||
{
|
||||
#region step1. 找出所有電站
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始取得電站資料】");
|
||||
var powerStations = await powerStationRepository.GetAllAsync();
|
||||
|
||||
string json = System.Text.Json.JsonSerializer.Serialize(powerStations);
|
||||
logger.LogError("【{0}】{1}", "CalcPowerStationJob - step1", json);
|
||||
logger.LogInformation("【CalcPowerStationJob】【取得成功電站資料】");
|
||||
logger.LogInformation("【CalcPowerStationJob】【電站資料】 - {0}", System.Text.Json.JsonSerializer.Serialize(powerStations));
|
||||
#endregion
|
||||
|
||||
List<PowerStationHistory> powerStationHistoriesHour = new List<PowerStationHistory>();
|
||||
@ -47,11 +47,13 @@ namespace SolarPower.Quartz.Jobs
|
||||
|
||||
var count = 0;
|
||||
#region 氣象觀測(取資料)
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始取得氣象觀測】");
|
||||
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";
|
||||
HttpResponseMessage response = client.GetAsync(UVUri).Result;
|
||||
String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
|
||||
Root2 observation = JsonConvert.DeserializeObject<Root2>(jsonUVs);
|
||||
logger.LogInformation("【CalcPowerStationJob】【取得成功氣象觀測】");
|
||||
#endregion
|
||||
|
||||
|
||||
@ -69,15 +71,16 @@ namespace SolarPower.Quartz.Jobs
|
||||
var dateTime = DateTimeNow.AddHours(-1).ToString("yyyy-MM-dd HH");
|
||||
|
||||
#region step2-1. 取得該電站的當前這小時的歷史資料
|
||||
var table_name = String.Format("`{0}`.{1}01_station", powerStation.SiteDB, powerStation.Code);
|
||||
logger.LogError("【{0}】{1}", "CalcPowerStationJob - time & dataTable", dateTime + "======" + table_name);
|
||||
var table_name = String.Format("`{0}`.s{1}01_station", powerStation.SiteDB, powerStation.Code);
|
||||
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
|
||||
var history = await powerStationRepository.GetPowerStationHistoryPerHour(dateTime, table_name);
|
||||
json = System.Text.Json.JsonSerializer.Serialize(history);
|
||||
logger.LogError("【{0}】{1}", "CalcPowerStationJob - history", json);
|
||||
logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
|
||||
logger.LogInformation("【CalcPowerStationJob】【電站[{0}]在{1}的每小時歷史資料】 - {2}", powerStation.Code, dateTime, System.Text.Json.JsonSerializer.Serialize(history));
|
||||
|
||||
if (history != null)
|
||||
{
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
|
||||
history.PowerStationId = powerStation.Id;
|
||||
history.Timestamp = Convert.ToDateTime(history.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@ -153,17 +156,22 @@ namespace SolarPower.Quartz.Jobs
|
||||
#endregion
|
||||
|
||||
powerStationHistoriesHour.Add(history);
|
||||
|
||||
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的每小時歷史資料】", powerStation.Code, dateTime);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region step2-2. 取得該電站的當前這小時的日照度歷史資料
|
||||
//1. 找出該電站所有日照計設備(包含共享
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始取得電站[{0}]在{1}的日照計設備資訊】", powerStation.Code, dateTime);
|
||||
var deviceInfos = await powerStationRepository.GetListPyrheliometerByPowerStationId(powerStation.Id, powerStation.SiteDB);
|
||||
// 找出該電站所有溫度計設備(包含共享
|
||||
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(deviceInfos));
|
||||
|
||||
if (deviceInfos != null)
|
||||
{
|
||||
//2. 計算該電站所有日照計設的每小時的平均在依照日照計數量平均
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的日照計的日照度】", powerStation.Code, dateTime);
|
||||
var pyrheliometerHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, deviceInfos, 0);
|
||||
|
||||
if (pyrheliometerHistory != null)
|
||||
@ -174,32 +182,47 @@ namespace SolarPower.Quartz.Jobs
|
||||
pyrheliometerHistory.PowerStationId = powerStation.Id;
|
||||
pyrheliometerHistoriesHour.Add(pyrheliometerHistory);
|
||||
}
|
||||
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的日照計的日照度】", powerStation.Code, dateTime);
|
||||
}
|
||||
//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)
|
||||
{
|
||||
logger.LogInformation("【CalcPowerStationJob】【開始計算電站[{0}]在{1}的溫度計的平均溫度】", powerStation.Code, dateTime);
|
||||
var tempHistory = await powerStationRepository.GetPyrheliometerHistoryPerHour(dateTime, tempdeviceInfos, 1);
|
||||
if (tempHistory != null)
|
||||
{
|
||||
tempHistory.Timestamp = Convert.ToDateTime(tempHistory.Timestamp + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
|
||||
tempHistory.PowerStationId = powerStation.Id;
|
||||
TempHistoriesHour.Add(tempHistory);
|
||||
|
||||
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的溫度計的平均溫度】", powerStation.Code, dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#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)
|
||||
{
|
||||
inverterHistory.TIMESTAMP = Convert.ToDateTime(inverterHistory.TIMESTAMP + ":00:00").ToString("yyyy-MM-dd HH:mm:ss");
|
||||
inverterHistory.PowerStationId = powerStation.Id;
|
||||
}
|
||||
|
||||
logger.LogInformation("【CalcPowerStationJob】【計算完成電站[{0}]在{1}的逆變器的資訊】", powerStation.Code, dateTime);
|
||||
#endregion
|
||||
|
||||
#region 確認是否有觀測站(沒有則新增)
|
||||
@ -226,9 +249,9 @@ namespace SolarPower.Quartz.Jobs
|
||||
WeatherObservation weatherObservation = new WeatherObservation();
|
||||
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);
|
||||
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);
|
||||
calcPowerStation.TodayWeather = weather.WeatherKey;
|
||||
calcPowerStation.RateOfRain = weather.PoP;
|
||||
logger.LogInformation("【CalcPowerStationJob】【取得成功電站[{0}]在{1}的天氣預報的資訊】", powerStation.Code, dateTime);
|
||||
if(weather != null)
|
||||
{
|
||||
calcPowerStation.TodayWeather = weather.WeatherKey;
|
||||
calcPowerStation.RateOfRain = weather.PoP;
|
||||
}
|
||||
|
||||
weatherObservations.Add(weatherObservation);
|
||||
calcPowerStations.Add(calcPowerStation);
|
||||
|
||||
count++;
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -268,9 +295,6 @@ namespace SolarPower.Quartz.Jobs
|
||||
"SolarHour"
|
||||
};
|
||||
|
||||
json = System.Text.Json.JsonSerializer.Serialize(powerStationHistoriesHour);
|
||||
logger.LogError("【{0}】{1}", "CalcPowerStationJob - step3", json);
|
||||
|
||||
await powerStationRepository.AddPowerStationHistory(powerStationHistoriesHour, history_properties);
|
||||
#endregion
|
||||
|
||||
@ -328,7 +352,7 @@ namespace SolarPower.Quartz.Jobs
|
||||
"KWHKWP",
|
||||
};
|
||||
|
||||
await powerStationRepository.AddInverterHisyort(inverterHistories, inverter_history_properties);
|
||||
await powerStationRepository.AddInverterHistory(inverterHistories, inverter_history_properties);
|
||||
#endregion
|
||||
|
||||
List<string> weather_observation_properties = new List<string>()
|
||||
@ -338,10 +362,6 @@ namespace SolarPower.Quartz.Jobs
|
||||
"Temp"
|
||||
};
|
||||
await powerStationRepository.AddWeatherObservation(weatherObservations, weather_observation_properties);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
@ -315,7 +315,7 @@ namespace SolarPower.Repository.Implement
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
@ -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>();
|
||||
|
||||
@ -35,7 +35,7 @@ namespace SolarPower.Repository.Implement
|
||||
FROM power_station ps
|
||||
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";
|
||||
}
|
||||
@ -49,7 +49,12 @@ namespace SolarPower.Repository.Implement
|
||||
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);
|
||||
|
||||
@ -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 = "";
|
||||
if(type == 1)
|
||||
if (type == 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)
|
||||
//{
|
||||
// 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)
|
||||
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 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
|
||||
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
|
||||
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
|
||||
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
|
||||
AND inv.INVERTERID IN @InverterIds
|
||||
GROUP BY FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H'), inv.INVERTERID) a
|
||||
ON FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H') = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID
|
||||
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
|
||||
";
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
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();
|
||||
using (IDbConnection conn = this._databaseHelper.GetConnection())
|
||||
|
||||
@ -16,7 +16,7 @@ namespace SolarPower.Repository.Interface
|
||||
/// </summary>
|
||||
/// <param name="myUser"></param>
|
||||
/// <returns></returns>
|
||||
List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser);
|
||||
List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// 查詢縣市列表
|
||||
@ -518,9 +518,10 @@ namespace SolarPower.Repository.Interface
|
||||
|
||||
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>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name);
|
||||
Task<int> AddInverterHisyort(List<InverterHistory> entity, List<string> properties);
|
||||
Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string db_name, string table_name, List<string> inverterIds);
|
||||
Task<int> AddInverter15minHistory(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<int> AddInverterHistoryDayList(List<InverterHistory> entity, List<string> properties);
|
||||
Task<List<InverterHistory>> GetInverterHistoryByPowerStationIdAndMonth(string month, int powerStationId);
|
||||
|
||||
@ -98,6 +98,13 @@ namespace SolarPower
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region 計算電站逆變器資訊(每整點2分開始執行15分鐘一個循環)
|
||||
services.AddSingleton<CalcInverter15minJob>();
|
||||
services.AddSingleton(
|
||||
new JobSchedule(jobType: typeof(CalcInverter15minJob), cronExpression: Configuration.GetValue<string>("BackgroundServiceCron:CalcInverter15minJob"))
|
||||
);
|
||||
#endregion
|
||||
|
||||
#region 計算電站發電量等資訊(每整點5分執行)
|
||||
services.AddSingleton<CalcPowerStationJob>();
|
||||
services.AddSingleton(
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<!-- Your main content goes below here: -->
|
||||
|
||||
<div class="row mb-5">
|
||||
<div class="card-columns col-xl-12">
|
||||
<div class="card-columns">
|
||||
<div class="card">
|
||||
<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>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<!-- we wrap header title inside a div tag with utility padding -->
|
||||
<div class="card-title font-weight-bold">控制器</div>
|
||||
<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> 新增
|
||||
</a>
|
||||
</div>
|
||||
@ -32,7 +32,7 @@
|
||||
<!-- we wrap header title inside a div tag with utility padding -->
|
||||
<div class="card-title font-weight-bold">逆變器</div>
|
||||
<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> 新增
|
||||
</a>
|
||||
</div>
|
||||
@ -67,7 +67,7 @@
|
||||
<!-- we wrap header title inside a div tag with utility padding -->
|
||||
<div class="card-title font-weight-bold">裝置設定</div>
|
||||
<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> 新增
|
||||
</a>
|
||||
</div>
|
||||
@ -105,7 +105,7 @@
|
||||
<!-- we wrap header title inside a div tag with utility padding -->
|
||||
<div class="card-title font-weight-bold">共用裝置</div>
|
||||
<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> 新增
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<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="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 -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="~/img/favicon/apple-touch-icon.png">
|
||||
@ -45,6 +45,62 @@
|
||||
|
||||
</head>
|
||||
<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 -->
|
||||
<div class="page-wrapper">
|
||||
|
||||
@ -78,11 +78,11 @@
|
||||
<div class="row mb-5">
|
||||
<div class="card-columns">
|
||||
<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>
|
||||
<div class="ml-auto">kWh</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>今日發電量</p>
|
||||
<p><span class="color-info-700" id="today_kwh">126,161.72</span></p>
|
||||
@ -94,11 +94,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">kW/m<sup>2</sup></div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均日照度</p>
|
||||
<p><span class="color-info-700" id="today_irradiance">126,161.72</span></p>
|
||||
@ -110,11 +110,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">%</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均 PR 值</p>
|
||||
<p><span class="color-info-700" id="today_PR">119.04</span></p>
|
||||
@ -126,11 +126,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">hr</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均 kWh / kWp</p>
|
||||
<p><span class="color-info-700" id="today_kwhkwp">140.39</span></p>
|
||||
@ -142,11 +142,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">kG</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>今日減碳量</p>
|
||||
<p><span class="color-info-700" id="today_carbon">6,091.78</span></p>
|
||||
|
||||
@ -5,144 +5,166 @@
|
||||
}
|
||||
@using SolarPower.Models.Role
|
||||
@model RoleLayerEnum
|
||||
|
||||
<ol class="breadcrumb page-breadcrumb" >
|
||||
<li class="breadcrumb-item"><a href="javascript:void(0);">總覽</a></li>
|
||||
<li class="breadcrumb-item">@ViewData["Title"]</li>
|
||||
<li class="breadcrumb-item city-name" id="breadcrumbcity">新竹市</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>
|
||||
</ol>
|
||||
<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>
|
||||
@*<ol class="breadcrumb page-breadcrumb" >
|
||||
<li class="breadcrumb-item"><a href="javascript:void(0);">總覽</a></li>
|
||||
<li class="breadcrumb-item">@ViewData["Title"]</li>
|
||||
<li class="breadcrumb-item city-name" id="breadcrumbcity">新竹市</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>
|
||||
</ol>*@
|
||||
<div class="container-fluid">
|
||||
<div class="row flex-nowrap wrapper">
|
||||
<div class="col-md-2 col-1 pl-0 pr-0 collapse width border-right sidebar vh-100">
|
||||
<div class="list-group border-0 card text-center text-md-left" id="sidebar">
|
||||
<div class="border bg-light rounded-top">
|
||||
<div class="form-group p-2 m-0 rounded-top">
|
||||
<input type="text" class="form-control form-control-lg shadow-inset-2 m-0" id="js_list_accordion_filter" placeholder="">
|
||||
</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 id="js_list_accordion" class="accordion accordion-hover accordion-clean js-list-filter">
|
||||
</div>
|
||||
<span class="filter-message js-filter-message"></span>
|
||||
</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>
|
||||
|
||||
|
||||
@section Scripts{
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/heatmap.js"></script>
|
||||
|
||||
<script>
|
||||
var localurl = this.location.href;
|
||||
var powerids = new Array(0);//當前選擇電站
|
||||
var Type = 0; // 項目
|
||||
var stationId;
|
||||
@ -160,6 +182,13 @@
|
||||
var url = new URL(location.href);
|
||||
stationId = url.searchParams.get('stationId');
|
||||
|
||||
GetPowerStationCollapse();
|
||||
|
||||
$('#js_list_accordion_filter').change(function () {
|
||||
var filter = $(this).val();
|
||||
GetPowerStationCollapse(filter);
|
||||
});
|
||||
|
||||
//#region 即時資訊tab
|
||||
var url = "/StationOverview/GetOneStationUpToDateInfo";
|
||||
var send_data = {
|
||||
@ -795,7 +824,7 @@
|
||||
|
||||
//#region 逆變器分析 tab
|
||||
|
||||
ChangeInverterkwhBarDaily();
|
||||
ChangeInverterkwhBarDaily('');
|
||||
|
||||
//#region 載入電站逆變器資料
|
||||
var url = "/StationOverview/GetInverterCheckBox";
|
||||
@ -928,6 +957,72 @@
|
||||
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
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<div class="row mb-5">
|
||||
<div class="card-columns">
|
||||
<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>
|
||||
<div class="ml-auto">kwh</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>今日發電量</p>
|
||||
<p><span class="color-info-700" id="today_kwh">126,161.72</span></p>
|
||||
@ -17,11 +17,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">NTD</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p id="money-card-subtitle-total">總發金額</p>
|
||||
<p><span class="color-info-700" id="total_money">126,161.72</span></p>
|
||||
@ -33,11 +33,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">kw/m<sup>2</sup></div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均日照度</p>
|
||||
<p><span class="color-info-700" id="today_irradiance">126,161.72</span></p>
|
||||
@ -49,10 +49,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">%</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均 PR 值</p>
|
||||
<p><span class="color-info-700" id="today_PR">119.04</span></p>
|
||||
@ -64,10 +65,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">hr</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>即時平均 kWh / kWp</p>
|
||||
<p><span class="color-info-700" id="today_kwhkwp">140.39</span></p>
|
||||
@ -79,11 +81,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="ml-auto">kG</div>
|
||||
</div>
|
||||
<div class="card-body" style="min-height: 148px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
<p>今日減碳量</p>
|
||||
<p><span class="color-info-700" id="today_carbon">6,091.78</span></p>
|
||||
|
||||
@ -24,7 +24,8 @@
|
||||
"BackgroundServiceCron": {
|
||||
"CalcPowerStationJob": "0 5 * * * ?",
|
||||
"CalcAvgPowerStationJob": "0 0 2 * * ?",
|
||||
"OperationScheduleJob": "0 0 2 * * ?"
|
||||
"OperationScheduleJob": "0 0 2 * * ?",
|
||||
"CalcInverter15minJob": "0 2/15 * * * ?"
|
||||
},
|
||||
"SMTPConfig": {
|
||||
"Host": "smtp.gmail.com",
|
||||
|
||||
@ -25,7 +25,8 @@
|
||||
"BackgroundServiceCron": {
|
||||
"CalcPowerStationJob": "0 5 * * * ?",
|
||||
"CalcAvgPowerStationJob": "0 0 2 * * ?",
|
||||
"OperationScheduleJob": "0 0 2 * * ?"
|
||||
"OperationScheduleJob": "0 0 2 * * ?",
|
||||
"CalcInverter15minJob": "0 2/15 * * * ?"
|
||||
},
|
||||
"SMTPConfig": {
|
||||
"Host": "smtp.gmail.com",
|
||||
|
||||
@ -866,7 +866,7 @@ html {
|
||||
/* app logo */
|
||||
.page-logo {
|
||||
height: 4.125rem;
|
||||
width: 16.875rem;
|
||||
width: 15.29rem;
|
||||
-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);
|
||||
overflow: hidden;
|
||||
@ -885,8 +885,9 @@ html {
|
||||
min-height: 1px;
|
||||
padding: 0 2rem; }
|
||||
.page-logo img {
|
||||
/*width: 28px;*/
|
||||
height: 28px; }
|
||||
/*width: 28px;
|
||||
height: 28px; */
|
||||
}
|
||||
.page-logo .page-logo-link {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1 0 auto;
|
||||
@ -1153,8 +1154,8 @@ html {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1 0 auto;
|
||||
flex: 1 0 auto;
|
||||
width: 16.875rem;
|
||||
max-width: 16.875rem;
|
||||
width: 15.29rem;
|
||||
max-width: 15.29rem;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
@ -1524,7 +1525,7 @@ html {
|
||||
}*/
|
||||
@media (min-width: 1399px) {
|
||||
.page-sidebar .primary-nav .nav-menu > li > a {
|
||||
font-size: 1.125rem; } }
|
||||
font-size: 1rem; } }
|
||||
|
||||
/* app navigation filter */
|
||||
.nav-filter {
|
||||
@ -2431,7 +2432,7 @@ html {
|
||||
|
||||
/* app content heading */
|
||||
.subheader:not(:empty) {
|
||||
margin-bottom: calc(1.5rem + 0.625rem);
|
||||
margin-bottom: calc(.5rem + 0.625rem);
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
@ -2738,7 +2739,7 @@ html {
|
||||
.page-breadcrumb {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
margin: 0 0 1.5rem;
|
||||
margin: 0 0 1rem;
|
||||
position: relative;
|
||||
text-shadow: #fff 0 1px; }
|
||||
|
||||
|
||||
@ -3033,3 +3033,63 @@ body:not(.mod-pace-custom) .pace .pace-progress {
|
||||
background: #fff; }
|
||||
|
||||
/*# 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;
|
||||
}
|
||||
|
||||
@ -6927,7 +6927,7 @@ button.bg-dark:focus {
|
||||
|
||||
.mb-5,
|
||||
.my-5 {
|
||||
margin-bottom: 2rem !important; }
|
||||
margin-bottom: 1rem !important; }
|
||||
|
||||
.ml-5,
|
||||
.mx-5 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user