[後台] 修改排程流程放置 在後台專案
This commit is contained in:
		
							parent
							
								
									ed02fcdec8
								
							
						
					
					
						commit
						1fe0f2c9a1
					
				@ -23,8 +23,10 @@
 | 
				
			|||||||
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.21" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.21" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.20" />
 | 
					    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.20" />
 | 
				
			||||||
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.5" />
 | 
					    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.5" />
 | 
				
			||||||
 | 
					    <PackageReference Include="ncrontab" Version="3.3.1" />
 | 
				
			||||||
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
 | 
					    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
 | 
				
			||||||
    <PackageReference Include="NPOI" Version="2.5.5" />
 | 
					    <PackageReference Include="NPOI" Version="2.5.5" />
 | 
				
			||||||
 | 
					    <PackageReference Include="Quartz" Version="3.3.3" />
 | 
				
			||||||
    <PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
 | 
					    <PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										198
									
								
								Backend/Quartz/JobSchedule.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								Backend/Quartz/JobSchedule.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,198 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Implement;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using NCrontab;
 | 
				
			||||||
 | 
					using static NCrontab.CrontabSchedule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Job調度中間對象
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class JobSchedule
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public JobSchedule(Type jobType, string cronExpression)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.JobType = jobType ?? throw new ArgumentNullException(nameof(jobType));
 | 
				
			||||||
 | 
					            CronExpression = cronExpression ?? throw new ArgumentNullException(nameof(cronExpression));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Job類型
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public Type JobType { get; private set; }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Cron表達式
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public string CronExpression { get; private set; }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Job狀態
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public JobStatus JobStatu { get; set; } = JobStatus.Init;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Job運行狀態
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public enum JobStatus : byte
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [Description("初始化")]
 | 
				
			||||||
 | 
					        Init = 0,
 | 
				
			||||||
 | 
					        [Description("運行中")]
 | 
				
			||||||
 | 
					        Running = 1,
 | 
				
			||||||
 | 
					        [Description("調度中")]
 | 
				
			||||||
 | 
					        Scheduling = 2,
 | 
				
			||||||
 | 
					        [Description("已停止")]
 | 
				
			||||||
 | 
					        Stopped = 3,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class Task_Detail
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IBackendRepository backendRepository;
 | 
				
			||||||
 | 
					        private readonly ILogger<Task_Detail> logger;
 | 
				
			||||||
 | 
					        public Task_Detail(ILogger<Task_Detail> logger, IBackendRepository backendRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backendRepository = backendRepository;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 取得時間規則
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="task"></param>
 | 
				
			||||||
 | 
					        /// <param name="task_item"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        private async Task<string> GetWorkRule(string task,string task_item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            string Times = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var sql = $@"select b.system_value from task_detail a
 | 
				
			||||||
 | 
					                                join variable b on a.variable_id = b.id
 | 
				
			||||||
 | 
					                                where a.task = '{task}' and a.task_item = '{task_item}'";
 | 
				
			||||||
 | 
					                Times = await backendRepository.GetOneAsync<string>(sql);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch(Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務時間獲取失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務時間獲取失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(),task,task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return Times;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 是否執行任務
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="task"></param>
 | 
				
			||||||
 | 
					        /// <param name="task_item"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public async Task<bool> GetNeedWorkTask(string task, string task_item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var sql = $@"select a.lastwork_time from task_detail a
 | 
				
			||||||
 | 
					                            where a.task = '{task}' and a.task_item = '{task_item}'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var lastworkTime = await backendRepository.GetOneAsync<string>(sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                DateTime dateTime = lastworkTime != null ? Convert.ToDateTime(lastworkTime) : Convert.ToDateTime("1970-01-01 00:00:01");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var nextTime = CrontabSchedule.Parse(await GetWorkRule(task, task_item), new ParseOptions { IncludingSeconds = true } ).GetNextOccurrence(dateTime);
 | 
				
			||||||
 | 
					                if (DateTime.Now >= nextTime)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch(Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【時間解析失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 紀錄任務開始執行時間
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="task"></param>
 | 
				
			||||||
 | 
					        /// <param name="task_item"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public async Task InsertWorkTime(string task, string task_item ,string LoggerWord = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Dictionary<string, object> worktime = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    { "@lastwork_time", DateTime.Now},
 | 
				
			||||||
 | 
					                    { "@success", 2},
 | 
				
			||||||
 | 
					                    { "@updated_at", DateTime.Now},
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(LoggerWord == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogInformation($"【Task_Detail】【開始{task},{task_item}任務】");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                logger.LogInformation($"【Task_Detail】【{LoggerWord}】");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務輸入開始時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 紀錄任務結束時間
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="task"></param>
 | 
				
			||||||
 | 
					        /// <param name="task_item"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public async Task InsertWorkTime_End(string task, string task_item,string LoggerWord = null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Dictionary<string, object> worktime = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    { "@success", 0},
 | 
				
			||||||
 | 
					                    { "@lastwork_end_time", DateTime.Now},
 | 
				
			||||||
 | 
					                    { "@updated_at", DateTime.Now},
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");
 | 
				
			||||||
 | 
					                if (LoggerWord == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogInformation($"【Task_Detail】【結束{task},{task_item}任務】");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                logger.LogInformation($"【Task_Detail】【{LoggerWord}】");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務輸入結束時間】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 執行失敗紀錄
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="task"></param>
 | 
				
			||||||
 | 
					        /// <param name="task_item"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public async Task WorkFail(string task, string task_item,string reason = "")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Dictionary<string, object> worktime = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    { "@success", 1},
 | 
				
			||||||
 | 
					                    { "@updated_at", DateTime.Now},
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                await backendRepository.UpdateOneByCustomTable(worktime, "task_detail", $" task = '{task}' and task_item = '{task_item}'");
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", reason, task, task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【Task_Detail】【任務執行失敗】[Exception]:{0},Task:{1},task_item:{2}", exception.ToString(), task, task_item);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1461
									
								
								Backend/Quartz/Jobs/ArchiveElectricMeterDayJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1461
									
								
								Backend/Quartz/Jobs/ArchiveElectricMeterDayJob.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										335
									
								
								Backend/Quartz/Jobs/ArchiveElectricMeterHourJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								Backend/Quartz/Jobs/ArchiveElectricMeterHourJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,335 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using System.Xml;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 電錶歸檔,每小時執行,只執行小時歸檔
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class ArchiveElectricMeterHourJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<ArchiveElectricMeterHourJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					        private readonly ILogger<Task_Detail> loggers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ArchiveElectricMeterHourJob(
 | 
				
			||||||
 | 
					            ILogger<ArchiveElectricMeterHourJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository, ILogger<Task_Detail> loggers)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.loggers = loggers;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Task_Detail task_Detail = new Task_Detail(loggers, backgroundServiceRepository);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(await task_Detail.GetNeedWorkTask("ArchiveElectricMeterHourJob", "All"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    await task_Detail.InsertWorkTime("ArchiveElectricMeterHourJob", "All", "任務開始");
 | 
				
			||||||
 | 
					                    EDFunction ed = new EDFunction();
 | 
				
			||||||
 | 
					                    XmlDocument xmlDocument = new XmlDocument();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var sqlArchive = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'archiveConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var variableArchive = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlArchive);
 | 
				
			||||||
 | 
					                    var electricMeterGuid = variableArchive.Where(x => x.Name == "ElectricMeterGuid").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 找出所有電錶設備
 | 
				
			||||||
 | 
					                    var sWhere = "deleted = 0 AND sub_system_guid = @sub_system_guid";
 | 
				
			||||||
 | 
					                    var electricMeters = await backgroundServiceRepository.GetAllAsync<Device>("device", sWhere, new { sub_system_guid = electricMeterGuid });
 | 
				
			||||||
 | 
					                    #endregion 找出所有電錶設備
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 找出所有電錶系統的點位
 | 
				
			||||||
 | 
					                    var sPointWhere = "deleted = 0 AND sub_system_guid = @sub_system_guid";
 | 
				
			||||||
 | 
					                    var points = await backgroundServiceRepository.GetAllAsync<Device_item>("device_item", sPointWhere, new { sub_system_guid = electricMeterGuid });
 | 
				
			||||||
 | 
					                    #endregion 找出所有電錶系統的點位
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 組合出所有電錶設備點位
 | 
				
			||||||
 | 
					                    List<DeviceNumberPoint> deviceNumberPoints = new List<DeviceNumberPoint>();
 | 
				
			||||||
 | 
					                    foreach (var electricMeter in electricMeters)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        foreach (var point in points)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                            deviceNumberPoint.DeviceNumber = electricMeter.Device_number;
 | 
				
			||||||
 | 
					                            deviceNumberPoint.Point = point.points;
 | 
				
			||||||
 | 
					                            deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", electricMeter.Device_number, point.points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            deviceNumberPoints.Add(deviceNumberPoint);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endregion 組合出所有電錶設備點位
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 取得obix 設定
 | 
				
			||||||
 | 
					                    var obixApiConfig = new ObixApiConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var variableObix = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlObix);
 | 
				
			||||||
 | 
					                    obixApiConfig.ApiBase = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                    obixApiConfig.UserName = ed.AESDecrypt(variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault());
 | 
				
			||||||
 | 
					                    obixApiConfig.Password = ed.AESDecrypt(variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password));
 | 
				
			||||||
 | 
					                    #endregion 取得obix 設定
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var now = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 小時歸檔
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var preHour = now.AddHours(-1); //取得前一小時
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var tempHour = string.Empty;
 | 
				
			||||||
 | 
					                        if (preHour.Hour < 10)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            tempHour = "0" + preHour.Hour.ToString();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            tempHour = preHour.Hour.ToString();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}T{1}:00:00.000+08:00", preHour.ToString("yyyy-MM-dd"), tempHour);
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}T{1}:59:59.000+08:00", preHour.ToString("yyyy-MM-dd"), tempHour);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                    <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                    <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                    <reltime name='interval' val = 'PT1H' />
 | 
				
			||||||
 | 
					                                                </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //Stopwatch stopWatch = new Stopwatch();
 | 
				
			||||||
 | 
					                        //stopWatch.Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //抓取每個設備的資料
 | 
				
			||||||
 | 
					                        List<Dictionary<string, object>> archiveHourRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                        foreach (var deviceNumberPoint in deviceNumberPoints)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                            //HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                            archiveHourRequest.Method = "POST";
 | 
				
			||||||
 | 
					                            archiveHourRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                            archiveHourRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                            using (Stream reqStream = archiveHourRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebResponse archiveHourResponse = (HttpWebResponse)archiveHourRequest.GetResponse();
 | 
				
			||||||
 | 
					                            var archiveHourResponseContent = new StreamReader(archiveHourResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            xmlDocument.LoadXml(archiveHourResponseContent);
 | 
				
			||||||
 | 
					                            string archiveHourJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                            JObject archiveHourJsonResult = (JObject)JsonConvert.DeserializeObject(archiveHourJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (archiveHourJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                //logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【取得資料失敗】");
 | 
				
			||||||
 | 
					                                //logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveHourJsonResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                Dictionary<string, object> archiveHourRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@point", deviceNumberPoint.Point);
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19));
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19));
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@repeat_times", 0);
 | 
				
			||||||
 | 
					                                archiveHourRawData.Add("@fail_reason", archiveHourJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                archiveHourRawDatas.Add(archiveHourRawData);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (archiveHourJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var histories = archiveHourJsonResult["obj"]["list"];
 | 
				
			||||||
 | 
					                                var rawdateCount = Convert.ToInt32(archiveHourJsonResult["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					                                if (histories != null && histories.HasValues)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (rawdateCount > 1)
 | 
				
			||||||
 | 
					                                    {   //多筆資料
 | 
				
			||||||
 | 
					                                        foreach (var history in histories)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            Dictionary<string, object> archiveHourRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                                            archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
 | 
				
			||||||
 | 
					                                            archiveHourRawData.Add("@point", deviceNumberPoint.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //時間
 | 
				
			||||||
 | 
					                                            if (history["abstime"] != null && history["abstime"].HasValues)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                foreach (var abstime in history["abstime"])
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    var name = abstime["@name"].ToString();
 | 
				
			||||||
 | 
					                                                    switch (name)
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        case "start":
 | 
				
			||||||
 | 
					                                                            var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@start_timestamp", startTimstamp);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                        case "end":
 | 
				
			||||||
 | 
					                                                            var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@end_timestamp", endTimstamp);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //區間內資料筆數
 | 
				
			||||||
 | 
					                                            if (history["int"] != null && history["int"].HasValues)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					                                                archiveHourRawData.Add("@count_rawdata", count);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //整合數值(最大、最小、平均、總和)
 | 
				
			||||||
 | 
					                                            if (history["real"] != null && history["real"].HasValues)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                foreach (var real in history["real"])
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    var name = real["@name"].ToString();
 | 
				
			||||||
 | 
					                                                    switch (name)
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        case "min":
 | 
				
			||||||
 | 
					                                                            var min = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@min_rawdata", min);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                        case "max":
 | 
				
			||||||
 | 
					                                                            var max = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@max_rawdata", max);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                        case "avg":
 | 
				
			||||||
 | 
					                                                            var avg = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@avg_rawdata", avg);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                        case "sum":
 | 
				
			||||||
 | 
					                                                            var sum = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                            archiveHourRawData.Add("@sum_rawdata", sum);
 | 
				
			||||||
 | 
					                                                            break;
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            archiveHourRawData.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            archiveHourRawDatas.Add(archiveHourRawData);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {   //單筆資料
 | 
				
			||||||
 | 
					                                        Dictionary<string, object> archiveHourRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                                        archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
 | 
				
			||||||
 | 
					                                        archiveHourRawData.Add("@point", deviceNumberPoint.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        //時間
 | 
				
			||||||
 | 
					                                        if (histories["obj"]["abstime"] != null && histories["obj"]["abstime"].HasValues)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            foreach (var abstime in histories["obj"]["abstime"])
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                var name = abstime["@name"].ToString();
 | 
				
			||||||
 | 
					                                                switch (name)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    case "start":
 | 
				
			||||||
 | 
					                                                        var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@start_timestamp", startTimstamp);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                    case "end":
 | 
				
			||||||
 | 
					                                                        var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@end_timestamp", endTimstamp);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        //區間內資料筆數
 | 
				
			||||||
 | 
					                                        if (histories["obj"]["int"] != null && histories["obj"]["int"].HasValues)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					                                            archiveHourRawData.Add("@count_rawdata", count);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        //整合數值(最大、最小、平均、總和)
 | 
				
			||||||
 | 
					                                        if (histories["obj"]["real"] != null && histories["obj"]["real"].HasValues)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            foreach (var real in histories["obj"]["real"])
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                var name = real["@name"].ToString();
 | 
				
			||||||
 | 
					                                                switch (name)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    case "min":
 | 
				
			||||||
 | 
					                                                        var min = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@min_rawdata", min);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                    case "max":
 | 
				
			||||||
 | 
					                                                        var max = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@max_rawdata", max);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                    case "avg":
 | 
				
			||||||
 | 
					                                                        var avg = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@avg_rawdata", avg);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                    case "sum":
 | 
				
			||||||
 | 
					                                                        var sum = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                                        archiveHourRawData.Add("@sum_rawdata", sum);
 | 
				
			||||||
 | 
					                                                        break;
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        archiveHourRawData.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        archiveHourRawDatas.Add(archiveHourRawData);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //stopWatch.Stop();
 | 
				
			||||||
 | 
					                        //logger.LogInformation("【ArchiveElectricMeterHourJob】【小時歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveHourRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceRepository.AddMutiByCustomTable(archiveHourRawDatas, "archive_electric_meter_hour");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime_End("ArchiveElectricMeterHourJob", "All", "任務完成");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception exception)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("ArchiveElectricMeterHourJob", "All", exception.ToString());
 | 
				
			||||||
 | 
					                        logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【任務失敗】");
 | 
				
			||||||
 | 
					                        logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endregion 小時歸檔
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await task_Detail.WorkFail("ArchiveElectricMeterHourJob", "All", exception.ToString());
 | 
				
			||||||
 | 
					                logger.LogError("【ArchiveElectricMeterHourJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【ArchiveElectricMeterHourJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										269
									
								
								Backend/Quartz/Jobs/DataDeliveryJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								Backend/Quartz/Jobs/DataDeliveryJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,269 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Text.Json;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class DataDeliveryJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<DataDeliveryJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DataDeliveryJob(
 | 
				
			||||||
 | 
					            ILogger<DataDeliveryJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Dictionary<string, object> insertLog = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                { "@task_id", 0 },
 | 
				
			||||||
 | 
					                { "@log_level", "" },
 | 
				
			||||||
 | 
					                { "@log_content", "" }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【DataDeliveryJob】【任務開始】");
 | 
				
			||||||
 | 
					                insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                insertLog["@log_content"] = $@"【DataDeliveryJob】任務開始";
 | 
				
			||||||
 | 
					                await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //找出所有要派送的資料
 | 
				
			||||||
 | 
					                string sWhere = @"is_complete = 0 AND task_type = @Task_type AND repeat_times < 10";
 | 
				
			||||||
 | 
					                var backgroundServiceTasks = await backgroundServiceRepository.GetAllAsync<BackgroundServiceTask>("background_service_task", sWhere, new { Task_type = BackgroundServiceTaskType.data_delivery });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (backgroundServiceTasks.Count == 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogInformation("【DataDeliveryJob】【查無任務列表】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                    insertLog["@log_content"] = $@"【DataDeliveryJob】查無任務列表";
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    List<Dictionary<string, object>> updateObjs = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                    foreach (var task in backgroundServiceTasks)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var DateTimeNow = DateTime.Now;
 | 
				
			||||||
 | 
					                        Dictionary<string, object> updateObj = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            { "Id", task.Id },
 | 
				
			||||||
 | 
					                            { "@repeat_times", 0 },
 | 
				
			||||||
 | 
					                            { "@is_complete", 0 },
 | 
				
			||||||
 | 
					                            { "@fail_reason", null },
 | 
				
			||||||
 | 
					                            { "@complete_at", null },
 | 
				
			||||||
 | 
					                            { "@updated_at", DateTimeNow }
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        insertLog["@task_id"] = task.Id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //var parameters = JsonSerializer.Deserialize<Dictionary<string, object>>(task.Target_data);
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogInformation("【DataDeliveryJob】【開始派送】[棟別IP]:{0}", task.Target_ip);
 | 
				
			||||||
 | 
					                            insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                            insertLog["@log_content"] = $@"開始派送";
 | 
				
			||||||
 | 
					                            await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
 | 
				
			||||||
 | 
					                            var endBoundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebRequest Postrequest = (HttpWebRequest)WebRequest.Create($"http://{task.Target_ip}/api/ReceiveDataDelivery/GetData");
 | 
				
			||||||
 | 
					                            Postrequest.ContentType = "multipart/form-data; boundary=" + boundary;
 | 
				
			||||||
 | 
					                            Postrequest.Method = "POST";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (!string.IsNullOrEmpty(task.Target_table))
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                using (Stream requestStream = Postrequest.GetRequestStream())
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    //Id
 | 
				
			||||||
 | 
					                                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                    string task_id = "Content-Disposition: form-data; name=\"" + "Id" + "\"\r\n\r\n" + task.Id;
 | 
				
			||||||
 | 
					                                    byte[] task_id_bytes = System.Text.Encoding.UTF8.GetBytes(task_id);
 | 
				
			||||||
 | 
					                                    requestStream.Write(task_id_bytes, 0, task_id_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    //Target Table
 | 
				
			||||||
 | 
					                                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                    string target_table = "Content-Disposition: form-data; name=\"" + "TargetTable" + "\"\r\n\r\n" + task.Target_table;
 | 
				
			||||||
 | 
					                                    byte[] target_table_bytes = System.Text.Encoding.UTF8.GetBytes(target_table);
 | 
				
			||||||
 | 
					                                    requestStream.Write(target_table_bytes, 0, target_table_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    //mode
 | 
				
			||||||
 | 
					                                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                    string target_mode = "Content-Disposition: form-data; name=\"" + "mode" + "\"\r\n\r\n" + task.Mode;
 | 
				
			||||||
 | 
					                                    byte[] target_mode_bytes = System.Text.Encoding.UTF8.GetBytes(target_mode);
 | 
				
			||||||
 | 
					                                    requestStream.Write(target_mode_bytes, 0, target_mode_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    //Target data
 | 
				
			||||||
 | 
					                                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                    string target_data = "Content-Disposition: form-data; name=\"" + "TargetData" + "\"\r\n\r\n" + task.Target_data;
 | 
				
			||||||
 | 
					                                    byte[] target_data_bytes = System.Text.Encoding.UTF8.GetBytes(target_data);
 | 
				
			||||||
 | 
					                                    requestStream.Write(target_data_bytes, 0, target_data_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    //解析Files
 | 
				
			||||||
 | 
					                                    if (task.Target_files != null)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        var target_files = JsonSerializer.Deserialize<List<Backend.Models.FileInfo>>(task.Target_files);
 | 
				
			||||||
 | 
					                                        var file_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        foreach (var file in target_files)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            //file Folder
 | 
				
			||||||
 | 
					                                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                            string file_folder = "Content-Disposition: form-data; name=\"" + $"FileInfos[{file_index}].Folder" + "\"\r\n\r\n" + file.Folder;
 | 
				
			||||||
 | 
					                                            byte[] file_folder_bytes = System.Text.Encoding.UTF8.GetBytes(file_folder);
 | 
				
			||||||
 | 
					                                            requestStream.Write(file_folder_bytes, 0, file_folder_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //file OriginalFileName
 | 
				
			||||||
 | 
					                                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                            string orig_file_name = "Content-Disposition: form-data; name=\"" + $"FileInfos[{file_index}].OriginalFileName" + "\"\r\n\r\n" + file.OriginalFileName;
 | 
				
			||||||
 | 
					                                            byte[] orig_file_name_bytes = System.Text.Encoding.UTF8.GetBytes(orig_file_name);
 | 
				
			||||||
 | 
					                                            requestStream.Write(orig_file_name_bytes, 0, orig_file_name_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //file FileName
 | 
				
			||||||
 | 
					                                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                            string file_name = "Content-Disposition: form-data; name=\"" + $"FileInfos[{file_index}].FileName" + "\"\r\n\r\n" + file.FileName;
 | 
				
			||||||
 | 
					                                            byte[] file_name_bytes = System.Text.Encoding.UTF8.GetBytes(file_name);
 | 
				
			||||||
 | 
					                                            requestStream.Write(file_name_bytes, 0, file_name_bytes.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            //取得Content-Type
 | 
				
			||||||
 | 
					                                            var content_type = string.Empty;
 | 
				
			||||||
 | 
					                                            string ext = Path.GetExtension(file.File);
 | 
				
			||||||
 | 
					                                            using (Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext))
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                if (registryKey != null)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    var value = registryKey.GetValue("Content Type");
 | 
				
			||||||
 | 
					                                                    if (value != null)
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        content_type = value.ToString();
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            if (file.File != null)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                string file_header = "Content-Disposition: form-data; name=\"" + $"FileInfos[{file_index}].File" + "\"; filename=\"" + file.FileName + "\"\r\nContent-Type: " + content_type + "\r\n\r\n";
 | 
				
			||||||
 | 
					                                                byte[] file_header_bytes = System.Text.Encoding.UTF8.GetBytes(file_header);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
 | 
				
			||||||
 | 
					                                                requestStream.Write(file_header_bytes, 0, file_header_bytes.Length);
 | 
				
			||||||
 | 
					                                                byte[] buffer = new byte[32768];
 | 
				
			||||||
 | 
					                                                int bytesRead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                // upload from file
 | 
				
			||||||
 | 
					                                                using (FileStream fileStream = File.OpenRead(file.File))
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
 | 
				
			||||||
 | 
					                                                        requestStream.Write(buffer, 0, bytesRead);
 | 
				
			||||||
 | 
					                                                    fileStream.Close();
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    requestStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
 | 
				
			||||||
 | 
					                                    requestStream.Close();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebResponse response = (HttpWebResponse)Postrequest.GetResponse();
 | 
				
			||||||
 | 
					                            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					                            var statusNumber = (int)response.StatusCode;
 | 
				
			||||||
 | 
					                            if (statusNumber != 200)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                logger.LogError("【DataDeliveryJob】【派送失敗】[棟別IP]:{0}", task.Target_ip);
 | 
				
			||||||
 | 
					                                logger.LogError("【DataDeliveryJob】【派送失敗】[response]:{0}", responseString);
 | 
				
			||||||
 | 
					                                updateObj["@repeat_times"] = task.Repeat_times + 1;
 | 
				
			||||||
 | 
					                                updateObj["@fail_reason"] = responseString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                                insertLog["@log_content"] = $@"派送失敗 - [失敗原因]:{responseString}";
 | 
				
			||||||
 | 
					                                await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                //解析回傳內容
 | 
				
			||||||
 | 
					                                var final = JObject.Parse(responseString);
 | 
				
			||||||
 | 
					                                var code = final["code"].ToString();
 | 
				
			||||||
 | 
					                                if (code == "0000")
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    logger.LogInformation("【DataDeliveryJob】【派送成功】[棟別IP]:{0}", task.Target_ip);
 | 
				
			||||||
 | 
					                                    updateObj["@repeat_times"] = task.Repeat_times;
 | 
				
			||||||
 | 
					                                    updateObj["@is_complete"] = 1;
 | 
				
			||||||
 | 
					                                    updateObj["@complete_at"] = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                                    insertLog["@log_content"] = $@"派送成功";
 | 
				
			||||||
 | 
					                                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    logger.LogError("【DataDeliveryJob】【派送失敗】[棟別IP]:{0}", task.Target_ip);
 | 
				
			||||||
 | 
					                                    logger.LogError("【DataDeliveryJob】【派送失敗】[response]:{0}", responseString);
 | 
				
			||||||
 | 
					                                    updateObj["@repeat_times"] = task.Repeat_times + 1;
 | 
				
			||||||
 | 
					                                    updateObj["@fail_reason"] = responseString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                                    insertLog["@log_content"] = $@"派送失敗 - [失敗原因]:{responseString}";
 | 
				
			||||||
 | 
					                                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch (Exception exception)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogError("【DataDeliveryJob】【派送失敗】[棟別IP]:{0}", task.Target_ip);
 | 
				
			||||||
 | 
					                            logger.LogError("【DataDeliveryJob】【派送失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                            updateObj["@repeat_times"] = task.Repeat_times + 1;
 | 
				
			||||||
 | 
					                            updateObj["@fail_reason"] = exception.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                            insertLog["@log_content"] = $@"派送失敗 - [失敗原因(Exception)]:{exception.ToString()}";
 | 
				
			||||||
 | 
					                            await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        updateObjs.Add(updateObj);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.UpdateListByCustomTable(updateObjs, "background_service_task", "id = @Id");
 | 
				
			||||||
 | 
					                    logger.LogInformation("【DataDeliveryJob】【任務完成】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    insertLog["@task_id"] = 0;
 | 
				
			||||||
 | 
					                    insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                    insertLog["@log_content"] = $@"任務完成";
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【DataDeliveryJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【DataDeliveryJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                insertLog["@task_id"] = 0;
 | 
				
			||||||
 | 
					                insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                insertLog["@log_content"] = $@"任務失敗";
 | 
				
			||||||
 | 
					                await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_task_log");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								Backend/Quartz/Jobs/ExecutionBackgroundServicePlanJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Backend/Quartz/Jobs/ExecutionBackgroundServicePlanJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    public class ExecutionBackgroundServicePlanJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<ExecutionBackgroundServicePlanJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ExecutionBackgroundServicePlanJob(
 | 
				
			||||||
 | 
					            ILogger<ExecutionBackgroundServicePlanJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【ExecutionBackgroundServicePlanJob】【任務開始】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 找出當前在起始與結束時間所有計畫
 | 
				
			||||||
 | 
					                var DateTimeNow = DateTime.Now;
 | 
				
			||||||
 | 
					                var sPlanWhere = @"deleted = 0 
 | 
				
			||||||
 | 
					                                    AND 
 | 
				
			||||||
 | 
					                                        (
 | 
				
			||||||
 | 
					                                            @DateTimeNow Between start_time AND end_time
 | 
				
			||||||
 | 
					                                        OR  (end_time IS NULL AND @DateTimeNow > start_time)
 | 
				
			||||||
 | 
					                                        )
 | 
				
			||||||
 | 
					                                ";
 | 
				
			||||||
 | 
					                var backgroundServicePlans = await backgroundServiceRepository.GetAllAsync<BackgroundServicePlan>("background_service_plan", sPlanWhere, new { DateTimeNow = DateTimeNow.ToString("yyyy-MM-dd HH:mm:ss") });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var plan in backgroundServicePlans)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    //logger.LogInformation("【ExecutionBackgroundServicePlanJob】【計畫編號:{0},計畫名稱:{1}】 - 開始生成下次任務項目", plan.Id, plan.Plane_name);
 | 
				
			||||||
 | 
					                    #region 紀錄最後生成任務的時間
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var lastCreateTime = Convert.ToDateTime(plan.Last_create_time);
 | 
				
			||||||
 | 
					                        if (lastCreateTime == default(DateTime))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            lastCreateTime = Convert.ToDateTime(plan.Start_time);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        DateTime nextCreateTime; //下次待生成的時間
 | 
				
			||||||
 | 
					                        nextCreateTime = plan.Execution_type switch
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            (byte)ExecutionTypeEnum.Min => Convert.ToDateTime(lastCreateTime).AddMinutes(plan.Execution_time),
 | 
				
			||||||
 | 
					                            (byte)ExecutionTypeEnum.Hour => Convert.ToDateTime(lastCreateTime).AddHours(plan.Execution_time),
 | 
				
			||||||
 | 
					                            (byte)ExecutionTypeEnum.Day => Convert.ToDateTime(lastCreateTime).AddDays(plan.Execution_time),
 | 
				
			||||||
 | 
					                            (byte)ExecutionTypeEnum.Week => Convert.ToDateTime(lastCreateTime).AddDays(plan.Execution_time * 7),
 | 
				
			||||||
 | 
					                            (byte)ExecutionTypeEnum.Month => Convert.ToDateTime(lastCreateTime).AddMonths(plan.Execution_time),
 | 
				
			||||||
 | 
					                            _ => default(DateTime)
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (nextCreateTime != default(DateTime) && nextCreateTime < DateTimeNow)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> servicePlanDic = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                { "@last_create_time", nextCreateTime},
 | 
				
			||||||
 | 
					                                { "@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            await backgroundServiceRepository.UpdateOneByCustomTable(servicePlanDic, "background_service_plan", "id=" + plan.Id + "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            #region 建立任務
 | 
				
			||||||
 | 
					                            try
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                BackgroundServiceTask backgroundServiceTask = new BackgroundServiceTask()
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                };
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            catch(Exception exception)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            #endregion 建立任務
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception exception)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //logger.LogError("【ExecutionBackgroundServicePlanJob】【計畫編號:{0},計畫名稱:{1}】 - 產生下次任務時間失敗", plan.Id, plan.Plane_name);
 | 
				
			||||||
 | 
					                        //logger.LogError("【ExecutionBackgroundServicePlanJob】【計畫編號:{0},計畫名稱:{1}】 - 產生下次任務時間失敗[Exception]- {2}", plan.Id, plan.Plane_name, exception.Message); ;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endregion 紀錄最後該生成任務的時間
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                logger.LogInformation("【ExecutionBackgroundServicePlanJob】【任務完成】");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【ExecutionBackgroundServicePlanJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【ExecutionBackgroundServicePlanJob】【任務失敗】[Exception]:{0}", exception.Message); ;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										163
									
								
								Backend/Quartz/Jobs/MessageNotificationJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								Backend/Quartz/Jobs/MessageNotificationJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using BackendWorkerService.Services.Interface;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Options;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class MessageNotificationJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<MessageNotificationJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private readonly ISendEmailService sendEmailService;
 | 
				
			||||||
 | 
					        private readonly ISendSMSService sendSMSService;
 | 
				
			||||||
 | 
					        private readonly ISendLineNotifyService sendLineNotifyService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public MessageNotificationJob(
 | 
				
			||||||
 | 
					            ILogger<MessageNotificationJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository,
 | 
				
			||||||
 | 
					            ISendEmailService sendEmailService,
 | 
				
			||||||
 | 
					            ISendSMSService sendSMSService,
 | 
				
			||||||
 | 
					            ISendLineNotifyService sendLineNotifyService)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.sendEmailService = sendEmailService;
 | 
				
			||||||
 | 
					            this.sendSMSService = sendSMSService;
 | 
				
			||||||
 | 
					            this.sendLineNotifyService = sendLineNotifyService;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Dictionary<string, object> insertLog = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                { "@task_id", 0 },
 | 
				
			||||||
 | 
					                { "@log_level", "" },
 | 
				
			||||||
 | 
					                { "@log_content", "" }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【MessageNotificationJob】【任務開始】");
 | 
				
			||||||
 | 
					                insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                insertLog["@log_content"] = $@"任務開始";
 | 
				
			||||||
 | 
					                await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_message_notification_task_log");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //找出所有要通知的清單
 | 
				
			||||||
 | 
					                string sWhere = @"is_complete = 0";
 | 
				
			||||||
 | 
					                var messageNotificationTasks = await backgroundServiceRepository.GetAllAsync<BackgroundServiceMessageNotificationTask>("background_service_message_notification_task", sWhere);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(messageNotificationTasks.Count == 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogInformation("【MessageNotificationJob】【查無任務列表】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                    insertLog["@log_content"] = $@"查無任務列表";
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_message_notification_task_log");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    List<Dictionary<string, object>> updateObjs = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                    foreach (var task in messageNotificationTasks)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var DateTimeNow = DateTime.Now;
 | 
				
			||||||
 | 
					                        Dictionary<string, object> updateObj = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            { "Id", task.Id },
 | 
				
			||||||
 | 
					                            { "@updated_at", DateTimeNow }
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            switch (task.Task_type)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case (byte)MessageNotificationTaskType.email:
 | 
				
			||||||
 | 
					                                    List<string> recipientEmails = new List<string>()
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        task.Recipient_email
 | 
				
			||||||
 | 
					                                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    if (sendEmailService.Send(task.Id, recipientEmails, task.Email_subject, task.Message_content))
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					                                        updateObj.Add("@complete_at", DateTimeNow);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@repeat_times", task.Repeat_times + 1);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    updateObjs.Add(updateObj);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case (byte)MessageNotificationTaskType.sms:
 | 
				
			||||||
 | 
					                                    if (sendSMSService.Send(task.Id, task.Recipient_phone, task.Message_content))
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					                                        updateObj.Add("@complete_at", DateTimeNow);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@repeat_times", task.Repeat_times + 1);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    updateObjs.Add(updateObj);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case (byte)MessageNotificationTaskType.line_notify:
 | 
				
			||||||
 | 
					                                    if (sendLineNotifyService.Send(task.Id, task.Line_token, task.Message_content))
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					                                        updateObj.Add("@complete_at", DateTimeNow);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        updateObj.Add("@repeat_times", task.Repeat_times + 1);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    updateObjs.Add(updateObj);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch(Exception exception)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogError("【MessageNotificationJob】【通知失敗】[任務id]:{0}", task.Id);
 | 
				
			||||||
 | 
					                            logger.LogError("【MessageNotificationJob】【通知失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                            insertLog["@log_content"] = $@"通知失敗 - [失敗原因(Exception)]:{exception.ToString()}";
 | 
				
			||||||
 | 
					                            await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_message_notification_task_log");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.UpdateListByCustomTable(updateObjs, "background_service_message_notification_task", "id = @Id");
 | 
				
			||||||
 | 
					                    logger.LogInformation("【MessageNotificationJob】【任務完成】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    insertLog["@task_id"] = 0;
 | 
				
			||||||
 | 
					                    insertLog["@log_level"] = $@"INFO";
 | 
				
			||||||
 | 
					                    insertLog["@log_content"] = $@"任務完成";
 | 
				
			||||||
 | 
					                    await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_message_notification_task_log");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【MessageNotificationJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【MessageNotificationJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                insertLog["@task_id"] = 0;
 | 
				
			||||||
 | 
					                insertLog["@log_level"] = $@"ERR";
 | 
				
			||||||
 | 
					                insertLog["@log_content"] = $@"任務失敗";
 | 
				
			||||||
 | 
					                await backgroundServiceRepository.AddOneByCustomTable(insertLog, "background_service_message_notification_task_log");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										324
									
								
								Backend/Quartz/Jobs/ParkingJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								Backend/Quartz/Jobs/ParkingJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,324 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using System.Xml;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 停車場管理
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class ParkingJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<ParkingJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					        private readonly IBackendRepository backendRepository;
 | 
				
			||||||
 | 
					        private readonly ILogger<Task_Detail> loggers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ParkingJob(
 | 
				
			||||||
 | 
					            ILogger<ParkingJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository, ILogger<Task_Detail> loggers, IBackendRepository backendRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.backendRepository = backendRepository;
 | 
				
			||||||
 | 
					            this.loggers = loggers;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Task_Detail task_Detail = new Task_Detail(loggers, backendRepository);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if(await task_Detail.GetNeedWorkTask("ParkingJob", "All"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    await task_Detail.InsertWorkTime("ParkingJob", "All", "任務開始");
 | 
				
			||||||
 | 
					                    EDFunction ed = new EDFunction();
 | 
				
			||||||
 | 
					                    var parkingConfig = new ParkingConfig();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var sqlParking = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'parkingConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var variable = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlParking);
 | 
				
			||||||
 | 
					                    parkingConfig.Host = variable.Where(x => x.Name == "Host").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                    parkingConfig.Prefix = variable.Where(x => x.Name == "Prefix").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                    parkingConfig.ApiBase = variable.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                    parkingConfig.UserName = ed.AESDecrypt(variable.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault());
 | 
				
			||||||
 | 
					                    parkingConfig.Password = ed.AESDecrypt(variable.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(parkingConfig.UserName + ":" + parkingConfig.Password));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 取得停車場資訊
 | 
				
			||||||
 | 
					                    if (await task_Detail.GetNeedWorkTask("ParkingJob", "Parking"))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await task_Detail.InsertWorkTime("ParkingJob", "Parking", "開始執行停車場剩餘車位Job");
 | 
				
			||||||
 | 
					                            HttpWebRequest spaceRequest = (HttpWebRequest)WebRequest.Create($"{parkingConfig.Host}{parkingConfig.Prefix}/api/space/details");
 | 
				
			||||||
 | 
					                            spaceRequest.Method = "GET";
 | 
				
			||||||
 | 
					                            //request.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                            spaceRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //Stopwatch stopWatch = new Stopwatch();
 | 
				
			||||||
 | 
					                            //stopWatch.Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebResponse spaceResponse = (HttpWebResponse)spaceRequest.GetResponse();
 | 
				
			||||||
 | 
					                            var spaceResponseContent = new StreamReader(spaceResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					                            //logger.LogInformation("【ParkingJob】【取得成功停車場車位資訊】");
 | 
				
			||||||
 | 
					                            //stopWatch.Stop();
 | 
				
			||||||
 | 
					                            //logger.LogInformation("【ParkingJob】【取得停車場車位資訊】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var spaceResponseResult = JsonConvert.DeserializeObject<SpaceResponse>(spaceResponseContent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //取得停車場車位對應表
 | 
				
			||||||
 | 
					                            var sqlSapceMapping = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = 'parkingSapceMapping'";
 | 
				
			||||||
 | 
					                            var parkingSapceMapping = await backgroundServiceRepository.GetAllAsync<VariableInfo>(sqlSapceMapping);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (spaceResponseResult != null && spaceResponseResult.Code == "20000")
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                foreach (var area in spaceResponseResult.Payload.Areas)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    //找出對定的設備代碼
 | 
				
			||||||
 | 
					                                    var selectedMapping = parkingSapceMapping.Where(x => x.System_key == area.Name).FirstOrDefault();
 | 
				
			||||||
 | 
					                                    if (selectedMapping != null)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        var tagName = selectedMapping.system_value;
 | 
				
			||||||
 | 
					                                        var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/CV/set";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var tagNameSplit = tagName.Split("_");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var parames = new List<object>();
 | 
				
			||||||
 | 
					                                        parames.Add(parkingConfig.ApiBase);
 | 
				
			||||||
 | 
					                                        for (var i = 0; i < tagNameSplit.Length; i++)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if (i != tagNameSplit.Length - 1)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                parames.Add(tagNameSplit[i]);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            else
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                parames.Add(tagName);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray()));
 | 
				
			||||||
 | 
					                                        request.Method = "POST";
 | 
				
			||||||
 | 
					                                        request.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                                        request.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var real = $@"<real val='{area.Remain}' />";
 | 
				
			||||||
 | 
					                                        byte[] realByteArray = Encoding.UTF8.GetBytes(real);
 | 
				
			||||||
 | 
					                                        using (Stream reqStream = request.GetRequestStream())
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            reqStream.Write(realByteArray, 0, realByteArray.Length);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 | 
				
			||||||
 | 
					                                        var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        XmlDocument xmlDocument = new XmlDocument();
 | 
				
			||||||
 | 
					                                        xmlDocument.LoadXml(responseContent);
 | 
				
			||||||
 | 
					                                        string json = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                                        JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        if (jsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            logger.LogError("【ParkingJob】【停車場剩餘車位資訊】");
 | 
				
			||||||
 | 
					                                            logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[錯誤內容]:{0}", json);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        else
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if (jsonResult.ContainsKey("real")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                List<Dictionary<string, object>> ontimeRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                var realList = jsonResult["real"];
 | 
				
			||||||
 | 
					                                                var display = realList["@display"];
 | 
				
			||||||
 | 
					                                                if (display != null)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    var tempStrSplit = display.ToString().Split(" ");
 | 
				
			||||||
 | 
					                                                    if (tempStrSplit[0] != area.Remain.ToString())
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[修改失敗]:{0}", display.ToString());
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        logger.LogWarning("【ParkingJob】【停車場剩餘車位資訊】[查無該名稱對應表]:{0}", area.Name);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                logger.LogWarning("【ParkingJob】【停車場剩餘車位資訊】 - [查無資料]");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            await task_Detail.InsertWorkTime_End("ParkingJob", "Parking", "執行成功停車場剩餘車位Job");
 | 
				
			||||||
 | 
					                            //logger.LogInformation("【ParkingJob】【執行成功停車場剩餘車位Job】");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch (Exception exception)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await task_Detail.WorkFail("ParkingJob", "Parking", exception.ToString());
 | 
				
			||||||
 | 
					                            logger.LogInformation("【ParkingJob】【執行失敗停車場剩餘車位Job】");
 | 
				
			||||||
 | 
					                            logger.LogInformation("【ParkingJob】【執行失敗停車場剩餘車位Job】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #region 取得設備資訊
 | 
				
			||||||
 | 
					                    if (await task_Detail.GetNeedWorkTask("ParkingJob", "Device"))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        try
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await task_Detail.InsertWorkTime("ParkingJob", "Device", "開始執行設備資訊Job");
 | 
				
			||||||
 | 
					                            //logger.LogInformation("【ParkingJob】【開始執行設備資訊Job】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebRequest equipmentRequest = (HttpWebRequest)WebRequest.Create($"{parkingConfig.Host}{parkingConfig.Prefix}/api/equipment/state");
 | 
				
			||||||
 | 
					                            equipmentRequest.Method = "GET";
 | 
				
			||||||
 | 
					                            //request.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                            equipmentRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            HttpWebResponse equipmentResponse = (HttpWebResponse)equipmentRequest.GetResponse();
 | 
				
			||||||
 | 
					                            var equipmentResponseContent = new StreamReader(equipmentResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            var equipmentResponseResult = JsonConvert.DeserializeObject<EquipmentResponse>(equipmentResponseContent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //取得設備對應表
 | 
				
			||||||
 | 
					                            var sqlEquipmentMapping = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = 'parkingEquipmentMapping'";
 | 
				
			||||||
 | 
					                            var parkingEquipmentMapping = await backgroundServiceRepository.GetAllAsync<VariableInfo>(sqlEquipmentMapping);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //List<VariableInfo> parkingEquipmentMapping = new List<VariableInfo>();
 | 
				
			||||||
 | 
					                            //VariableInfo variableInfo_1 = new VariableInfo();
 | 
				
			||||||
 | 
					                            //variableInfo_1.System_key = "APS-000";
 | 
				
			||||||
 | 
					                            //variableInfo_1.system_value = "D3_P_B4F_CAPS_B413";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //parkingEquipmentMapping.Add(variableInfo_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            //VariableInfo variableInfo_2 = new VariableInfo();
 | 
				
			||||||
 | 
					                            //variableInfo_2.System_key = "APS-001";
 | 
				
			||||||
 | 
					                            //variableInfo_2.system_value = "D3_P_B4F_CAPS_B414";
 | 
				
			||||||
 | 
					                            //parkingEquipmentMapping.Add(variableInfo_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (equipmentResponseResult != null && equipmentResponseResult.Code == "20000")
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                foreach (var equipment in equipmentResponseResult.Payload)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    //找出對定的設備代碼
 | 
				
			||||||
 | 
					                                    var selectedMapping = parkingEquipmentMapping.Where(x => x.System_key == equipment.Name).FirstOrDefault();
 | 
				
			||||||
 | 
					                                    if (selectedMapping != null)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var tagName = selectedMapping.system_value;
 | 
				
			||||||
 | 
					                                        var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/ST/set";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var tagNameSplit = tagName.Split("_");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var parames = new List<object>();
 | 
				
			||||||
 | 
					                                        parames.Add(parkingConfig.ApiBase);
 | 
				
			||||||
 | 
					                                        for (var i = 0; i < tagNameSplit.Length; i++)
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if (i != tagNameSplit.Length - 1)
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                parames.Add(tagNameSplit[i]);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                            else
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                parames.Add(tagName);
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray()));
 | 
				
			||||||
 | 
					                                        request.Method = "POST";
 | 
				
			||||||
 | 
					                                        request.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                                        request.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var real = $@"<real val='{equipment.Alive.ToString().ToLower()}' />";
 | 
				
			||||||
 | 
					                                        byte[] realByteArray = Encoding.UTF8.GetBytes(real);
 | 
				
			||||||
 | 
					                                        using (Stream reqStream = request.GetRequestStream())
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            reqStream.Write(realByteArray, 0, realByteArray.Length);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 | 
				
			||||||
 | 
					                                        var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        XmlDocument xmlDocument = new XmlDocument();
 | 
				
			||||||
 | 
					                                        xmlDocument.LoadXml(responseContent);
 | 
				
			||||||
 | 
					                                        string json = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                                        JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        if (jsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            logger.LogError("【ParkingJob】【設備資訊】");
 | 
				
			||||||
 | 
					                                            logger.LogError("【ParkingJob】【設備資訊】[錯誤內容]:{0}", json);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        else
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            if (jsonResult.ContainsKey("bool")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                List<Dictionary<string, object>> ontimeRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                var realList = jsonResult["bool"];
 | 
				
			||||||
 | 
					                                                var val = realList["@val"];
 | 
				
			||||||
 | 
					                                                if (val != null)
 | 
				
			||||||
 | 
					                                                {
 | 
				
			||||||
 | 
					                                                    var tempStrSplit = val.ToString();
 | 
				
			||||||
 | 
					                                                    if (tempStrSplit != equipment.Alive.ToString().ToLower())
 | 
				
			||||||
 | 
					                                                    {
 | 
				
			||||||
 | 
					                                                        logger.LogError("【ParkingJob】【設備資訊】[修改失敗]:{0}", val.ToString());
 | 
				
			||||||
 | 
					                                                    }
 | 
				
			||||||
 | 
					                                                }
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        logger.LogWarning("【ParkingJob】【設備資訊】[查無該名稱對應表]:{0}", equipment.Name);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                logger.LogWarning("【ParkingJob】【設備資訊】 - [查無資料]");
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            await task_Detail.InsertWorkTime_End("ParkingJob", "Device", "執行成功設備資訊Job");
 | 
				
			||||||
 | 
					                            //logger.LogInformation("【ParkingJob】【執行成功設備資訊Job】");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        catch (Exception exception)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await task_Detail.WorkFail("ParkingJob", "Device", exception.ToString());
 | 
				
			||||||
 | 
					                            logger.LogInformation("【ParkingJob】【執行失敗設備資訊Job】");
 | 
				
			||||||
 | 
					                            logger.LogInformation("【ParkingJob】【執行失敗設備資訊Job】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    await task_Detail.InsertWorkTime_End("ParkingJob", "All", "任務完成");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                await task_Detail.WorkFail("ParkingJob", "All", exception.ToString());
 | 
				
			||||||
 | 
					                logger.LogError("【ParkingJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【ParkingJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										77
									
								
								Backend/Quartz/Jobs/RegularUpdateDBTableJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Backend/Quartz/Jobs/RegularUpdateDBTableJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					using Backend.Services.Implement;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 定時將資料表加入派送任務
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class RegularUpdateDBTableJob: IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<RegularUpdateDBTableJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					        private readonly IBackendRepository backendRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public RegularUpdateDBTableJob(
 | 
				
			||||||
 | 
					            ILogger<RegularUpdateDBTableJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository,
 | 
				
			||||||
 | 
					            IBackendRepository backendRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.backendRepository = backendRepository;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【RegularUpdateDBTableJob】【任務開始】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //要派送的資料表
 | 
				
			||||||
 | 
					                List<string> db_tables = new List<string>() { "variable" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var db_table in db_tables)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        logger.LogInformation("【RegularUpdateDBTableJob】【新增資料表 [{0}] 至派送任務】", db_table);
 | 
				
			||||||
 | 
					                        //取得資料表所有資料
 | 
				
			||||||
 | 
					                        var temp_datas = (await backgroundServiceRepository.GetAllAsync<dynamic>(db_table, ""));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        List<Dictionary<string, object>> dicts = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                        foreach (var temp_data in temp_datas)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var dict = new Dictionary<string, object>((IDictionary<string, object>)temp_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            dicts.Add(dict);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        await backendRepository.ManualInsertBackgroundServiceTask("", "", db_table, "purge_all_insert", dicts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        logger.LogError("【RegularUpdateDBTableJob】【新增成功 資料表 [{0}] 至派送任務】", db_table);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch(Exception exception)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        logger.LogError("【RegularUpdateDBTableJob】【新增失敗 資料表 [{0}] 至派送任務】", db_table);
 | 
				
			||||||
 | 
					                        logger.LogError("【RegularUpdateDBTableJob】【新增失敗 資料表 [{0}] 至派送任務】[Exception]:{1}", db_table, exception.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【RegularUpdateDBTableJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【RegularUpdateDBTableJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										559
									
								
								Backend/Quartz/Jobs/WeatherAPIJob.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										559
									
								
								Backend/Quartz/Jobs/WeatherAPIJob.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,559 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Implement;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Net.Http;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using System.Xml;
 | 
				
			||||||
 | 
					using System.Xml.Serialization;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using NCrontab;
 | 
				
			||||||
 | 
					using BackendWorkerService.Services.Implement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz.Jobs
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [DisallowConcurrentExecution]
 | 
				
			||||||
 | 
					    class WeatherAPIJob : IJob
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<WeatherAPIJob> logger;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					        private readonly IBackendRepository backendRepository;
 | 
				
			||||||
 | 
					        private readonly ILogger<Task_Detail> loggers;
 | 
				
			||||||
 | 
					        public WeatherAPIJob(ILogger<WeatherAPIJob> logger,
 | 
				
			||||||
 | 
					            IBackgroundServiceRepository backgroundServiceRepository, IBackendRepository backendRepository, ILogger<Task_Detail> loggers)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.backendRepository = backendRepository;
 | 
				
			||||||
 | 
					            this.loggers = loggers;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public string Fetch_PostWithJSONFormat(string url, string paramter)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                string username = "stanGG";
 | 
				
			||||||
 | 
					                string password = "St12345678";
 | 
				
			||||||
 | 
					                string encoded = Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
 | 
				
			||||||
 | 
					                HttpWebRequest Postrequest = (HttpWebRequest)WebRequest.Create(url);
 | 
				
			||||||
 | 
					                Postrequest.Method = "POST";
 | 
				
			||||||
 | 
					                Postrequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                Postrequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                using (var streamWriter = new StreamWriter(Postrequest.GetRequestStream()))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (paramter != "NULL")
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        string json = "<real val=\"" + paramter + "\"/>";
 | 
				
			||||||
 | 
					                        streamWriter.Write(json);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        string json = "<real val= NULL />";
 | 
				
			||||||
 | 
					                        streamWriter.Write(json);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                HttpWebResponse response = (HttpWebResponse)Postrequest.GetResponse();
 | 
				
			||||||
 | 
					                var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					                XmlDocument xmlDoc = new XmlDocument();
 | 
				
			||||||
 | 
					                xmlDoc.LoadXml(responseString);
 | 
				
			||||||
 | 
					                string jsonText = JsonConvert.SerializeXmlNode(xmlDoc);
 | 
				
			||||||
 | 
					                //JObject resultVal = (JObject)JsonConvert.DeserializeObject(jsonText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return jsonText;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【WeatherAPIJob】" + "Fetch_PostWithJSONFormat:" + ex.ToString());
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task Execute(IJobExecutionContext context)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Task_Detail task_Detail = new Task_Detail(loggers, backendRepository);
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var obixApiConfig = new ObixApiConfig();
 | 
				
			||||||
 | 
					                string encoded = string.Empty;
 | 
				
			||||||
 | 
					                #region 取得obix 設定
 | 
				
			||||||
 | 
					                var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var variableObix = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlObix);
 | 
				
			||||||
 | 
					                obixApiConfig.ApiBase = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                obixApiConfig.UserName = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                obixApiConfig.Password = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password));
 | 
				
			||||||
 | 
					                #endregion 取得obix 設定
 | 
				
			||||||
 | 
					                //取得氣象預報
 | 
				
			||||||
 | 
					                if (await task_Detail.GetNeedWorkTask("WeatherAPI", "api_weateher"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime("WeatherAPI", "api_weateher");
 | 
				
			||||||
 | 
					                        var client = new HttpClient();
 | 
				
			||||||
 | 
					                        var DataNO = "F-D0047-061";
 | 
				
			||||||
 | 
					                        var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-D0047-061?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&format=JSON&locationName=%E4%BF%A1%E7%BE%A9%E5%8D%80&elementName=Wx,PoP12h,T,RH";
 | 
				
			||||||
 | 
					                        HttpResponseMessage response = client.GetAsync(UVUri).Result;
 | 
				
			||||||
 | 
					                        String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var observation = JsonConvert.DeserializeObject<Root>(jsonUVs);
 | 
				
			||||||
 | 
					                        logger.LogInformation("【WeatherAPIJob】【取得成功氣象預報】");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (observation.Success != "true")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogInformation("【WeatherAPIJob】【取得氣象預報資料不正確】");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogInformation("【WeatherAPIJob】【開始存入氣象預報到資料庫】");
 | 
				
			||||||
 | 
					                            List<Dictionary<string, object>> WeatherAPIdbS = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                            var Type_ALL = observation.Records.Locations[0].Location[0].WeatherElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            foreach (var a in Type_ALL)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                foreach (var b in a.Time)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (a.ElementName == "PoP12h" || a.ElementName == "Wx")
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        if (Convert.ToDateTime(b.StartTime) > DateTime.Now.AddDays(1))
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            break;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        if (Convert.ToDateTime(b.DataTime) > DateTime.Now.AddDays(1))
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            break;
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    Dictionary<string, object> WeatherAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        { "@weather_type", a.ElementName},
 | 
				
			||||||
 | 
					                                        { "@data_no", DataNO},
 | 
				
			||||||
 | 
					                                        { "@get_value", b.ElementValue[0].Value},
 | 
				
			||||||
 | 
					                                        { "@measures", b.ElementValue[0].Measures},
 | 
				
			||||||
 | 
					                                        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                                        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                                    };
 | 
				
			||||||
 | 
					                                    if (a.ElementName == "PoP12h" || a.ElementName == "Wx")
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        WeatherAPIdb.Add("@start_time", b.StartTime);
 | 
				
			||||||
 | 
					                                        WeatherAPIdb.Add("@end_time", b.EndTime);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        WeatherAPIdb.Add("@start_time", b.DataTime);
 | 
				
			||||||
 | 
					                                        WeatherAPIdb.Add("@end_time", null);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    WeatherAPIdbS.Add(WeatherAPIdb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                    if (a.ElementName == "Wx")
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        Dictionary<string, object> TWeatherAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            { "@weather_type", "WxV"},
 | 
				
			||||||
 | 
					                                            { "@data_no", DataNO},
 | 
				
			||||||
 | 
					                                            { "@get_value", b.ElementValue[1].Value},
 | 
				
			||||||
 | 
					                                            { "@measures", b.ElementValue[1].Measures},
 | 
				
			||||||
 | 
					                                            { "@start_time", b.StartTime},
 | 
				
			||||||
 | 
					                                            { "@end_time", b.EndTime},
 | 
				
			||||||
 | 
					                                            { "@created_by", "system"},
 | 
				
			||||||
 | 
					                                            { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                                        };
 | 
				
			||||||
 | 
					                                        WeatherAPIdbS.Add(TWeatherAPIdb);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            await backendRepository.AddMutiByCustomTable(WeatherAPIdbS, "api_weateher");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime_End("WeatherAPI", "api_weateher");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("WeatherAPI", "api_weateher", ex.Message.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (await task_Detail.GetNeedWorkTask("WeatherAPI", "api_rain"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime("WeatherAPI", "api_rain");
 | 
				
			||||||
 | 
					                        WebClient mywebClient = new WebClient();
 | 
				
			||||||
 | 
					                        mywebClient.DownloadFile("https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/W-C0033-003?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&downloadType=WEB&format=CAP", @"root/PowerfulRain.xml");
 | 
				
			||||||
 | 
					                        XmlDocument doc = new XmlDocument();
 | 
				
			||||||
 | 
					                        doc.Load("root/PowerfulRain.xml");
 | 
				
			||||||
 | 
					                        var json = JsonConvert.SerializeXmlNode(doc);
 | 
				
			||||||
 | 
					                        var haveinfo = json.Split("info");
 | 
				
			||||||
 | 
					                        //if (haveinfo.Length > 2)
 | 
				
			||||||
 | 
					                        //{
 | 
				
			||||||
 | 
					                        //    var observation = RainApi.Welcome.FromJson(json);
 | 
				
			||||||
 | 
					                        //    var area = observation.Alert.Info[0].Area.Where(a => a.Geocode.Value == "63").Select(a => a.AreaDesc).FirstOrDefault();
 | 
				
			||||||
 | 
					                        //    var sql = $"select id from api_rain where msgType = '{observation.Alert.MsgType}' and onset = '{observation.Alert.Info[0].Onset.ToString("yyyy-MM-dd HH:mm:ss")}' and expires = '{observation.Alert.Info[0].Expires.ToString("yyyy-MM-dd HH:mm:ss")}'";
 | 
				
			||||||
 | 
					                        //    var NeedCallApi = await backendRepository.GetOneAsync<int>(sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //    Dictionary<string, object> RainAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        { "@msgType", observation.Alert.MsgType},
 | 
				
			||||||
 | 
					                        //        { "@headline", observation.Alert.Info[0].Headline},
 | 
				
			||||||
 | 
					                        //        { "@areaDesc", area},
 | 
				
			||||||
 | 
					                        //        { "@onset", observation.Alert.Info[0].Onset},
 | 
				
			||||||
 | 
					                        //        { "@expires", observation.Alert.Info[0].Expires},
 | 
				
			||||||
 | 
					                        //        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                        //        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //    };
 | 
				
			||||||
 | 
					                        //    var id = await backendRepository.AddOneByCustomTableReturnId(RainAPIdb, "api_rain");
 | 
				
			||||||
 | 
					                        //    if (NeedCallApi != 0)
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        var val = RainValue(observation.Alert.MsgType, observation.Alert.Info[0].Headline);
 | 
				
			||||||
 | 
					                        //        if (val < 5)
 | 
				
			||||||
 | 
					                        //        {
 | 
				
			||||||
 | 
					                        //            var ReStr = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_MET1/SeverityLEVL_RAIN/set", val.ToString());
 | 
				
			||||||
 | 
					                        //            UpdatedNiagara("api_rain", ReStr, id);
 | 
				
			||||||
 | 
					                        //        }
 | 
				
			||||||
 | 
					                        //    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //    FolderFunction folderFunction = new FolderFunction();
 | 
				
			||||||
 | 
					                        //    folderFunction.DeleteFile("root/PowerfulRain.xml");
 | 
				
			||||||
 | 
					                        //    await task_Detail.InsertWorkTime_End("WeatherAPI", "api_rain");
 | 
				
			||||||
 | 
					                        //}
 | 
				
			||||||
 | 
					                        //else
 | 
				
			||||||
 | 
					                        //{
 | 
				
			||||||
 | 
					                        //    var observation = RainApi.Welcome.FromJson(json);
 | 
				
			||||||
 | 
					                        //    var area = observation.Alert.Info[0].Area.Where(a => a.Geocode.Value == "63").Select(a => a.AreaDesc).FirstOrDefault();
 | 
				
			||||||
 | 
					                        //    var sql = $"select id from api_rain where msgType = '{observation.Alert.MsgType}' and onset = '{observation.Alert.Info[0].Onset.ToString("yyyy-MM-dd HH:mm:ss")}' and expires = '{observation.Alert.Info[0].Expires.ToString("yyyy-MM-dd HH:mm:ss")}'";
 | 
				
			||||||
 | 
					                        //    var NeedCallApi = await backendRepository.GetOneAsync<int>(sql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //    Dictionary<string, object> RainAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        { "@msgType", observation.Alert.MsgType},
 | 
				
			||||||
 | 
					                        //        { "@headline", observation.Alert.Info[0].Headline},
 | 
				
			||||||
 | 
					                        //        { "@areaDesc", area},
 | 
				
			||||||
 | 
					                        //        { "@onset", observation.Alert.Info[0].Onset.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //        { "@expires", observation.Alert.Info[0].Expires.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                        //        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //    };
 | 
				
			||||||
 | 
					                        //    var id = await backendRepository.AddOneByCustomTableReturnId(RainAPIdb, "api_rain");
 | 
				
			||||||
 | 
					                        //    if (NeedCallApi != 0)
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        var val = RainValue(observation.Alert.MsgType, observation.Alert.Info[0].Headline);
 | 
				
			||||||
 | 
					                        //        if (val < 5)
 | 
				
			||||||
 | 
					                        //        {
 | 
				
			||||||
 | 
					                        //            var ReStr = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_MET1/SeverityLEVL_RAIN/set", val.ToString());
 | 
				
			||||||
 | 
					                        //            UpdatedNiagara("api_rain", ReStr, id);
 | 
				
			||||||
 | 
					                        //        }
 | 
				
			||||||
 | 
					                        //    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //    FolderFunction folderFunction = new FolderFunction();
 | 
				
			||||||
 | 
					                        //    folderFunction.DeleteFile("root/PowerfulRain.xml");
 | 
				
			||||||
 | 
					                        //    await task_Detail.InsertWorkTime_End("WeatherAPI", "api_rain");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //}
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("WeatherAPI", "api_rain", ex.Message.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (await task_Detail.GetNeedWorkTask("WeatherAPI", "api_typhoon"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime("WeatherAPI", "api_typhoon");
 | 
				
			||||||
 | 
					                        WebClient mywebClient = new WebClient();
 | 
				
			||||||
 | 
					                        mywebClient.DownloadFile("https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/W-C0034-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&downloadType=WEB&format=CAP", @"root/Typhoon.xml");
 | 
				
			||||||
 | 
					                        XmlDocument doc = new XmlDocument();
 | 
				
			||||||
 | 
					                        doc.Load("root/Typhoon.xml");
 | 
				
			||||||
 | 
					                        var json = JsonConvert.SerializeXmlNode(doc);
 | 
				
			||||||
 | 
					                        var haveinfo = json.Split("info");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //if (haveinfo.Length > 2)
 | 
				
			||||||
 | 
					                        //{
 | 
				
			||||||
 | 
					                        //    var observation = TyphoonApi.Welcome.FromJson(json);
 | 
				
			||||||
 | 
					                        //    var area = observation.Alert.Info.Area.Where(a => a.Geocode.Value == "63").Select(a => a.AreaDesc).FirstOrDefault();
 | 
				
			||||||
 | 
					                        //    var sql = $"select id from api_typhoon where msgType = '{observation.Alert.MsgType}' and onset = '{observation.Alert.Info[0].Onset.ToString("yyyy-MM-dd HH:mm:ss")}' and expires = '{observation.Alert.Info[0].Expires.ToString("yyyy-MM-dd HH:mm:ss")}'";
 | 
				
			||||||
 | 
					                        //    var NeedCallApi = await backendRepository.GetOneAsync<int>(sql);
 | 
				
			||||||
 | 
					                        //    Dictionary<string, object> EarthquakeAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        { "@msgType", observation.Alert.MsgType},
 | 
				
			||||||
 | 
					                        //        { "@headline", observation.Alert.Info[0].Headline},
 | 
				
			||||||
 | 
					                        //        { "@areaDesc", area},
 | 
				
			||||||
 | 
					                        //        { "@urgency",observation.Alert.Info[0].Urgency},
 | 
				
			||||||
 | 
					                        //        { "@severity",observation.Alert.Info[0].Severity},
 | 
				
			||||||
 | 
					                        //        { "@onset", observation.Alert.Info[0].Onset},
 | 
				
			||||||
 | 
					                        //        { "@expires", observation.Alert.Info[0].Expires},
 | 
				
			||||||
 | 
					                        //        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                        //        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //    };
 | 
				
			||||||
 | 
					                        //    var id = await backendRepository.AddOneByCustomTableReturnId(EarthquakeAPIdb, "api_typhoon");
 | 
				
			||||||
 | 
					                        //    if (NeedCallApi != 0)
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        if (observation.Alert.Info[0].Urgency != null && observation.Alert.Info[0].Urgency != "Expected")
 | 
				
			||||||
 | 
					                        //        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //            var ReStr = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_MET2/SeverityLEVL_Typhoon/set", observation.Alert.Info[0].Urgency);
 | 
				
			||||||
 | 
					                        //            UpdatedNiagara("api_typhoon", ReStr, id);
 | 
				
			||||||
 | 
					                        //        }
 | 
				
			||||||
 | 
					                        //    }
 | 
				
			||||||
 | 
					                        //    FolderFunction folderFunction = new FolderFunction();
 | 
				
			||||||
 | 
					                        //    folderFunction.DeleteFile("root/Typhoon.xml");
 | 
				
			||||||
 | 
					                        //    await task_Detail.InsertWorkTime_End("WeatherAPI", "api_typhoon");
 | 
				
			||||||
 | 
					                        //}
 | 
				
			||||||
 | 
					                        //else
 | 
				
			||||||
 | 
					                        //{
 | 
				
			||||||
 | 
					                        //    var observation = TyphoonApi.Welcome.FromJson(json);
 | 
				
			||||||
 | 
					                        //    //var area = observation.Alert.Info.Area.Where(a => a.Geocode.Value == "63").Select(a => a.AreaDesc).FirstOrDefault();
 | 
				
			||||||
 | 
					                        //    var sql = $"select id from api_typhoon where msgType = '{observation.Alert.MsgType}' and onset = '{observation.Alert.Info.Onset.ToString("yyyy-MM-dd HH:mm:ss")}' and expires = '{observation.Alert.Info.Expires.ToString("yyyy-MM-dd HH:mm:ss")}'";
 | 
				
			||||||
 | 
					                        //    var NeedCallApi = await backendRepository.GetOneAsync<int>(sql);
 | 
				
			||||||
 | 
					                        //    Dictionary<string, object> EarthquakeAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        { "@msgType", observation.Alert.MsgType},
 | 
				
			||||||
 | 
					                        //        { "@headline", observation.Alert.Info.Headline},
 | 
				
			||||||
 | 
					                        //        //{ "@areaDesc", area},
 | 
				
			||||||
 | 
					                        //        { "@urgency",observation.Alert.Info.Urgency},
 | 
				
			||||||
 | 
					                        //        { "@severity",observation.Alert.Info.Severity},
 | 
				
			||||||
 | 
					                        //        { "@onset", observation.Alert.Info.Onset.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //        { "@expires", observation.Alert.Info.Expires.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                        //        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                        //    };
 | 
				
			||||||
 | 
					                        //    var id = await backendRepository.AddOneByCustomTableReturnId(EarthquakeAPIdb, "api_typhoon");
 | 
				
			||||||
 | 
					                        //    if (NeedCallApi != 0)
 | 
				
			||||||
 | 
					                        //    {
 | 
				
			||||||
 | 
					                        //        if (observation.Alert.Info.Urgency != null && observation.Alert.Info.Urgency != "Expected")
 | 
				
			||||||
 | 
					                        //        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //            var ReStr = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_MET2/SeverityLEVL_Typhoon/set", observation.Alert.Info.Urgency);
 | 
				
			||||||
 | 
					                        //            UpdatedNiagara("api_typhoon", ReStr, id);
 | 
				
			||||||
 | 
					                        //        }
 | 
				
			||||||
 | 
					                        //    }
 | 
				
			||||||
 | 
					                        //    FolderFunction folderFunction = new FolderFunction();
 | 
				
			||||||
 | 
					                        //    folderFunction.DeleteFile("root/Typhoon.xml");
 | 
				
			||||||
 | 
					                        //    await task_Detail.InsertWorkTime_End("WeatherAPI", "api_typhoon");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("WeatherAPI", "api_typhoon", ex.Message.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (await task_Detail.GetNeedWorkTask("WeatherAPI", "api_earthquake"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime("WeatherAPI", "api_earthquake");
 | 
				
			||||||
 | 
					                        var client = new HttpClient();
 | 
				
			||||||
 | 
					                        var UVUri = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/E-A0015-001?Authorization=CWB-EA24220B-DDCC-4188-84E5-AD37A0E03F80&format=JSON&areaName=%E8%87%BA%E5%8C%97%E5%B8%82";
 | 
				
			||||||
 | 
					                        HttpResponseMessage response = client.GetAsync(UVUri).Result;
 | 
				
			||||||
 | 
					                        String jsonUVs = response.Content.ReadAsStringAsync().Result.ToString();
 | 
				
			||||||
 | 
					                        var observation = QuickType.Welcome.FromJson(jsonUVs);
 | 
				
			||||||
 | 
					                        if (!observation.Success)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogInformation("【WeatherAPIJob】【取得地震觀測資料不正確】");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            logger.LogInformation("【WeatherAPIJob】【開始存入地震觀測到資料庫】");
 | 
				
			||||||
 | 
					                            List<Dictionary<string, object>> EarthquakeAPIdbS = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                            var nowNo = await backendRepository.GetOneAsync<int>("select if( Max(earthquakeNo) is null ,0,Max(earthquakeNo)) earthquakeNo from api_earthquake where newEarthquake = 1");
 | 
				
			||||||
 | 
					                            foreach (var a in observation.Records.Earthquake)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                if (a.EarthquakeNo <= nowNo)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    Dictionary<string, object> EarthquakeAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        { "@earthquakeNo", a.EarthquakeNo},
 | 
				
			||||||
 | 
					                                        { "@newEarthquake", 0},
 | 
				
			||||||
 | 
					                                        { "@originTime", DateTime.Parse(a.EarthquakeInfo.OriginTime.ToString(), System.Globalization.CultureInfo.CurrentCulture)},
 | 
				
			||||||
 | 
					                                        { "@magnitudeValue", a.EarthquakeInfo.EarthquakeMagnitude.MagnitudeValue},
 | 
				
			||||||
 | 
					                                        { "@areaName", null},
 | 
				
			||||||
 | 
					                                        { "@areaIntensity", null},
 | 
				
			||||||
 | 
					                                        { "@created_by", "system"},
 | 
				
			||||||
 | 
					                                        { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                                    };
 | 
				
			||||||
 | 
					                                    EarthquakeAPIdbS.Add(EarthquakeAPIdb);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (a.Intensity.ShakingArea.Length > 0)
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        Dictionary<string, object> EarthquakeAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            { "@earthquakeNo", a.EarthquakeNo},
 | 
				
			||||||
 | 
					                                            { "@newEarthquake", 1},
 | 
				
			||||||
 | 
					                                            { "@originTime", DateTime.Parse(a.EarthquakeInfo.OriginTime.ToString(), System.Globalization.CultureInfo.CurrentCulture)},
 | 
				
			||||||
 | 
					                                            { "@magnitudeValue", a.EarthquakeInfo.EarthquakeMagnitude.MagnitudeValue},
 | 
				
			||||||
 | 
					                                            { "@areaName", a.Intensity.ShakingArea[0].CountyName},
 | 
				
			||||||
 | 
					                                            { "@areaIntensity", a.Intensity.ShakingArea[0].AreaIntensity},
 | 
				
			||||||
 | 
					                                            { "@created_by", "system"},
 | 
				
			||||||
 | 
					                                            { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var Nag = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_GEO/SeverityLEVL_LMI/set", a.Intensity.ShakingArea[0].AreaIntensity.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        if (Nag.Contains("err"))
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            EarthquakeAPIdb.Add("@niagara", Nag);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        else
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            EarthquakeAPIdb.Add("@niagara", "success");
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        EarthquakeAPIdbS.Add(EarthquakeAPIdb);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        Dictionary<string, object> EarthquakeAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            { "@earthquakeNo", a.EarthquakeNo},
 | 
				
			||||||
 | 
					                                            { "@newEarthquake", 1},
 | 
				
			||||||
 | 
					                                            { "@originTime", DateTime.Parse(a.EarthquakeInfo.OriginTime.ToString(), System.Globalization.CultureInfo.CurrentCulture)},
 | 
				
			||||||
 | 
					                                            { "@magnitudeValue", a.EarthquakeInfo.EarthquakeMagnitude.MagnitudeValue},
 | 
				
			||||||
 | 
					                                            { "@areaName", null},
 | 
				
			||||||
 | 
					                                            { "@areaIntensity", null},
 | 
				
			||||||
 | 
					                                            { "@created_by", "system"},
 | 
				
			||||||
 | 
					                                            { "@created_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},
 | 
				
			||||||
 | 
					                                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        var Nag = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/CAP/D2_CWB_L110_CAP_GEO/SeverityLEVL_LMI/set", "NULL");
 | 
				
			||||||
 | 
					                                        if (Nag.Contains("err"))
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            EarthquakeAPIdb.Add("@niagara", Nag);
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        else
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            EarthquakeAPIdb.Add("@niagara", "success");
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        EarthquakeAPIdbS.Add(EarthquakeAPIdb);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            await backendRepository.AddMutiByCustomTable(EarthquakeAPIdbS, "api_earthquake");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime_End("WeatherAPI", "api_earthquake");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("WeatherAPI", "api_earthquake", ex.Message.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (await task_Detail.GetNeedWorkTask("WeatherAPI", "set_weather"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    try
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime("WeatherAPI", "set_weather");
 | 
				
			||||||
 | 
					                        var sql = @$"SELECT	
 | 
				
			||||||
 | 
					                                    id,
 | 
				
			||||||
 | 
					                                    weather_type,
 | 
				
			||||||
 | 
					                                    get_value
 | 
				
			||||||
 | 
					                            FROM api_weateher
 | 
				
			||||||
 | 
					                            where id in (select MAX(id) from api_weateher where start_time < NOW() group by weather_type)
 | 
				
			||||||
 | 
					                            order by start_time desc";
 | 
				
			||||||
 | 
					                        var types = await backendRepository.GetAllAsync<ShowWeather>(sql);
 | 
				
			||||||
 | 
					                        var T = types.Where(a => a.weather_type == "T").FirstOrDefault();
 | 
				
			||||||
 | 
					                        var RbT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set", T.get_value);
 | 
				
			||||||
 | 
					                        UpdatedNiagara("api_weateher", RbT, T.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var RH = types.Where(a => a.weather_type == "RH").FirstOrDefault();
 | 
				
			||||||
 | 
					                        var RHT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set", RH.get_value);
 | 
				
			||||||
 | 
					                        UpdatedNiagara("api_weateher", RHT, RH.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var PoP12h = types.Where(a => a.weather_type == "PoP12h").FirstOrDefault();
 | 
				
			||||||
 | 
					                        var PoP12hT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set", PoP12h.get_value);
 | 
				
			||||||
 | 
					                        UpdatedNiagara("api_weateher", PoP12hT, PoP12h.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var Wx = types.Where(a => a.weather_type == "Wx").FirstOrDefault();
 | 
				
			||||||
 | 
					                        var WxT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set", Wx.get_value);
 | 
				
			||||||
 | 
					                        UpdatedNiagara("api_weateher", WxT, Wx.id);
 | 
				
			||||||
 | 
					                        await task_Detail.InsertWorkTime_End("WeatherAPI", "set_weather");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception ex)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message.ToString());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【WeatherAPIJob】【任務失敗】");
 | 
				
			||||||
 | 
					                logger.LogError("【WeatherAPIJob】【任務失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int RainValue(string Ty, string Headline)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var rint = 5;
 | 
				
			||||||
 | 
					            if (Ty == "")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (Headline.Contains("大雨"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    rint = 1;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (Headline.Contains("豪雨"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    rint = 2;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (Headline.Contains("大豪雨"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    rint = 3;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (Headline.Contains("超大豪雨"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    rint = 4;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return rint;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async void UpdatedNiagara(string DBTableName, string ResponseStr, int CheckNumId)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var Su = "success";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ResponseStr.Contains("err"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Su = ResponseStr;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Dictionary<string, object> RainAPIdb = new Dictionary<string, object>()
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    { "@niagara", Su}
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                await backendRepository.UpdateOneByCustomTable(RainAPIdb, DBTableName, " id = " + CheckNumId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【WeatherAPIJob】" + "UpdatedNiagara:" + ex.ToString());
 | 
				
			||||||
 | 
					                throw ex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										69
									
								
								Backend/Quartz/QuartzHostedService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Backend/Quartz/QuartzHostedService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.Hosting;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Quartz.Spi;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class QuartzHostedService : IHostedService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ISchedulerFactory _schedulerFactory;
 | 
				
			||||||
 | 
					        private readonly IJobFactory _jobFactory;
 | 
				
			||||||
 | 
					        private readonly IEnumerable<JobSchedule> _jobSchedules;
 | 
				
			||||||
 | 
					        public QuartzHostedService(ISchedulerFactory schedulerFactory, IJobFactory jobFactory, IEnumerable<JobSchedule> jobSchedules)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory));
 | 
				
			||||||
 | 
					            _jobFactory = jobFactory ?? throw new ArgumentNullException(nameof(jobFactory));
 | 
				
			||||||
 | 
					            _jobSchedules = jobSchedules ?? throw new ArgumentNullException(nameof(jobSchedules));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IScheduler Scheduler { get; set; }
 | 
				
			||||||
 | 
					        public async Task StartAsync(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
 | 
				
			||||||
 | 
					            Scheduler.JobFactory = _jobFactory;
 | 
				
			||||||
 | 
					            foreach (var jobSchedule in _jobSchedules)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var job = CreateJob(jobSchedule);
 | 
				
			||||||
 | 
					                var trigger = CreateTrigger(jobSchedule);
 | 
				
			||||||
 | 
					                await Scheduler.ScheduleJob(job, trigger, cancellationToken);
 | 
				
			||||||
 | 
					                jobSchedule.JobStatu = JobStatus.Scheduling;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            await Scheduler.Start(cancellationToken);
 | 
				
			||||||
 | 
					            foreach (var jobSchedule in _jobSchedules)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                jobSchedule.JobStatu = JobStatus.Running;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public async Task StopAsync(CancellationToken cancellationToken)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            await Scheduler?.Shutdown(cancellationToken);
 | 
				
			||||||
 | 
					            foreach (var jobSchedule in _jobSchedules)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                jobSchedule.JobStatu = JobStatus.Stopped;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        private static IJobDetail CreateJob(JobSchedule schedule)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var jobType = schedule.JobType;
 | 
				
			||||||
 | 
					            return JobBuilder
 | 
				
			||||||
 | 
					                .Create(jobType)
 | 
				
			||||||
 | 
					                .WithIdentity(jobType.FullName)
 | 
				
			||||||
 | 
					                .WithDescription(jobType.Name)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        private static ITrigger CreateTrigger(JobSchedule schedule)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return TriggerBuilder
 | 
				
			||||||
 | 
					                .Create()
 | 
				
			||||||
 | 
					                .WithIdentity($"{schedule.JobType.FullName}.trigger")
 | 
				
			||||||
 | 
					                .WithCronSchedule(schedule.CronExpression)
 | 
				
			||||||
 | 
					                .WithDescription(schedule.CronExpression)
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								Backend/Quartz/SingletonJobFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Backend/Quartz/SingletonJobFactory.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					using Quartz.Spi;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Backend.Quartz
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SingletonJobFactory : IJobFactory
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IServiceProvider _serviceProvider;
 | 
				
			||||||
 | 
					        public SingletonJobFactory(IServiceProvider serviceProvider)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public void ReturnJob(IJob job)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										935
									
								
								Backend/Services/Implement/ProcEletricMeterService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										935
									
								
								Backend/Services/Implement/ProcEletricMeterService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,935 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Configuration;
 | 
				
			||||||
 | 
					using System.Data;
 | 
				
			||||||
 | 
					using System.Data.SqlClient;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using Dapper;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System.Xml;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Repository.Helper;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Interface;
 | 
				
			||||||
 | 
					using Repository.BackendRepository.Implement;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Implement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 電錶補償歸檔
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class ProcEletricMeterService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceRepository backgroundServiceRepository;
 | 
				
			||||||
 | 
					        private readonly IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ProcEletricMeterService(IBackgroundServiceRepository backgroundServiceRepository,
 | 
				
			||||||
 | 
					            IBackgroundServiceMsSqlRepository backgroundServiceMySqlRepository)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.backgroundServiceRepository = backgroundServiceRepository;
 | 
				
			||||||
 | 
					            this.backgroundServiceMsSqlRepository = backgroundServiceMySqlRepository;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task<bool> ArchiveData()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            bool result = false;
 | 
				
			||||||
 | 
					            int repeatTimes = 0;
 | 
				
			||||||
 | 
					            string targetTable = string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            EDFunction ed = new EDFunction();
 | 
				
			||||||
 | 
					            XmlDocument xmlDocument = new XmlDocument();
 | 
				
			||||||
 | 
					            var obixApiConfig = new ObixApiConfig();
 | 
				
			||||||
 | 
					            string encoded = string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                //取得可錯誤次數
 | 
				
			||||||
 | 
					                var sqlArchive = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'archiveConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var variableArchive = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlArchive);
 | 
				
			||||||
 | 
					                repeatTimes = Convert.ToInt32(variableArchive.Where(x => x.Name == "RepeatTimes").Select(x => x.Value).FirstOrDefault());
 | 
				
			||||||
 | 
					                var saveToMSDB = await backgroundServiceRepository.GetOneAsync<string>("select system_value from variable where system_type = 'save_to_ms_db' and deleted = 0");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                #region 取得obix 設定
 | 
				
			||||||
 | 
					                var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var variableObix = await backgroundServiceRepository.GetAllAsync<KeyValue>(sqlObix);
 | 
				
			||||||
 | 
					                obixApiConfig.ApiBase = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                obixApiConfig.UserName = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					                obixApiConfig.Password = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password));
 | 
				
			||||||
 | 
					                #endregion 取得obix 設定
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //取得錯誤的設備sql format
 | 
				
			||||||
 | 
					                var sql_error_format = @"SELECT * FROM {0} WHERE is_complete = 0 AND repeat_times < @RepeatTimes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //MY 新增/修改sql format
 | 
				
			||||||
 | 
					                var MYsql_update_format = @"
 | 
				
			||||||
 | 
					                                            UPDATE {0} SET 
 | 
				
			||||||
 | 
					                                                    count_rawdata = @count_rawdata,
 | 
				
			||||||
 | 
					                                                    min_rawdata = @min_rawdata,
 | 
				
			||||||
 | 
					                                                    max_rawdata = @max_rawdata,
 | 
				
			||||||
 | 
					                                                    avg_rawdata = @avg_rawdata,
 | 
				
			||||||
 | 
					                                                    sum_rawdata = @sum_rawdata,
 | 
				
			||||||
 | 
					                                                    is_complete = @is_complete,
 | 
				
			||||||
 | 
					                                                    repeat_times = @repeat_times,
 | 
				
			||||||
 | 
					                                                    fail_reason = @fail_reason,
 | 
				
			||||||
 | 
					                                                    updated_at = @updated_at
 | 
				
			||||||
 | 
					                                                 WHERE device_number = @device_number
 | 
				
			||||||
 | 
					                                                    AND point = @point
 | 
				
			||||||
 | 
					                                                    AND start_timestamp = @start_timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                                INSERT INTO {0} (
 | 
				
			||||||
 | 
					                                                    device_number,
 | 
				
			||||||
 | 
					                                                    point,
 | 
				
			||||||
 | 
					                                                    start_timestamp,
 | 
				
			||||||
 | 
					                                                    end_timestamp,
 | 
				
			||||||
 | 
					                                                    count_rawdata,
 | 
				
			||||||
 | 
					                                                    min_rawdata,
 | 
				
			||||||
 | 
					                                                    max_rawdata,
 | 
				
			||||||
 | 
					                                                    avg_rawdata,
 | 
				
			||||||
 | 
					                                                    sum_rawdata,
 | 
				
			||||||
 | 
					                                                    is_complete,
 | 
				
			||||||
 | 
					                                                    repeat_times,
 | 
				
			||||||
 | 
					                                                    fail_reason)
 | 
				
			||||||
 | 
					                                                SELECT
 | 
				
			||||||
 | 
					                                                    @device_number,
 | 
				
			||||||
 | 
					                                                    @point,
 | 
				
			||||||
 | 
					                                                    @start_timestamp,
 | 
				
			||||||
 | 
					                                                    @end_timestamp,
 | 
				
			||||||
 | 
					                                                    @count_rawdata,
 | 
				
			||||||
 | 
					                                                    @min_rawdata,
 | 
				
			||||||
 | 
					                                                    @max_rawdata,
 | 
				
			||||||
 | 
					                                                    @avg_rawdata,
 | 
				
			||||||
 | 
					                                                    @sum_rawdata,
 | 
				
			||||||
 | 
					                                                    @is_complete,
 | 
				
			||||||
 | 
					                                                    @repeat_times,
 | 
				
			||||||
 | 
					                                                    @fail_reason
 | 
				
			||||||
 | 
					                                                WHERE ROW_COUNT() = 0;";
 | 
				
			||||||
 | 
					                //新增/修改sql format
 | 
				
			||||||
 | 
					                var sql_update_format = @"BEGIN TRANSACTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            UPDATE {0} SET 
 | 
				
			||||||
 | 
					                                                    count_rawdata = @count_rawdata,
 | 
				
			||||||
 | 
					                                                    min_rawdata = @min_rawdata,
 | 
				
			||||||
 | 
					                                                    max_rawdata = @max_rawdata,
 | 
				
			||||||
 | 
					                                                    avg_rawdata = @avg_rawdata,
 | 
				
			||||||
 | 
					                                                    sum_rawdata = @sum_rawdata,
 | 
				
			||||||
 | 
					                                                    is_complete = @is_complete,
 | 
				
			||||||
 | 
					                                                    repeat_times = @repeat_times,
 | 
				
			||||||
 | 
					                                                    fail_reason = @fail_reason,
 | 
				
			||||||
 | 
					                                                    updated_at = @updated_at
 | 
				
			||||||
 | 
					                                                 WHERE device_number = @device_number
 | 
				
			||||||
 | 
					                                                    AND point = @point
 | 
				
			||||||
 | 
					                                                    AND start_timestamp = @start_timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                            IF @@ROWCOUNT = 0
 | 
				
			||||||
 | 
					                                            BEGIN
 | 
				
			||||||
 | 
					                                                INSERT INTO {0} (
 | 
				
			||||||
 | 
					                                                    device_number,
 | 
				
			||||||
 | 
					                                                    point,
 | 
				
			||||||
 | 
					                                                    start_timestamp,
 | 
				
			||||||
 | 
					                                                    end_timestamp,
 | 
				
			||||||
 | 
					                                                    count_rawdata,
 | 
				
			||||||
 | 
					                                                    min_rawdata,
 | 
				
			||||||
 | 
					                                                    max_rawdata,
 | 
				
			||||||
 | 
					                                                    avg_rawdata,
 | 
				
			||||||
 | 
					                                                    sum_rawdata,
 | 
				
			||||||
 | 
					                                                    is_complete,
 | 
				
			||||||
 | 
					                                                    repeat_times,
 | 
				
			||||||
 | 
					                                                    fail_reason)
 | 
				
			||||||
 | 
					                                                VALUES (
 | 
				
			||||||
 | 
					                                                    @device_number,
 | 
				
			||||||
 | 
					                                                    @point,
 | 
				
			||||||
 | 
					                                                    @start_timestamp,
 | 
				
			||||||
 | 
					                                                    @end_timestamp,
 | 
				
			||||||
 | 
					                                                    @count_rawdata,
 | 
				
			||||||
 | 
					                                                    @min_rawdata,
 | 
				
			||||||
 | 
					                                                    @max_rawdata,
 | 
				
			||||||
 | 
					                                                    @avg_rawdata,
 | 
				
			||||||
 | 
					                                                    @sum_rawdata,
 | 
				
			||||||
 | 
					                                                    @is_complete,
 | 
				
			||||||
 | 
					                                                    @repeat_times,
 | 
				
			||||||
 | 
					                                                    @fail_reason)
 | 
				
			||||||
 | 
					                                            END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                        COMMIT TRANSACTION;";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                #region 時歸檔補償
 | 
				
			||||||
 | 
					                //using (IDbConnection conn = new SqlConnection(Connection1))
 | 
				
			||||||
 | 
					                //{
 | 
				
			||||||
 | 
					                //    //取得所有須補償的設備資訊
 | 
				
			||||||
 | 
					                //    targetTable = "archive_electric_meter_hour";
 | 
				
			||||||
 | 
					                //    var sql_error_hour = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                //    var error_hours = conn.Query<ArchiveElectricMeter>(sql_error_hour, new { RepeatTimes = repeatTimes }).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //    List<Dictionary<string, object>> archiveHourRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                //    if (error_hours.Count() > 0)
 | 
				
			||||||
 | 
					                //    {
 | 
				
			||||||
 | 
					                //        foreach (var error_hour in error_hours)
 | 
				
			||||||
 | 
					                //        {
 | 
				
			||||||
 | 
					                //            DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                //            deviceNumberPoint.DeviceNumber = error_hour.Device_number;
 | 
				
			||||||
 | 
					                //            deviceNumberPoint.Point = error_hour.Point;
 | 
				
			||||||
 | 
					                //            deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_hour.Device_number, error_hour.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            var startTimestamp = string.Format("{0}+08:00", error_hour.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                //            var endTimestamp = string.Format("{0}+08:00", error_hour.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                //                                    <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                //                                    <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                //                                    <reltime name='interval' val = 'PT1H' />
 | 
				
			||||||
 | 
					                //                                </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                //            //HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                //            archiveHourRequest.Method = "POST";
 | 
				
			||||||
 | 
					                //            archiveHourRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                //            archiveHourRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                //            using (Stream reqStream = archiveHourRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                //            {
 | 
				
			||||||
 | 
					                //                reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                //            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            HttpWebResponse archiveHourResponse = (HttpWebResponse)archiveHourRequest.GetResponse();
 | 
				
			||||||
 | 
					                //            var archiveHourResponseContent = new StreamReader(archiveHourResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            xmlDocument.LoadXml(archiveHourResponseContent);
 | 
				
			||||||
 | 
					                //            string archiveHourJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                //            JObject archiveHourJsonResult = (JObject)JsonConvert.DeserializeObject(archiveHourJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            if (archiveHourJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                //            {
 | 
				
			||||||
 | 
					                //                Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@device_number", error_hour.Device_number);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@point", error_hour.Point);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@start_timestamp", error_hour.Start_timestamp);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@end_timestamp", error_hour.End_timestamp);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@repeat_times", ++error_hour.Repeat_times);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@fail_reason", archiveHourJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                //                archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //                archiveHourRawDatas.Add(archiveDayRawData);
 | 
				
			||||||
 | 
					                //            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //            if (archiveHourJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                //            {
 | 
				
			||||||
 | 
					                //                var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveHourJsonResult);
 | 
				
			||||||
 | 
					                //                if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                //                {
 | 
				
			||||||
 | 
					                //                    archiveHourRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                //                }
 | 
				
			||||||
 | 
					                //            }
 | 
				
			||||||
 | 
					                //        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //        if (archiveHourRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                //        {
 | 
				
			||||||
 | 
					                //            var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                //            conn.Execute(sql_error_update, archiveHourRawDatas);
 | 
				
			||||||
 | 
					                //        }
 | 
				
			||||||
 | 
					                //    }
 | 
				
			||||||
 | 
					                //    conn.Close();
 | 
				
			||||||
 | 
					                //}
 | 
				
			||||||
 | 
					                #endregion 時歸檔補償
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                #region 天歸檔補償
 | 
				
			||||||
 | 
					                //取得所有須補償的設備資訊
 | 
				
			||||||
 | 
					                targetTable = "archive_electric_meter_day";
 | 
				
			||||||
 | 
					                var sql_error_day = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var electric_error_days = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_day, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> electricArchiveDayRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (electric_error_days.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_day in electric_error_days)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_day.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_day.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_day.Device_number, error_day.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_day.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_day.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT1D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveDayRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveDayRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveDayRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveDayRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveDayResponse = (HttpWebResponse)archiveDayRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveDayResponseContent = new StreamReader(archiveDayResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveDayResponseContent);
 | 
				
			||||||
 | 
					                        string archiveDayJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveDayJsonResult = (JObject)JsonConvert.DeserializeObject(archiveDayJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveDayJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@device_number", error_day.Device_number);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@point", error_day.Point);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@start_timestamp", DateTime.Parse(error_day.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@end_timestamp", DateTime.Parse(error_day.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@repeat_times", ++error_day.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@fail_reason", archiveDayJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            electricArchiveDayRawDatas.Add(archiveDayRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveDayJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveDayJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                electricArchiveDayRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (electricArchiveDayRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        { 
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, electricArchiveDayRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, electricArchiveDayRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                targetTable = "archive_water_meter_day";
 | 
				
			||||||
 | 
					                sql_error_day = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var water_error_days = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_day, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> waterArchiveDayRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (water_error_days.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_day in water_error_days)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_day.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_day.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_day.Device_number, error_day.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_day.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_day.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT1D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveDayRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveDayRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveDayRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveDayRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveDayResponse = (HttpWebResponse)archiveDayRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveDayResponseContent = new StreamReader(archiveDayResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveDayResponseContent);
 | 
				
			||||||
 | 
					                        string archiveDayJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveDayJsonResult = (JObject)JsonConvert.DeserializeObject(archiveDayJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveDayJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveDayRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@device_number", error_day.Device_number);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@point", error_day.Point);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@start_timestamp", DateTime.Parse(error_day.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@end_timestamp", DateTime.Parse(error_day.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@repeat_times", ++error_day.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@fail_reason", archiveDayJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            waterArchiveDayRawDatas.Add(archiveDayRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveDayJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveDayJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                waterArchiveDayRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (waterArchiveDayRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, waterArchiveDayRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, waterArchiveDayRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #endregion 天歸檔補償
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                #region 週歸檔補償
 | 
				
			||||||
 | 
					                //取得所有須補償的設備資訊
 | 
				
			||||||
 | 
					                targetTable = "archive_electric_meter_week";
 | 
				
			||||||
 | 
					                var sql_error_week = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var eletric_error_weeks = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_week, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> electricArchiveWeekRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (eletric_error_weeks.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_week in eletric_error_weeks)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_week.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_week.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_week.Device_number, error_week.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_week.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_week.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT7D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveWeekRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveWeekRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveWeekRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveWeekRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveWeekResponse = (HttpWebResponse)archiveWeekRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveWeekResponseContent = new StreamReader(archiveWeekResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveWeekResponseContent);
 | 
				
			||||||
 | 
					                        string archiveWeekJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveWeekJsonResult = (JObject)JsonConvert.DeserializeObject(archiveWeekJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveWeekJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveWeekRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@device_number", error_week.Device_number);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@point", error_week.Point);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@start_timestamp", DateTime.Parse(error_week.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@end_timestamp", DateTime.Parse(error_week.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@repeat_times", ++error_week.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@fail_reason", archiveWeekJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            electricArchiveWeekRawDatas.Add(archiveWeekRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveWeekJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveWeekJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                electricArchiveWeekRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (electricArchiveWeekRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, electricArchiveWeekRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, electricArchiveWeekRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                targetTable = "archive_water_meter_week";
 | 
				
			||||||
 | 
					                sql_error_week = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var water_error_weeks = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_week, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> waterArchiveWeekRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (water_error_weeks.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_week in water_error_weeks)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_week.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_week.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_week.Device_number, error_week.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_week.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_week.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT7D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveWeekRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveWeekRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveWeekRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveWeekRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveWeekResponse = (HttpWebResponse)archiveWeekRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveWeekResponseContent = new StreamReader(archiveWeekResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveWeekResponseContent);
 | 
				
			||||||
 | 
					                        string archiveWeekJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveWeekJsonResult = (JObject)JsonConvert.DeserializeObject(archiveWeekJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveWeekJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveWeekRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@device_number", error_week.Device_number);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@point", error_week.Point);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@start_timestamp", DateTime.Parse(error_week.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@end_timestamp", DateTime.Parse(error_week.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@repeat_times", ++error_week.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@fail_reason", archiveWeekJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            waterArchiveWeekRawDatas.Add(archiveWeekRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveWeekJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveWeekJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                waterArchiveWeekRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (waterArchiveWeekRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, waterArchiveWeekRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(Mysql_error_update, waterArchiveWeekRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #endregion 週歸檔補償
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                #region 月歸檔補償
 | 
				
			||||||
 | 
					                //取得所有須補償的設備資訊
 | 
				
			||||||
 | 
					                targetTable = "archive_electric_meter_month";
 | 
				
			||||||
 | 
					                var sql_error_month = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var electric_error_months = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_month, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> electricArchiveMonthRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (electric_error_months.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_month in electric_error_months)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_month.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_month.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_month.Device_number, error_month.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_month.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_month.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startDateTime = Convert.ToDateTime(error_month.Start_timestamp);
 | 
				
			||||||
 | 
					                        var dayInMonth = DateTime.DaysInMonth(startDateTime.Year, startDateTime.Month);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT{dayInMonth}D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveMonthRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveMonthRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveMonthRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveMonthRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveMonthResponse = (HttpWebResponse)archiveMonthRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveMonthResponseContent = new StreamReader(archiveMonthResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveMonthResponseContent);
 | 
				
			||||||
 | 
					                        string archiveMonthJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveMonthJsonResult = (JObject)JsonConvert.DeserializeObject(archiveMonthJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveMonthJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveMonthRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@device_number", error_month.Device_number);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@point", error_month.Point);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@start_timestamp", DateTime.Parse(error_month.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@end_timestamp", DateTime.Parse(error_month.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@repeat_times", ++error_month.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@fail_reason", archiveMonthJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            electricArchiveMonthRawDatas.Add(archiveMonthRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveMonthJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveMonthJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                electricArchiveMonthRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (electricArchiveMonthRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, electricArchiveMonthRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(MYsql_update_format, electricArchiveMonthRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                targetTable = "archive_electric_meter_month";
 | 
				
			||||||
 | 
					                sql_error_month = string.Format(sql_error_format, targetTable);
 | 
				
			||||||
 | 
					                var water_error_months = await backgroundServiceRepository.GetAllAsync<ArchiveElectricMeter>(sql_error_month, new { RepeatTimes = repeatTimes });
 | 
				
			||||||
 | 
					                List<Dictionary<string, object>> waterArchiveMonthRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					                if (water_error_months.Count() > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    foreach (var error_month in water_error_months)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint();
 | 
				
			||||||
 | 
					                        deviceNumberPoint.DeviceNumber = error_month.Device_number;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.Point = error_month.Point;
 | 
				
			||||||
 | 
					                        deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", error_month.Device_number, error_month.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startTimestamp = string.Format("{0}+08:00", error_month.Start_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					                        var endTimestamp = string.Format("{0}+08:00", error_month.End_timestamp.Replace(" ", "T"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var startDateTime = Convert.ToDateTime(error_month.Start_timestamp);
 | 
				
			||||||
 | 
					                        var dayInMonth = DateTime.DaysInMonth(startDateTime.Year, startDateTime.Month);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var historyQueryFilter = $@"<obj is='obix: HistoryFilter'>
 | 
				
			||||||
 | 
					                                                <abstime name='start' val='{startTimestamp}' />
 | 
				
			||||||
 | 
					                                                <abstime name='end' val='{endTimestamp}' />
 | 
				
			||||||
 | 
					                                                <reltime name='interval' val = 'PT{dayInMonth}D' />
 | 
				
			||||||
 | 
					                                            </obj>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/");
 | 
				
			||||||
 | 
					                        //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/");
 | 
				
			||||||
 | 
					                        archiveMonthRequest.Method = "POST";
 | 
				
			||||||
 | 
					                        archiveMonthRequest.Headers.Add("Authorization", "Basic " + encoded);
 | 
				
			||||||
 | 
					                        archiveMonthRequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter);
 | 
				
			||||||
 | 
					                        using (Stream reqStream = archiveMonthRequest.GetRequestStream())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            reqStream.Write(byteArray, 0, byteArray.Length);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        HttpWebResponse archiveMonthResponse = (HttpWebResponse)archiveMonthRequest.GetResponse();
 | 
				
			||||||
 | 
					                        var archiveMonthResponseContent = new StreamReader(archiveMonthResponse.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        xmlDocument.LoadXml(archiveMonthResponseContent);
 | 
				
			||||||
 | 
					                        string archiveMonthJson = JsonConvert.SerializeXmlNode(xmlDocument);
 | 
				
			||||||
 | 
					                        JObject archiveMonthJsonResult = (JObject)JsonConvert.DeserializeObject(archiveMonthJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveMonthJsonResult.ContainsKey("err")) //抓取錯誤
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            Dictionary<string, object> archiveMonthRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@device_number", error_month.Device_number);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@point", error_month.Point);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@start_timestamp", DateTime.Parse(error_month.Start_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@end_timestamp", DateTime.Parse(error_month.End_timestamp, System.Globalization.CultureInfo.CurrentCulture));
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@is_complete", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@repeat_times", ++error_month.Repeat_times);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@fail_reason", archiveMonthJson);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@count_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@min_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@max_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@avg_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@sum_rawdata", 0);
 | 
				
			||||||
 | 
					                            archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            waterArchiveMonthRawDatas.Add(archiveMonthRawData);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (archiveMonthJsonResult.ContainsKey("obj")) //表示可以讀取到內容
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveMonthJsonResult);
 | 
				
			||||||
 | 
					                            if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                waterArchiveMonthRawDatas.AddRange(ArrangeRawDatas);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (waterArchiveMonthRawDatas.Count() > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var Mysql_error_update = string.Format(MYsql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        var sql_error_update = string.Format(sql_update_format, targetTable);
 | 
				
			||||||
 | 
					                        if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1")
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            await backgroundServiceMsSqlRepository.ExecuteSql(sql_error_update, waterArchiveMonthRawDatas);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        await backgroundServiceRepository.ExecuteSql(MYsql_update_format, waterArchiveMonthRawDatas);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                #endregion 月歸檔補償
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                result = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw exception;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private List<Dictionary<string, object>> ArrangeRawData(DeviceNumberPoint deviceNumberPoint, JObject jsonResult)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<Dictionary<string, object>> arrangeRawDatas = new List<Dictionary<string, object>>();
 | 
				
			||||||
 | 
					            var histories = jsonResult["obj"]["list"];
 | 
				
			||||||
 | 
					            var rawdateCount = Convert.ToInt32(jsonResult["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (rawdateCount == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (histories != null && histories.HasValues)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (rawdateCount > 1)
 | 
				
			||||||
 | 
					                {   //多筆資料
 | 
				
			||||||
 | 
					                    foreach (var history in histories)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Dictionary<string, object> arrangeRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@point", deviceNumberPoint.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //時間
 | 
				
			||||||
 | 
					                        if (history["abstime"] != null && history["abstime"].HasValues)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            foreach (var abstime in history["abstime"])
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var name = abstime["@name"].ToString();
 | 
				
			||||||
 | 
					                                switch (name)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    case "start":
 | 
				
			||||||
 | 
					                                        var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@start_timestamp", startTimstamp);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                    case "end":
 | 
				
			||||||
 | 
					                                        var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@end_timestamp", endTimstamp);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //區間內資料筆數
 | 
				
			||||||
 | 
					                        if (history["int"] != null && history["int"].HasValues)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					                            arrangeRawData.Add("@count_rawdata", count);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //整合數值(最大、最小、平均、總和)
 | 
				
			||||||
 | 
					                        if (history["real"] != null && history["real"].HasValues)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            foreach (var real in history["real"])
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                var name = real["@name"].ToString();
 | 
				
			||||||
 | 
					                                switch (name)
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    case "min":
 | 
				
			||||||
 | 
					                                        var min = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@min_rawdata", min);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                    case "max":
 | 
				
			||||||
 | 
					                                        var max = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@max_rawdata", max);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                    case "avg":
 | 
				
			||||||
 | 
					                                        var avg = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@avg_rawdata", avg);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                    case "sum":
 | 
				
			||||||
 | 
					                                        var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float);
 | 
				
			||||||
 | 
					                                        arrangeRawData.Add("@sum_rawdata", sum);
 | 
				
			||||||
 | 
					                                        break;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@repeat_times", 0);
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@fail_reason", null);
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        arrangeRawDatas.Add(arrangeRawData);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {   //單筆資料
 | 
				
			||||||
 | 
					                    Dictionary<string, object> arrangeRawData = new Dictionary<string, object>();
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber);
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@point", deviceNumberPoint.Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //時間
 | 
				
			||||||
 | 
					                    if (histories["obj"]["abstime"] != null && histories["obj"]["abstime"].HasValues)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        foreach (var abstime in histories["obj"]["abstime"])
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var name = abstime["@name"].ToString();
 | 
				
			||||||
 | 
					                            switch (name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "start":
 | 
				
			||||||
 | 
					                                    var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@start_timestamp", startTimstamp);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case "end":
 | 
				
			||||||
 | 
					                                    var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss");
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@end_timestamp", endTimstamp);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //區間內資料筆數
 | 
				
			||||||
 | 
					                    if (histories["obj"]["int"] != null && histories["obj"]["int"].HasValues)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString());
 | 
				
			||||||
 | 
					                        arrangeRawData.Add("@count_rawdata", count);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    //整合數值(最大、最小、平均、總和)
 | 
				
			||||||
 | 
					                    if (histories["obj"]["real"] != null && histories["obj"]["real"].HasValues)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        foreach (var real in histories["obj"]["real"])
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var name = real["@name"].ToString();
 | 
				
			||||||
 | 
					                            switch (name)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                case "min":
 | 
				
			||||||
 | 
					                                    var min = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@min_rawdata", min);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case "max":
 | 
				
			||||||
 | 
					                                    var max = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@max_rawdata", max);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case "avg":
 | 
				
			||||||
 | 
					                                    var avg = Convert.ToDecimal(real["@val"].ToString());
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@avg_rawdata", avg);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                                case "sum":
 | 
				
			||||||
 | 
					                                    var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float);
 | 
				
			||||||
 | 
					                                    arrangeRawData.Add("@sum_rawdata", sum);
 | 
				
			||||||
 | 
					                                    break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@is_complete", 1);
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@repeat_times", 0);
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@fail_reason", null);
 | 
				
			||||||
 | 
					                    arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    arrangeRawDatas.Add(arrangeRawData);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return arrangeRawDatas;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										640
									
								
								Backend/Services/Implement/Quicktype.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										640
									
								
								Backend/Services/Implement/Quicktype.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,640 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// <auto-generated />
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    using QuickType;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    var welcome = Welcome.FromJson(jsonString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace QuickType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using System.Globalization;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json.Converters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("success")]
 | 
				
			||||||
 | 
					        [JsonConverter(typeof(ParseStringConverter))]
 | 
				
			||||||
 | 
					        public bool Success { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("result")]
 | 
				
			||||||
 | 
					        public Result Result { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("records")]
 | 
				
			||||||
 | 
					        public Records Records { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Records
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("datasetDescription")]
 | 
				
			||||||
 | 
					        public DatasetDescription DatasetDescription { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("Earthquake")]
 | 
				
			||||||
 | 
					        public Earthquake[] Earthquake { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Earthquake
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("EarthquakeNo")]
 | 
				
			||||||
 | 
					        public long EarthquakeNo { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ReportType")]
 | 
				
			||||||
 | 
					        public DatasetDescription ReportType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ReportColor")]
 | 
				
			||||||
 | 
					        public ReportColor ReportColor { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ReportContent")]
 | 
				
			||||||
 | 
					        public string ReportContent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ReportImageURI")]
 | 
				
			||||||
 | 
					        public Uri ReportImageUri { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ReportRemark")]
 | 
				
			||||||
 | 
					        public ReportRemark ReportRemark { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("Web")]
 | 
				
			||||||
 | 
					        public Uri Web { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("ShakemapImageURI")]
 | 
				
			||||||
 | 
					        public Uri ShakemapImageUri { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EarthquakeInfo")]
 | 
				
			||||||
 | 
					        public EarthquakeInfo EarthquakeInfo { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("Intensity")]
 | 
				
			||||||
 | 
					        public Intensity Intensity { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class EarthquakeInfo
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("OriginTime")]
 | 
				
			||||||
 | 
					        public DateTimeOffset OriginTime { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("Source")]
 | 
				
			||||||
 | 
					        public Source Source { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("FocalDepth")]
 | 
				
			||||||
 | 
					        public double FocalDepth { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("Epicenter")]
 | 
				
			||||||
 | 
					        public Epicenter Epicenter { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EarthquakeMagnitude")]
 | 
				
			||||||
 | 
					        public EarthquakeMagnitude EarthquakeMagnitude { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class EarthquakeMagnitude
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("MagnitudeType")]
 | 
				
			||||||
 | 
					        public MagnitudeType MagnitudeType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("MagnitudeValue")]
 | 
				
			||||||
 | 
					        public double MagnitudeValue { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Epicenter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("Location")]
 | 
				
			||||||
 | 
					        public string Location { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EpicenterLatitude")]
 | 
				
			||||||
 | 
					        public double EpicenterLatitude { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EpicenterLongitude")]
 | 
				
			||||||
 | 
					        public double EpicenterLongitude { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Intensity
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("ShakingArea")]
 | 
				
			||||||
 | 
					        public ShakingArea[] ShakingArea { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class ShakingArea
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("AreaDesc")]
 | 
				
			||||||
 | 
					        public string AreaDesc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("CountyName")]
 | 
				
			||||||
 | 
					        public string CountyName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("InfoStatus", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public InfoStatus? InfoStatus { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("AreaIntensity")]
 | 
				
			||||||
 | 
					        public AreaIntensityEnum AreaIntensity { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EqStation")]
 | 
				
			||||||
 | 
					        public EqStation[] EqStation { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class EqStation
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("pga", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Pga Pga { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("pgv", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Pga Pgv { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("StationName")]
 | 
				
			||||||
 | 
					        public string StationName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("StationID")]
 | 
				
			||||||
 | 
					        public string StationId { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("InfoStatus", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public InfoStatus? InfoStatus { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("BackAzimuth")]
 | 
				
			||||||
 | 
					        public double BackAzimuth { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EpicenterDistance")]
 | 
				
			||||||
 | 
					        public double EpicenterDistance { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("SeismicIntensity")]
 | 
				
			||||||
 | 
					        public AreaIntensityEnum SeismicIntensity { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("StationLatitude")]
 | 
				
			||||||
 | 
					        public double StationLatitude { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("StationLongitude")]
 | 
				
			||||||
 | 
					        public double StationLongitude { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("WaveImageURI", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Uri WaveImageUri { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Pga
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("unit")]
 | 
				
			||||||
 | 
					        public Unit Unit { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("EWComponent")]
 | 
				
			||||||
 | 
					        public double EwComponent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("NSComponent")]
 | 
				
			||||||
 | 
					        public double NsComponent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("VComponent")]
 | 
				
			||||||
 | 
					        public double VComponent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("IntScaleValue")]
 | 
				
			||||||
 | 
					        public double IntScaleValue { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Result
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("resource_id")]
 | 
				
			||||||
 | 
					        public string ResourceId { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("fields")]
 | 
				
			||||||
 | 
					        public Field[] Fields { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Field
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("id")]
 | 
				
			||||||
 | 
					        public string Id { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("type")]
 | 
				
			||||||
 | 
					        public TypeEnum Type { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum DatasetDescription { 地震報告 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum MagnitudeType { 芮氏規模 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum Source { 中央氣象局 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum AreaIntensityEnum { The1級, The2級, The3級, The4級 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum InfoStatus { Observe };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum Unit { Gal, Kine };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum ReportColor { 綠色 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum ReportRemark { 本報告係中央氣象局地震觀測網即時地震資料地震速報之結果 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum TypeEnum { Float, Integer, String, Timestamp };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static class Serialize
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static class Converter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
 | 
				
			||||||
 | 
					            DateParseHandling = DateParseHandling.None,
 | 
				
			||||||
 | 
					            Converters =
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                MagnitudeTypeConverter.Singleton,
 | 
				
			||||||
 | 
					                SourceConverter.Singleton,
 | 
				
			||||||
 | 
					                AreaIntensityEnumConverter.Singleton,
 | 
				
			||||||
 | 
					                InfoStatusConverter.Singleton,
 | 
				
			||||||
 | 
					                UnitConverter.Singleton,
 | 
				
			||||||
 | 
					                ReportColorConverter.Singleton,
 | 
				
			||||||
 | 
					                ReportRemarkConverter.Singleton,
 | 
				
			||||||
 | 
					                DatasetDescriptionConverter.Singleton,
 | 
				
			||||||
 | 
					                TypeEnumConverter.Singleton,
 | 
				
			||||||
 | 
					                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class MagnitudeTypeConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(MagnitudeType) || t == typeof(MagnitudeType?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "芮氏規模")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return MagnitudeType.芮氏規模;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type MagnitudeType");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (MagnitudeType)untypedValue;
 | 
				
			||||||
 | 
					            if (value == MagnitudeType.芮氏規模)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "芮氏規模");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type MagnitudeType");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly MagnitudeTypeConverter Singleton = new MagnitudeTypeConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class SourceConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(Source) || t == typeof(Source?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "中央氣象局")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return Source.中央氣象局;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type Source");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (Source)untypedValue;
 | 
				
			||||||
 | 
					            if (value == Source.中央氣象局)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "中央氣象局");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type Source");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly SourceConverter Singleton = new SourceConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class AreaIntensityEnumConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(AreaIntensityEnum) || t == typeof(AreaIntensityEnum?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "1級":
 | 
				
			||||||
 | 
					                    return AreaIntensityEnum.The1級;
 | 
				
			||||||
 | 
					                case "2級":
 | 
				
			||||||
 | 
					                    return AreaIntensityEnum.The2級;
 | 
				
			||||||
 | 
					                case "3級":
 | 
				
			||||||
 | 
					                    return AreaIntensityEnum.The3級;
 | 
				
			||||||
 | 
					                case "4級":
 | 
				
			||||||
 | 
					                    return AreaIntensityEnum.The4級;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type AreaIntensityEnum");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (AreaIntensityEnum)untypedValue;
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case AreaIntensityEnum.The1級:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "1級");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case AreaIntensityEnum.The2級:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "2級");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case AreaIntensityEnum.The3級:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "3級");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case AreaIntensityEnum.The4級:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "4級");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type AreaIntensityEnum");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly AreaIntensityEnumConverter Singleton = new AreaIntensityEnumConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class InfoStatusConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(InfoStatus) || t == typeof(InfoStatus?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "observe")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return InfoStatus.Observe;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type InfoStatus");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (InfoStatus)untypedValue;
 | 
				
			||||||
 | 
					            if (value == InfoStatus.Observe)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "observe");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type InfoStatus");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly InfoStatusConverter Singleton = new InfoStatusConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class UnitConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(Unit) || t == typeof(Unit?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "gal":
 | 
				
			||||||
 | 
					                    return Unit.Gal;
 | 
				
			||||||
 | 
					                case "kine":
 | 
				
			||||||
 | 
					                    return Unit.Kine;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type Unit");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (Unit)untypedValue;
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case Unit.Gal:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "gal");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case Unit.Kine:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "kine");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type Unit");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly UnitConverter Singleton = new UnitConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ReportColorConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(ReportColor) || t == typeof(ReportColor?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "綠色")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return ReportColor.綠色;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type ReportColor");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (ReportColor)untypedValue;
 | 
				
			||||||
 | 
					            if (value == ReportColor.綠色)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "綠色");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type ReportColor");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly ReportColorConverter Singleton = new ReportColorConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ReportRemarkConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(ReportRemark) || t == typeof(ReportRemark?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "本報告係中央氣象局地震觀測網即時地震資料地震速報之結果。")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return ReportRemark.本報告係中央氣象局地震觀測網即時地震資料地震速報之結果;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type ReportRemark");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (ReportRemark)untypedValue;
 | 
				
			||||||
 | 
					            if (value == ReportRemark.本報告係中央氣象局地震觀測網即時地震資料地震速報之結果)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "本報告係中央氣象局地震觀測網即時地震資料地震速報之結果。");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type ReportRemark");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly ReportRemarkConverter Singleton = new ReportRemarkConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class DatasetDescriptionConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(DatasetDescription) || t == typeof(DatasetDescription?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            if (value == "地震報告")
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return DatasetDescription.地震報告;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type DatasetDescription");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (DatasetDescription)untypedValue;
 | 
				
			||||||
 | 
					            if (value == DatasetDescription.地震報告)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, "地震報告");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type DatasetDescription");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly DatasetDescriptionConverter Singleton = new DatasetDescriptionConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class TypeEnumConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(TypeEnum) || t == typeof(TypeEnum?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Float":
 | 
				
			||||||
 | 
					                    return TypeEnum.Float;
 | 
				
			||||||
 | 
					                case "Integer":
 | 
				
			||||||
 | 
					                    return TypeEnum.Integer;
 | 
				
			||||||
 | 
					                case "String":
 | 
				
			||||||
 | 
					                    return TypeEnum.String;
 | 
				
			||||||
 | 
					                case "Timestamp":
 | 
				
			||||||
 | 
					                    return TypeEnum.Timestamp;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type TypeEnum");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (TypeEnum)untypedValue;
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case TypeEnum.Float:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "Float");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case TypeEnum.Integer:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "Integer");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case TypeEnum.String:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "String");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case TypeEnum.Timestamp:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "Timestamp");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type TypeEnum");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly TypeEnumConverter Singleton = new TypeEnumConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ParseStringConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(bool) || t == typeof(bool?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            bool b;
 | 
				
			||||||
 | 
					            if (Boolean.TryParse(value, out b))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return b;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type bool");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (bool)untypedValue;
 | 
				
			||||||
 | 
					            var boolString = value ? "true" : "false";
 | 
				
			||||||
 | 
					            serializer.Serialize(writer, boolString);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly ParseStringConverter Singleton = new ParseStringConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										228
									
								
								Backend/Services/Implement/RainApi.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								Backend/Services/Implement/RainApi.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,228 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// <auto-generated />
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    using QuickType;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    var welcome = Welcome.FromJson(jsonString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace RainApi
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using System.Globalization;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json.Converters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("?xml")]
 | 
				
			||||||
 | 
					        public Xml Xml { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("alert")]
 | 
				
			||||||
 | 
					        public Alert Alert { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Alert
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@xmlns")]
 | 
				
			||||||
 | 
					        public string Xmlns { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("identifier")]
 | 
				
			||||||
 | 
					        public string Identifier { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("sender")]
 | 
				
			||||||
 | 
					        public string Sender { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("sent")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Sent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("status")]
 | 
				
			||||||
 | 
					        public string Status { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("msgType")]
 | 
				
			||||||
 | 
					        public string MsgType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("scope")]
 | 
				
			||||||
 | 
					        public string Scope { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("references")]
 | 
				
			||||||
 | 
					        public string References { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("info")]
 | 
				
			||||||
 | 
					        public Info[] Info { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("language")]
 | 
				
			||||||
 | 
					        public string Language { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("category")]
 | 
				
			||||||
 | 
					        public string Category { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("event")]
 | 
				
			||||||
 | 
					        public string Event { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("responseType")]
 | 
				
			||||||
 | 
					        public string ResponseType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("urgency")]
 | 
				
			||||||
 | 
					        public string Urgency { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("severity")]
 | 
				
			||||||
 | 
					        public string Severity { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("certainty")]
 | 
				
			||||||
 | 
					        public string Certainty { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("eventCode")]
 | 
				
			||||||
 | 
					        public EventCode EventCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("effective")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Effective { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("onset")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Onset { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("expires")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Expires { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("senderName")]
 | 
				
			||||||
 | 
					        public string SenderName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("headline")]
 | 
				
			||||||
 | 
					        public string Headline { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("description")]
 | 
				
			||||||
 | 
					        public string Description { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("web")]
 | 
				
			||||||
 | 
					        public Uri Web { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("parameter")]
 | 
				
			||||||
 | 
					        public EventCode[] Parameter { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("area")]
 | 
				
			||||||
 | 
					        public Area[] Area { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Area
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("areaDesc")]
 | 
				
			||||||
 | 
					        public string AreaDesc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("geocode")]
 | 
				
			||||||
 | 
					        public EventCode Geocode { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class EventCode
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("valueName")]
 | 
				
			||||||
 | 
					        public ValueName ValueName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("value")]
 | 
				
			||||||
 | 
					        public string Value { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Xml
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@version")]
 | 
				
			||||||
 | 
					        public string Version { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("@encoding")]
 | 
				
			||||||
 | 
					        public string Encoding { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public enum ValueName { AlertColor, AlertTitle, ProfileCapTwpEvent10, SeverityLevel, TaiwanGeocode103, WebsiteColor };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static class Serialize
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static class Converter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
 | 
				
			||||||
 | 
					            DateParseHandling = DateParseHandling.None,
 | 
				
			||||||
 | 
					            Converters =
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ValueNameConverter.Singleton,
 | 
				
			||||||
 | 
					                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ValueNameConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(ValueName) || t == typeof(ValueName?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case "Taiwan_Geocode_103":
 | 
				
			||||||
 | 
					                    return ValueName.TaiwanGeocode103;
 | 
				
			||||||
 | 
					                case "alert_color":
 | 
				
			||||||
 | 
					                    return ValueName.AlertColor;
 | 
				
			||||||
 | 
					                case "alert_title":
 | 
				
			||||||
 | 
					                    return ValueName.AlertTitle;
 | 
				
			||||||
 | 
					                case "profile:CAP-TWP:Event:1.0":
 | 
				
			||||||
 | 
					                    return ValueName.ProfileCapTwpEvent10;
 | 
				
			||||||
 | 
					                case "severity_level":
 | 
				
			||||||
 | 
					                    return ValueName.SeverityLevel;
 | 
				
			||||||
 | 
					                case "website_color":
 | 
				
			||||||
 | 
					                    return ValueName.WebsiteColor;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type ValueName");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (ValueName)untypedValue;
 | 
				
			||||||
 | 
					            switch (value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ValueName.TaiwanGeocode103:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "Taiwan_Geocode_103");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case ValueName.AlertColor:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "alert_color");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case ValueName.AlertTitle:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "alert_title");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case ValueName.ProfileCapTwpEvent10:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "profile:CAP-TWP:Event:1.0");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case ValueName.SeverityLevel:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "severity_level");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                case ValueName.WebsiteColor:
 | 
				
			||||||
 | 
					                    serializer.Serialize(writer, "website_color");
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot marshal type ValueName");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly ValueNameConverter Singleton = new ValueNameConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										81
									
								
								Backend/Services/Implement/SendEmailService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Backend/Services/Implement/SendEmailService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					using Microsoft.Extensions.Options;
 | 
				
			||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Net.Mail;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using BackendWorkerService.Services.Interface;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Implement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class SendEmailService : ISendEmailService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<SendEmailService> logger;
 | 
				
			||||||
 | 
					        private readonly IOptions<SMTPConfig> _options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private SMTPConfig smtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public SendEmailService(ILogger<SendEmailService> logger, IOptions<SMTPConfig> options)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            smtp = options.Value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Send(int id, List<string> recipientEmails, string subject, string content)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【SendEmailSMSService】【Email開始寄送】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                MailMessage MyMail = new MailMessage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                MyMail.SubjectEncoding = System.Text.Encoding.UTF8;//郵件標題編碼
 | 
				
			||||||
 | 
					                MyMail.BodyEncoding = System.Text.Encoding.UTF8; //郵件內容編碼
 | 
				
			||||||
 | 
					                MyMail.IsBodyHtml = true; //是否使用html格式
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var mailFrom = $"FIC IBMS管理系統通知 <{smtp.UserName}>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                MyMail.From = new System.Net.Mail.MailAddress(mailFrom); //寄件人
 | 
				
			||||||
 | 
					                foreach (var email in recipientEmails)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    MyMail.To.Add(email); //設定收件者Email
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                MyMail.Subject = subject; //主題
 | 
				
			||||||
 | 
					                MyMail.Body = content; //設定信件內容
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //讀取 SMTP Config
 | 
				
			||||||
 | 
					                SmtpClient MySMTP = new SmtpClient(smtp.Host, smtp.Port);
 | 
				
			||||||
 | 
					                MySMTP.EnableSsl = smtp.EnableSsl;
 | 
				
			||||||
 | 
					                MySMTP.Credentials = new System.Net.NetworkCredential(smtp.UserName, smtp.Password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    MySMTP.Send(MyMail);
 | 
				
			||||||
 | 
					                    MySMTP.Dispose();
 | 
				
			||||||
 | 
					                    MyMail.Dispose(); //釋放資源
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    logger.LogInformation("【SendEmailSMSService】【Email寄送成功】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch(Exception exception)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogError("【SendEmailSMSService】【Email寄送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                    logger.LogError("【SendEmailSMSService】【Email寄送失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【SendEmailSMSService】【Email寄送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                logger.LogError("【SendEmailSMSService】【Email寄送失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					                //return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								Backend/Services/Implement/SendLineNotifyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Backend/Services/Implement/SendLineNotifyService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					using BackendWorkerService.Services.Interface;
 | 
				
			||||||
 | 
					using Microsoft.    Extensions.Logging;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Implement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class SendLineNotifyService: ISendLineNotifyService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private readonly ILogger<SendLineNotifyService> logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public SendLineNotifyService(ILogger<SendLineNotifyService> logger)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Send(int id, string lineToken, string message)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogInformation("【SendLineNotifyService】【Line Notify開始發送】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                HttpWebRequest Postrequest = (HttpWebRequest)WebRequest.Create("https://notify-api.line.me/api/notify?message=" + message);
 | 
				
			||||||
 | 
					                Postrequest.Method = "POST";
 | 
				
			||||||
 | 
					                Postrequest.Headers.Add("Authorization", "Bearer " + lineToken);
 | 
				
			||||||
 | 
					                Postrequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					                HttpWebResponse response = (HttpWebResponse)Postrequest.GetResponse();
 | 
				
			||||||
 | 
					                var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					                var final = JObject.Parse(responseString);
 | 
				
			||||||
 | 
					                var get = final["status"].ToString();
 | 
				
			||||||
 | 
					                if (get != "200")
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogError("【SendLineNotifyService】【Line Notify發送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                    logger.LogError("【SendLineNotifyService】【Line Notify發送失敗】[失敗內容]:{0}", responseString);
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                logger.LogInformation("【SendLineNotifyService】【Line Notify發送成功】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【SendLineNotifyService】【Line Notify發送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                logger.LogError("【SendLineNotifyService】【Line Notify發送失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					                //return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								Backend/Services/Implement/SendSMSService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								Backend/Services/Implement/SendSMSService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					using Backend.Models;
 | 
				
			||||||
 | 
					using BackendWorkerService.Services.Interface;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Options;
 | 
				
			||||||
 | 
					using Newtonsoft.Json;
 | 
				
			||||||
 | 
					using Newtonsoft.Json.Linq;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Xml;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Implement
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    class SendSMSService : ISendSMSService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly ILogger<SendSMSService> logger;
 | 
				
			||||||
 | 
					        private readonly IOptions<SMSConfig> _options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private SMSConfig sms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public SendSMSService(ILogger<SendSMSService> logger, IOptions<SMSConfig> options)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.logger = logger;
 | 
				
			||||||
 | 
					            sms = options.Value;
 | 
				
			||||||
 | 
					            sms.Encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(sms.UserName + ":" + sms.Password));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Send(int id, string phone, string content)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【SendSMSService】【SMS開始寄送】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                //設定傳送的Request
 | 
				
			||||||
 | 
					                HttpWebRequest Postrequest = (HttpWebRequest)WebRequest.Create(sms.Api);
 | 
				
			||||||
 | 
					                Postrequest.Method = "POST";
 | 
				
			||||||
 | 
					                Postrequest.Headers.Add("Authorization", "Basic " + sms.Encoded);
 | 
				
			||||||
 | 
					                Postrequest.PreAuthenticate = true;
 | 
				
			||||||
 | 
					                using (var streamWriter = new StreamWriter(Postrequest.GetRequestStream()))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    string json = string.Format("<real val=\"{0},{1}\"/>", phone, content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    streamWriter.Write(json);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //設定回傳的Request
 | 
				
			||||||
 | 
					                HttpWebResponse response = (HttpWebResponse)Postrequest.GetResponse();
 | 
				
			||||||
 | 
					                var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 | 
				
			||||||
 | 
					                XmlDocument xmlDoc = new XmlDocument();
 | 
				
			||||||
 | 
					                xmlDoc.LoadXml(responseString);
 | 
				
			||||||
 | 
					                string jsonText = JsonConvert.SerializeXmlNode(xmlDoc);
 | 
				
			||||||
 | 
					                JObject resultVal = (JObject)JsonConvert.DeserializeObject(jsonText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (resultVal.ContainsKey("obj"))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var display_split = resultVal["obj"]["@display"].ToString().Split(' ');
 | 
				
			||||||
 | 
					                    var responseStatus = display_split[display_split.Length - 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (responseStatus == "{ok}")
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        logger.LogInformation("【SendSMSService】【SMS寄送成功】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                        return true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    logger.LogError("【SendSMSService】【SMS寄送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                    logger.LogError("【SendSMSService】【SMS寄送失敗】[失敗內容]:{0}", resultVal);
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception exception)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                logger.LogError("【SendSMSService】【SMS寄送失敗】[任務編號]:{0}", id);
 | 
				
			||||||
 | 
					                logger.LogError("【SendSMSService】【SMS寄送失敗】[Exception]:{0}", exception.ToString());
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
 | 
					                //return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										283
									
								
								Backend/Services/Implement/TyphoonApi.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								Backend/Services/Implement/TyphoonApi.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,283 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// <auto-generated />
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    using QuickType;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//    var welcome = Welcome.FromJson(jsonString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace TyphoonApi
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using System.Globalization;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json;
 | 
				
			||||||
 | 
					    using Newtonsoft.Json.Converters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("?xml")]
 | 
				
			||||||
 | 
					        public Xml Xml { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("alert")]
 | 
				
			||||||
 | 
					        public Alert Alert { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Alert
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@xmlns")]
 | 
				
			||||||
 | 
					        public string Xmlns { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("identifier")]
 | 
				
			||||||
 | 
					        public string Identifier { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("sender")]
 | 
				
			||||||
 | 
					        public string Sender { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("sent")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Sent { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("status")]
 | 
				
			||||||
 | 
					        public string Status { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("msgType")]
 | 
				
			||||||
 | 
					        public string MsgType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("scope")]
 | 
				
			||||||
 | 
					        public string Scope { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("references")]
 | 
				
			||||||
 | 
					        public string References { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("info")]
 | 
				
			||||||
 | 
					        public Info Info { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Info
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("language")]
 | 
				
			||||||
 | 
					        public string Language { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("category")]
 | 
				
			||||||
 | 
					        public string Category { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("event")]
 | 
				
			||||||
 | 
					        public string Event { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("responseType")]
 | 
				
			||||||
 | 
					        public string ResponseType { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("urgency")]
 | 
				
			||||||
 | 
					        public string Urgency { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("severity")]
 | 
				
			||||||
 | 
					        public string Severity { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("certainty")]
 | 
				
			||||||
 | 
					        public string Certainty { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("eventCode")]
 | 
				
			||||||
 | 
					        public EventCode EventCode { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("effective")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Effective { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("onset")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Onset { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("expires")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Expires { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("senderName")]
 | 
				
			||||||
 | 
					        public string SenderName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("headline")]
 | 
				
			||||||
 | 
					        public string Headline { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("description")]
 | 
				
			||||||
 | 
					        public Description Description { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("web")]
 | 
				
			||||||
 | 
					        public Uri Web { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("parameter")]
 | 
				
			||||||
 | 
					        public EventCode[] Parameter { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("area")]
 | 
				
			||||||
 | 
					        public Area[] Area { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Area
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("areaDesc")]
 | 
				
			||||||
 | 
					        public string AreaDesc { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("polygon")]
 | 
				
			||||||
 | 
					        public string Polygon { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Description
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("typhoon-info")]
 | 
				
			||||||
 | 
					        public TyphoonInfo TyphoonInfo { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("section")]
 | 
				
			||||||
 | 
					        public DescriptionSection[] Section { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class DescriptionSection
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@title")]
 | 
				
			||||||
 | 
					        public string Title { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("#text")]
 | 
				
			||||||
 | 
					        public string Text { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class TyphoonInfo
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("section")]
 | 
				
			||||||
 | 
					        public TyphoonInfoSection[] Section { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class TyphoonInfoSection
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@title")]
 | 
				
			||||||
 | 
					        public string Title { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("#text", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public string Text { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("typhoon_name", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public string TyphoonName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("cwb_typhoon_name", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public string CwbTyphoonName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("analysis", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Analysis Analysis { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("prediction", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Analysis Prediction { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Analysis
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("time")]
 | 
				
			||||||
 | 
					        public DateTimeOffset Time { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("position")]
 | 
				
			||||||
 | 
					        public string Position { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("max_winds")]
 | 
				
			||||||
 | 
					        public Gust MaxWinds { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("gust")]
 | 
				
			||||||
 | 
					        public Gust Gust { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("pressure")]
 | 
				
			||||||
 | 
					        public Gust Pressure { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("radius_of_15mps")]
 | 
				
			||||||
 | 
					        public Gust RadiusOf15Mps { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("scale", NullValueHandling = NullValueHandling.Ignore)]
 | 
				
			||||||
 | 
					        public Scale[] Scale { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Gust
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@unit")]
 | 
				
			||||||
 | 
					        public string Unit { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("#text")]
 | 
				
			||||||
 | 
					        [JsonConverter(typeof(ParseStringConverter))]
 | 
				
			||||||
 | 
					        public long Text { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Scale
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@lang")]
 | 
				
			||||||
 | 
					        public string Lang { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("#text")]
 | 
				
			||||||
 | 
					        public string Text { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class EventCode
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("valueName")]
 | 
				
			||||||
 | 
					        public string ValueName { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("value")]
 | 
				
			||||||
 | 
					        public string Value { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Xml
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [JsonProperty("@version")]
 | 
				
			||||||
 | 
					        public string Version { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [JsonProperty("@encoding")]
 | 
				
			||||||
 | 
					        public string Encoding { get; set; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public partial class Welcome
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static class Serialize
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static class Converter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
 | 
				
			||||||
 | 
					            DateParseHandling = DateParseHandling.None,
 | 
				
			||||||
 | 
					            Converters =
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal class ParseStringConverter : JsonConverter
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (reader.TokenType == JsonToken.Null) return null;
 | 
				
			||||||
 | 
					            var value = serializer.Deserialize<string>(reader);
 | 
				
			||||||
 | 
					            long l;
 | 
				
			||||||
 | 
					            if (Int64.TryParse(value, out l))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return l;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw new Exception("Cannot unmarshal type long");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (untypedValue == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                serializer.Serialize(writer, null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var value = (long)untypedValue;
 | 
				
			||||||
 | 
					            serializer.Serialize(writer, value.ToString());
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static readonly ParseStringConverter Singleton = new ParseStringConverter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								Backend/Services/Interface/ISendEmailService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Backend/Services/Interface/ISendEmailService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Interface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface ISendEmailService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bool Send(int id, List<string> recipientEmails, string subject, string content);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								Backend/Services/Interface/ISendLineNotifyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Backend/Services/Interface/ISendLineNotifyService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Interface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface ISendLineNotifyService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bool Send(int id, string lineToken, string message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								Backend/Services/Interface/ISendSMSService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Backend/Services/Interface/ISendSMSService.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BackendWorkerService.Services.Interface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public interface ISendSMSService
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        bool Send(int id, string phone, string message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
using Microsoft.AspNetCore.Builder;
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
using Microsoft.AspNetCore.Hosting;
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
using Microsoft.AspNetCore.HttpsPolicy;
 | 
					 | 
				
			||||||
using Microsoft.Extensions.Configuration;
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
using Microsoft.Extensions.DependencyInjection;
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
using Microsoft.Extensions.Hosting;
 | 
					using Microsoft.Extensions.Hosting;
 | 
				
			||||||
@ -16,15 +15,18 @@ using Repository.FrontendRepository.Interface;
 | 
				
			|||||||
using Repository.Models;
 | 
					using Repository.Models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using Backend.Jwt;
 | 
					using Backend.Jwt;
 | 
				
			||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
 | 
					using Microsoft.AspNetCore.Authentication.JwtBearer;
 | 
				
			||||||
using Microsoft.IdentityModel.Tokens;
 | 
					using Microsoft.IdentityModel.Tokens;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
using System.IdentityModel.Tokens.Jwt;
 | 
					using System.IdentityModel.Tokens.Jwt;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Backend.Quartz.Jobs;
 | 
				
			||||||
 | 
					using Backend.Quartz;
 | 
				
			||||||
 | 
					using Quartz.Impl;
 | 
				
			||||||
 | 
					using Quartz.Spi;
 | 
				
			||||||
 | 
					using Quartz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Backend
 | 
					namespace Backend
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -115,8 +117,16 @@ namespace Backend
 | 
				
			|||||||
            services.AddTransient<IDeviceManageRepository, DeviceManageRepository>();
 | 
					            services.AddTransient<IDeviceManageRepository, DeviceManageRepository>();
 | 
				
			||||||
            services.AddTransient<IDeviceImportRepository, DeviceImportRepository>();
 | 
					            services.AddTransient<IDeviceImportRepository, DeviceImportRepository>();
 | 
				
			||||||
            services.AddTransient<INiagaraDataSynchronizeRepository, NiagaraDataSynchronizeRepository>();
 | 
					            services.AddTransient<INiagaraDataSynchronizeRepository, NiagaraDataSynchronizeRepository>();
 | 
				
			||||||
 | 
					            services.AddTransient<IBackgroundServiceRepository, BackgroundServiceRepository>();
 | 
				
			||||||
 | 
					            services.AddTransient<IBackgroundServiceMsSqlRepository, BackgroundServiceMsSqlRepository>();
 | 
				
			||||||
            #endregion Repository ª`¤J
 | 
					            #endregion Repository ª`¤J
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #region 添加Quartz服務
 | 
				
			||||||
 | 
					            services.AddTransient<IJobFactory, SingletonJobFactory>();
 | 
				
			||||||
 | 
					            services.AddTransient<ISchedulerFactory, StdSchedulerFactory>();
 | 
				
			||||||
 | 
					            services.AddHostedService<QuartzHostedService>();
 | 
				
			||||||
 | 
					            #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #region JWT ª`¤J
 | 
					            #region JWT ª`¤J
 | 
				
			||||||
            services.AddTransient<IJwtHelpers, JwtHelpers>();
 | 
					            services.AddTransient<IJwtHelpers, JwtHelpers>();
 | 
				
			||||||
            services
 | 
					            services
 | 
				
			||||||
@ -153,6 +163,20 @@ namespace Backend
 | 
				
			|||||||
                });
 | 
					                });
 | 
				
			||||||
            #endregion JWT ª`¤J
 | 
					            #endregion JWT ª`¤J
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #region 電錶歸檔(設定每 天 執行一次)
 | 
				
			||||||
 | 
					            services.AddSingleton<ArchiveElectricMeterDayJob>();
 | 
				
			||||||
 | 
					            services.AddSingleton(
 | 
				
			||||||
 | 
					            new JobSchedule(jobType: typeof(ArchiveElectricMeterDayJob), cronExpression: Configuration.GetValue<string>("BackgroundServiceCron:ArchiveElectricMeterDayJob"))
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #region 定時取得氣象API
 | 
				
			||||||
 | 
					            services.AddSingleton<WeatherAPIJob>();
 | 
				
			||||||
 | 
					            services.AddSingleton(
 | 
				
			||||||
 | 
					            new JobSchedule(jobType: typeof(WeatherAPIJob), cronExpression: Configuration.GetValue<string>("BackgroundServiceCron:WeatherAPIJob"))
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            double loginExpireMinute = this.Configuration.GetValue<double>("LoginExpireMinute");
 | 
					            double loginExpireMinute = this.Configuration.GetValue<double>("LoginExpireMinute");
 | 
				
			||||||
            services.AddSession(options =>
 | 
					            services.AddSession(options =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,17 @@
 | 
				
			|||||||
    "SignKey": "TaipeiDome123456", //簽章//最少16字元
 | 
					    "SignKey": "TaipeiDome123456", //簽章//最少16字元
 | 
				
			||||||
    "JwtLifeSeconds": 3600
 | 
					    "JwtLifeSeconds": 3600
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  "LoggerPath": "C:\\inetpub\\Taipei_dome_background_service\\Logs",
 | 
				
			||||||
 | 
					  "BackgroundServiceCron": {
 | 
				
			||||||
 | 
					    "ExecutionBackgroundServicePlanJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "MessageNotificationJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "DataDeliveryJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "RegularUpdateDBTableJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "ParkingJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "ArchiveElectricMeterHourJob": "0 0 2 * * ?",
 | 
				
			||||||
 | 
					    "ArchiveElectricMeterDayJob": "0/5 * * * * ?",
 | 
				
			||||||
 | 
					    "WeatherAPIJob": "0/5 * * * * ?"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "DBConfig": {
 | 
					  "DBConfig": {
 | 
				
			||||||
    "MySqlDBConfig": {
 | 
					    "MySqlDBConfig": {
 | 
				
			||||||
      "Server": "FYlY+w0XDIz+jmF2rlZWJw==", //0.201
 | 
					      "Server": "FYlY+w0XDIz+jmF2rlZWJw==", //0.201
 | 
				
			||||||
@ -23,6 +34,13 @@
 | 
				
			|||||||
      //"Database": "iuaY0h0+TWkir44/eZLDqw==", //tpe_dome_office
 | 
					      //"Database": "iuaY0h0+TWkir44/eZLDqw==", //tpe_dome_office
 | 
				
			||||||
      "Root": "SzdxEgaJJ7tcTCrUl2zKsA==",
 | 
					      "Root": "SzdxEgaJJ7tcTCrUl2zKsA==",
 | 
				
			||||||
      "Password": "FVAPxztxpY4gJJKQ/se4bQ=="
 | 
					      "Password": "FVAPxztxpY4gJJKQ/se4bQ=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "MSSqlDBConfig": {
 | 
				
			||||||
 | 
					      "Server": "bJm+UAtbeaTjDmp/A5ep2w==", //0.130
 | 
				
			||||||
 | 
					      "Port": "S5cUXKnKOacFtFy9+0dtpw==",
 | 
				
			||||||
 | 
					      "Database": "VvfWH/59gQguY2eA2xBCug==", //taipei_dome 
 | 
				
			||||||
 | 
					      "Root": "sD8GZ9UPiIQGU6dU011/4A==",
 | 
				
			||||||
 | 
					      "Password": "0O24es2ZRF5uoJ4aU+YCdg=="
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //"MSSqlDBConfig": {
 | 
					    //"MSSqlDBConfig": {
 | 
				
			||||||
    //  "Server": "zp3Nilx0PISEEC4caZWqCg==", //172.16.220.250
 | 
					    //  "Server": "zp3Nilx0PISEEC4caZWqCg==", //172.16.220.250
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@
 | 
				
			|||||||
    "SignKey": "TaipeiDome123456", //簽章//最少16字元
 | 
					    "SignKey": "TaipeiDome123456", //簽章//最少16字元
 | 
				
			||||||
    "JwtLifeSeconds": 3600
 | 
					    "JwtLifeSeconds": 3600
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  "LoggerPath": "C:\\inetpub\\Taipei_dome_background_service\\Logs",
 | 
				
			||||||
  "DBConfig": {
 | 
					  "DBConfig": {
 | 
				
			||||||
    "MySqlDBConfig": {
 | 
					    "MySqlDBConfig": {
 | 
				
			||||||
      "Server": "FYlY+w0XDIz+jmF2rlZWJw==", //0.201
 | 
					      "Server": "FYlY+w0XDIz+jmF2rlZWJw==", //0.201
 | 
				
			||||||
@ -22,6 +23,13 @@
 | 
				
			|||||||
      //"Database": "iuaY0h0+TWkir44/eZLDqw==", //tpe_dome_office
 | 
					      //"Database": "iuaY0h0+TWkir44/eZLDqw==", //tpe_dome_office
 | 
				
			||||||
      "Root": "SzdxEgaJJ7tcTCrUl2zKsA==",
 | 
					      "Root": "SzdxEgaJJ7tcTCrUl2zKsA==",
 | 
				
			||||||
      "Password": "FVAPxztxpY4gJJKQ/se4bQ=="
 | 
					      "Password": "FVAPxztxpY4gJJKQ/se4bQ=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "MSSqlDBConfig": {
 | 
				
			||||||
 | 
					      "Server": "bJm+UAtbeaTjDmp/A5ep2w==", //0.130
 | 
				
			||||||
 | 
					      "Port": "S5cUXKnKOacFtFy9+0dtpw==",
 | 
				
			||||||
 | 
					      "Database": "VvfWH/59gQguY2eA2xBCug==", //taipei_dome 
 | 
				
			||||||
 | 
					      "Root": "sD8GZ9UPiIQGU6dU011/4A==",
 | 
				
			||||||
 | 
					      "Password": "0O24es2ZRF5uoJ4aU+YCdg=="
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //"MSSqlDBConfig": {
 | 
					    //"MSSqlDBConfig": {
 | 
				
			||||||
    //  "Server": "ueFp+VFb200lhh1Uctc97WH0/tX6tfXYU2v1oxCWuuM=",
 | 
					    //  "Server": "ueFp+VFb200lhh1Uctc97WH0/tX6tfXYU2v1oxCWuuM=",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										136
									
								
								Backend/root/PowerfulRain.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								Backend/root/PowerfulRain.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    <identifier>CWB-Weather_extremely-rain_202306011035001</identifier>
 | 
				
			||||||
 | 
					    <sender>weather@cwb.gov.tw</sender>
 | 
				
			||||||
 | 
					    <sent>2023-06-01T10:43:55+08:00</sent>
 | 
				
			||||||
 | 
					    <status>Actual</status>
 | 
				
			||||||
 | 
					    <msgType>Update</msgType>
 | 
				
			||||||
 | 
					    <scope>Public</scope>
 | 
				
			||||||
 | 
					    <references>weather@cwb.gov.tw,CWB-Weather_extremely-rain_202306010655001,2023-06-01T07:02:17+08:00 weather@cwb.gov.tw,CWB-Weather_extremely-rain_202306010345001,2023-06-01T03:56:19+08:00</references>
 | 
				
			||||||
 | 
					    <info>
 | 
				
			||||||
 | 
					        <language>zh-TW</language>
 | 
				
			||||||
 | 
					        <category>Met</category>
 | 
				
			||||||
 | 
					        <event>降雨</event>
 | 
				
			||||||
 | 
					        <responseType>Monitor</responseType>
 | 
				
			||||||
 | 
					        <urgency>Future</urgency>
 | 
				
			||||||
 | 
					        <severity>Moderate</severity>
 | 
				
			||||||
 | 
					        <certainty>Likely</certainty>
 | 
				
			||||||
 | 
					        <eventCode>
 | 
				
			||||||
 | 
					            <valueName>profile:CAP-TWP:Event:1.0</valueName>
 | 
				
			||||||
 | 
					            <value>rainfall</value>
 | 
				
			||||||
 | 
					        </eventCode>
 | 
				
			||||||
 | 
					        <effective>2023-06-01T10:35:00+08:00</effective>
 | 
				
			||||||
 | 
					        <onset>2023-06-01T10:36:00+08:00</onset>
 | 
				
			||||||
 | 
					        <expires>2023-06-01T23:00:00+08:00</expires>
 | 
				
			||||||
 | 
					        <senderName>中央氣象局</senderName>
 | 
				
			||||||
 | 
					        <headline>大雨特報</headline>
 | 
				
			||||||
 | 
					        <description>
 | 
				
			||||||
 | 
					颱風外圍環流影響,今(1)日新竹以北及宜蘭山區有局部大雨發生的機率,請注意瞬間大雨,山區請慎防坍方及落石。
 | 
				
			||||||
 | 
					        </description>
 | 
				
			||||||
 | 
					        <web>https://www.cwb.gov.tw/V8/C/P/Warning/FIFOWS.html</web>
 | 
				
			||||||
 | 
					        <parameter>
 | 
				
			||||||
 | 
					            <valueName>alert_title</valueName>
 | 
				
			||||||
 | 
					            <value>大雨特報</value>
 | 
				
			||||||
 | 
					        </parameter>
 | 
				
			||||||
 | 
					        <parameter>
 | 
				
			||||||
 | 
					            <valueName>severity_level</valueName>
 | 
				
			||||||
 | 
					            <value>大雨</value>
 | 
				
			||||||
 | 
					        </parameter>
 | 
				
			||||||
 | 
					        <parameter>
 | 
				
			||||||
 | 
					            <valueName>alert_color</valueName>
 | 
				
			||||||
 | 
					            <value>黃色</value>
 | 
				
			||||||
 | 
					        </parameter>
 | 
				
			||||||
 | 
					        <parameter>
 | 
				
			||||||
 | 
					            <valueName>website_color</valueName>
 | 
				
			||||||
 | 
					            <value>255,255,0</value>
 | 
				
			||||||
 | 
					        </parameter>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					  <area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣橫山鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000408</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣北埔鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000409</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>桃園市復興區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6801300</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>臺北市士林區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6301100</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市三峽區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6500900</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市石碇區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6501900</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>臺北市北投區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6301200</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣五峰鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000413</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣尖石鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000412</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市烏來區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6502900</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市坪林區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6502000</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市平溪區</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>6502400</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>宜蘭縣南澳鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000212</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area><area>
 | 
				
			||||||
 | 
					            <areaDesc>宜蘭縣大同鄉</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>1000211</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					    </info>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</alert>
 | 
				
			||||||
							
								
								
									
										197
									
								
								Backend/root/Typhoon.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								Backend/root/Typhoon.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    <identifier>CWB-Weather_typhoon-warning_202305311730001</identifier>
 | 
				
			||||||
 | 
					    <sender>weather@cwb.gov.tw</sender>
 | 
				
			||||||
 | 
					    <sent>2023-05-31T17:17:30+08:00</sent>
 | 
				
			||||||
 | 
					    <status>Actual</status>
 | 
				
			||||||
 | 
					    <msgType>Cancel</msgType>
 | 
				
			||||||
 | 
					    <scope>Public</scope>
 | 
				
			||||||
 | 
					    <references>weather@cwb.gov.tw,CWB-Weather_typhoon-warning_202305311430001,2023-05-31T14:22:23+08:00</references>
 | 
				
			||||||
 | 
					    <info>
 | 
				
			||||||
 | 
					        <language>zh-TW</language>
 | 
				
			||||||
 | 
					        <category>Met</category>
 | 
				
			||||||
 | 
					        <event>颱風</event>
 | 
				
			||||||
 | 
					        <urgency>Past</urgency>
 | 
				
			||||||
 | 
					        <severity>Minor</severity>
 | 
				
			||||||
 | 
					        <certainty>Observed</certainty>
 | 
				
			||||||
 | 
					        <eventCode>
 | 
				
			||||||
 | 
					            <valueName>profile:CAP-TWP:Event:1.0</valueName>
 | 
				
			||||||
 | 
					            <value>typhoon</value>
 | 
				
			||||||
 | 
					        </eventCode>
 | 
				
			||||||
 | 
					        <effective>2023-05-31T17:30:00+08:00</effective>
 | 
				
			||||||
 | 
					        <onset>2023-05-31T17:30:00+08:00</onset>
 | 
				
			||||||
 | 
					        <expires>2023-05-31T17:40:00+08:00</expires>
 | 
				
			||||||
 | 
					        <senderName>中央氣象局</senderName>
 | 
				
			||||||
 | 
					        <headline>解除颱風警報</headline>
 | 
				
			||||||
 | 
					        <description>
 | 
				
			||||||
 | 
					[颱風動態]
 | 
				
			||||||
 | 
					根據最新資料顯示,第2號颱風暴風半徑略為縮小,中心目前在鵝鑾鼻東北東方海面,向北北東轉東北移動,對巴士海峽及臺灣東半部近海威脅已解除。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[注意事項]
 | 
				
			||||||
 | 
					*巴士海峽及臺灣附近各海面風浪明顯偏大;基隆北海岸、南部、東半部(含蘭嶼、綠島)、恆春半島沿海及澎湖、馬祖易有長浪發生,尤其東半部(含蘭嶼、綠島)、基隆北海岸、恆春半島沿海易有4至5米浪高,請避免前往海邊活動。*陸上強風特報:今(31)日臺南至苗栗沿海空曠地區及澎湖、蘭嶼、綠島易有9至10級強陣風,新竹以北、基隆北海岸、東半部沿海空曠地區、臺南至苗栗地區、恆春半島、金門、馬祖亦有較強陣風,請特別注意。*30日0時至31日17時出現較大累積雨量如下:宜蘭縣翠峰湖334.5毫米,臺中市南湖圈谷257.0毫米。*本警報單之颱風半徑為平均半徑,第2號颱風之7級風暴風半徑近似正圓,平均半徑約為280公里。颱風詳細特性請參考本局颱輔助說明(https://www.cwb.gov.tw/Data/typhoon/TY_PDF.pdf)。*此為第2號颱風警報最後一次報告。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </description>
 | 
				
			||||||
 | 
					        <instruction></instruction>
 | 
				
			||||||
 | 
					        <web>https://www.cwb.gov.tw/V8/C/P/Warning/FIFOWS.html</web>
 | 
				
			||||||
 | 
					        <parameter>
 | 
				
			||||||
 | 
					            <valueName>alert_title</valueName>
 | 
				
			||||||
 | 
					            <value>颱風警報</value>
 | 
				
			||||||
 | 
					        </parameter>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>基隆市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10017</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺北市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>63</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>新北市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>65</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>桃園市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>68</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10018</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10004</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>苗栗縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10005</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺中市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>66</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>彰化縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10007</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>雲林縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10009</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>南投縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10008</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>嘉義縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10010</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>嘉義市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10020</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺南市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>67</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>高雄市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>64</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>屏東縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10013</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>宜蘭縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10002</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>花蓮縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10015</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺東縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10014</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>澎湖縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10016</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>金門縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>09020</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>連江縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>09007</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					    </info>
 | 
				
			||||||
 | 
					</alert>
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,64 +1,197 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
 | 
					<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    <identifier>CWB-Weather_typhoon-warning_202305311430001</identifier>
 | 
					    <identifier>CWB-Weather_typhoon-warning_202305311730001</identifier>
 | 
				
			||||||
    <sender>weather@cwb.gov.tw</sender>
 | 
					    <sender>weather@cwb.gov.tw</sender>
 | 
				
			||||||
    <sent>2023-05-31T14:22:22+08:00</sent>
 | 
					    <sent>2023-05-31T17:17:30+08:00</sent>
 | 
				
			||||||
    <status>Actual</status>
 | 
					    <status>Actual</status>
 | 
				
			||||||
    <msgType>Update</msgType>
 | 
					    <msgType>Cancel</msgType>
 | 
				
			||||||
    <scope>Public</scope>
 | 
					    <scope>Public</scope>
 | 
				
			||||||
    <references>weather@cwb.gov.tw,CWB-Weather_typhoon-warning_202305311130001,2023-05-31T11:24:11+08:00</references>
 | 
					    <references>weather@cwb.gov.tw,CWB-Weather_typhoon-warning_202305311430001,2023-05-31T14:22:23+08:00</references>
 | 
				
			||||||
    <info>
 | 
					    <info>
 | 
				
			||||||
        <language>zh-TW</language>
 | 
					        <language>zh-TW</language>
 | 
				
			||||||
        <category>Met</category>
 | 
					        <category>Met</category>
 | 
				
			||||||
        <event>颱風</event>
 | 
					        <event>颱風</event>
 | 
				
			||||||
        <responseType>Monitor</responseType>
 | 
					        <urgency>Past</urgency>
 | 
				
			||||||
        <urgency>Future</urgency>
 | 
					        <severity>Minor</severity>
 | 
				
			||||||
        <severity>Moderate</severity>
 | 
					        <certainty>Observed</certainty>
 | 
				
			||||||
        <certainty>Likely</certainty>
 | 
					 | 
				
			||||||
        <eventCode>
 | 
					        <eventCode>
 | 
				
			||||||
            <valueName>profile:CAP-TWP:Event:1.0</valueName>
 | 
					            <valueName>profile:CAP-TWP:Event:1.0</valueName>
 | 
				
			||||||
            <value>typhoon</value>
 | 
					            <value>typhoon</value>
 | 
				
			||||||
        </eventCode>
 | 
					        </eventCode>
 | 
				
			||||||
        <effective>2023-05-31T14:30:00+08:00</effective>
 | 
					        <effective>2023-05-31T17:30:00+08:00</effective>
 | 
				
			||||||
        <onset>2023-05-31T14:30:00+08:00</onset>
 | 
					        <onset>2023-05-31T17:30:00+08:00</onset>
 | 
				
			||||||
        <expires>2023-05-31T18:30:00+08:00</expires>
 | 
					        <expires>2023-05-31T17:40:00+08:00</expires>
 | 
				
			||||||
        <senderName>中央氣象局</senderName>
 | 
					        <senderName>中央氣象局</senderName>
 | 
				
			||||||
        <headline>海上颱風警報</headline>
 | 
					        <headline>解除颱風警報</headline>
 | 
				
			||||||
        <description>
 | 
					        <description>
 | 
				
			||||||
<typhoon-info><section title="警報報數">15</section><section title="警報類別">SEA</section><section title="颱風編號">2</section><section title="颱風資訊"><typhoon_name>MAWAR</typhoon_name><cwb_typhoon_name>瑪娃</cwb_typhoon_name><analysis><time>2023-05-31T06:00:00+00:00</time><position>22.20,125.20</position><max_winds unit="m/s">33</max_winds><gust unit="m/s">43</gust><pressure unit="hPa">970</pressure><radius_of_15mps unit="km">300</radius_of_15mps><scale lang="zh-TW">中度颱風</scale><scale lang="en">TYPHOON</scale></analysis><prediction><time>2023-06-01T06:00:00+00:00</time><position>24.80,126.20</position><max_winds unit="m/s">30</max_winds><gust unit="m/s">38</gust><pressure unit="hPa">975</pressure><radius_of_15mps unit="km">250</radius_of_15mps></prediction></section></typhoon-info><section title="命名與位置">中度颱風 瑪娃(國際命名 MAWAR)31日14時的中心位置在北緯 22.2 度,東經 125.2 度,即在鵝鑾鼻的東方約 440 公里之海面上。</section><section title="強度與半徑">中心氣壓 970 百帕,近中心最大風速每秒 33 公尺(約每小時 119 公里),相當於 12 級風,瞬間最大陣風每秒 43 公尺(約每小時 155 公里),相當於 14 級風,七級風暴風半徑 300 公里,十級風暴風半徑 100 公里。</section><section title="移速與預測">以每小時14公里速度,向北北東進行,預測1日14時的中心位置在北緯 24.8 度,東經 126.2 度,即在宜蘭的東方約 450 公里之海面上。</section><section title="颱風動態">根據最新資料顯示,第2號颱風中心目前在鵝鑾鼻東方海面,向北北東移動,其暴風圈正掠過臺灣東南部近海,對巴士海峽及臺灣東半部海面構成威脅。預計此颱風未來強度有稍減弱且暴風圈亦有縮小的趨勢。</section><section title="警戒區域及事項">巴士海峽、臺灣東南部海面(含蘭嶼、綠島)、臺灣東北部海面航行及作業船隻應嚴加戒備。</section><section title="豪雨特報">颱風外圍環流影響,易有短延時強降雨,今(31)日宜蘭縣、新北市及臺中市山區有局部大雨或豪雨發生,大臺北、桃園、新竹、花蓮地區及南投山區(奇萊山區)有局部大雨發生的機率,請注意強陣風,山區請注意落石及坍方。</section><section title="注意事項">*巴士海峽及臺灣附近各海面風浪明顯偏大;基隆北海岸、南部、東半部(含蘭嶼、綠島)、恆春半島沿海及澎湖、馬祖易有長浪發生,尤其東半部(含蘭嶼、綠島)、基隆北海岸、恆春半島沿海易有4至5米浪高,請避免前往海邊活動。*陸上強風特報:今(31)日臺南至苗栗沿海空曠地區及澎湖、蘭嶼、綠島易有9至10級強陣風,新竹以北、基隆北海岸、東半部沿海空曠地區、臺南至苗栗地區、恆春半島、金門、馬祖亦有較強陣風,請特別注意。*颱風外圍沉降影響,今(31日)白天臺南、高雄、屏東及金門有局部36度以上高溫出現的機率,請注意。*30日0時至31日14時出現較大累積雨量如下:宜蘭縣翠峰湖316.0毫米,臺中市南湖圈谷232.0毫米。*本警報單之颱風半徑為平均半徑,第2號颱風之7級風暴風半徑近似正圓,平均半徑約為300公里。颱風詳細特性請參考本局颱輔助說明(https://www.cwb.gov.tw/Data/typhoon/TY_PDF.pdf)。*若此颱風行徑無特殊變化,本局預計於今(31)日17時30分解除海上颱風警報。</section>
 | 
					[颱風動態]
 | 
				
			||||||
 | 
					根據最新資料顯示,第2號颱風暴風半徑略為縮小,中心目前在鵝鑾鼻東北東方海面,向北北東轉東北移動,對巴士海峽及臺灣東半部近海威脅已解除。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[注意事項]
 | 
				
			||||||
 | 
					*巴士海峽及臺灣附近各海面風浪明顯偏大;基隆北海岸、南部、東半部(含蘭嶼、綠島)、恆春半島沿海及澎湖、馬祖易有長浪發生,尤其東半部(含蘭嶼、綠島)、基隆北海岸、恆春半島沿海易有4至5米浪高,請避免前往海邊活動。*陸上強風特報:今(31)日臺南至苗栗沿海空曠地區及澎湖、蘭嶼、綠島易有9至10級強陣風,新竹以北、基隆北海岸、東半部沿海空曠地區、臺南至苗栗地區、恆春半島、金門、馬祖亦有較強陣風,請特別注意。*30日0時至31日17時出現較大累積雨量如下:宜蘭縣翠峰湖334.5毫米,臺中市南湖圈谷257.0毫米。*本警報單之颱風半徑為平均半徑,第2號颱風之7級風暴風半徑近似正圓,平均半徑約為280公里。颱風詳細特性請參考本局颱輔助說明(https://www.cwb.gov.tw/Data/typhoon/TY_PDF.pdf)。*此為第2號颱風警報最後一次報告。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </description>
 | 
					        </description>
 | 
				
			||||||
 | 
					        <instruction></instruction>
 | 
				
			||||||
        <web>https://www.cwb.gov.tw/V8/C/P/Warning/FIFOWS.html</web>
 | 
					        <web>https://www.cwb.gov.tw/V8/C/P/Warning/FIFOWS.html</web>
 | 
				
			||||||
        <parameter>
 | 
					        <parameter>
 | 
				
			||||||
            <valueName>alert_title</valueName>
 | 
					            <valueName>alert_title</valueName>
 | 
				
			||||||
            <value>颱風警報</value>
 | 
					            <value>颱風警報</value>
 | 
				
			||||||
        </parameter>
 | 
					        </parameter>
 | 
				
			||||||
        <parameter>
 | 
					 | 
				
			||||||
            <valueName>severity_level</valueName>
 | 
					 | 
				
			||||||
            <value>海上颱風警報</value>
 | 
					 | 
				
			||||||
        </parameter>
 | 
					 | 
				
			||||||
        <parameter>
 | 
					 | 
				
			||||||
            <valueName>alert_color</valueName>
 | 
					 | 
				
			||||||
            <value>橙色</value>
 | 
					 | 
				
			||||||
        </parameter>
 | 
					 | 
				
			||||||
        <parameter>
 | 
					 | 
				
			||||||
            <valueName>website_color</valueName>
 | 
					 | 
				
			||||||
            <value>255,0,0</value>
 | 
					 | 
				
			||||||
        </parameter>
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
        <area>
 | 
					        <area>
 | 
				
			||||||
            <areaDesc>巴士海峽東部</areaDesc>
 | 
					            <areaDesc>基隆市</areaDesc>
 | 
				
			||||||
            <polygon>20.00,121.50 20.00,121.00 20.50,121.00 21.00,121.00 21.50,121.00 22.00,121.00 22.00,121.50 22.00,122.00 22.00,122.50 22.00,123.00 21.50,123.00 21.00,123.00 20.50,123.00 20.00,123.00 20.00,122.50 20.00,122.00 20.00,121.50</polygon>
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10017</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
        </area>
 | 
					        </area>
 | 
				
			||||||
        <area>
 | 
					        <area>
 | 
				
			||||||
            <areaDesc>臺灣東北部海面</areaDesc>
 | 
					            <areaDesc>臺北市</areaDesc>
 | 
				
			||||||
            <polygon>23.50,122.00 23.50,121.50 23.70,121.54 23.90,121.60 23.98,121.61 24.00,121.61 24.03,121.62 24.04,121.61 24.06,121.60 24.08,121.61 24.18,121.66 24.21,121.68 24.29,121.74 24.29,121.75 24.30,121.77 24.33,121.76 24.41,121.78 24.43,121.78 24.45,121.80 24.46,121.80 24.46,121.82 24.47,121.83 24.48,121.84 24.50,121.85 24.53,121.85 24.56,121.85 24.59,121.85 24.61,121.84 24.61,121.83 24.62,121.82 24.64,121.82 24.75,121.80 24.76,121.80 24.79,121.81 24.84,121.81 24.85,121.82 24.87,121.83 24.93,121.88 24.96,121.91 24.98,121.95 24.99,121.97 24.99,121.98 25.00,121.99 25.00,122.00 25.00,122.00 25.00,122.50 25.00,123.00 24.50,123.00 24.00,123.00 23.50,123.00 23.50,122.50 23.50,122.00</polygon>
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>63</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
        </area>
 | 
					        </area>
 | 
				
			||||||
        <area>
 | 
					        <area>
 | 
				
			||||||
            <areaDesc>臺灣東南部海面</areaDesc>
 | 
					            <areaDesc>新北市</areaDesc>
 | 
				
			||||||
            <polygon>22.00,121.50 22.00,121.00 22.00,120.86 22.04,120.88 22.10,120.88 22.23,120.88 22.28,120.87 22.29,120.87 22.32,120.87 22.34,120.88 22.50,120.94 22.54,120.96 22.57,120.97 22.61,121.00 22.64,121.01 22.66,121.03 22.71,121.08 22.72,121.11 22.72,121.12 22.73,121.13 22.74,121.14 22.76,121.17 22.90,121.26 23.00,121.31 23.09,121.36 23.33,121.45 23.40,121.47 23.41,121.48 23.42,121.48 23.49,121.50 23.50,121.50 23.50,122.00 23.50,122.50 23.50,123.00 23.00,123.00 22.50,123.00 22.00,123.00 22.00,122.50 22.00,122.00 22.00,121.50</polygon>
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>65</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>桃園市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>68</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10018</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>新竹縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10004</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>苗栗縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10005</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺中市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>66</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>彰化縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10007</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>雲林縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10009</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>南投縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10008</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>嘉義縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10010</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>嘉義市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10020</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺南市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>67</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>高雄市</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>64</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>屏東縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10013</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>宜蘭縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10002</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>花蓮縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10015</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>臺東縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10014</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>澎湖縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>10016</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>金門縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>09020</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
 | 
					        </area>
 | 
				
			||||||
 | 
					        <area>
 | 
				
			||||||
 | 
					            <areaDesc>連江縣</areaDesc>
 | 
				
			||||||
 | 
					            <geocode>
 | 
				
			||||||
 | 
					                <valueName>Taiwan_Geocode_103</valueName>
 | 
				
			||||||
 | 
					                <value>09007</value>
 | 
				
			||||||
 | 
					            </geocode>
 | 
				
			||||||
        </area>
 | 
					        </area>
 | 
				
			||||||
    </info>
 | 
					    </info>
 | 
				
			||||||
 | 
					 | 
				
			||||||
</alert>
 | 
					</alert>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user