├── .gitignore ├── LICENSE ├── QuartzNetAPI ├── Host.Tests │ ├── Host.Tests.csproj │ └── HttpHelperTests.cs ├── Host │ ├── Attributes │ │ └── NoLoginAttribute.cs │ ├── Common │ │ ├── AppConfig.cs │ │ ├── AppSetting.cs │ │ ├── BaseResult.cs │ │ ├── Constant.cs │ │ ├── EncryptDecryptExtension.cs │ │ ├── Enums │ │ │ ├── ConnectionMethod.cs │ │ │ ├── JobTypeEnum.cs │ │ │ ├── MailMessageEnum.cs │ │ │ ├── RequestTypeEnum.cs │ │ │ └── TriggerTypeEnum.cs │ │ ├── FileConfig.cs │ │ ├── HttpHelper.cs │ │ ├── MailHelper.cs │ │ └── StringExtension.cs │ ├── Controllers │ │ ├── JobController.cs │ │ └── SetingController.cs │ ├── Dockerfile │ ├── Dockerfile[树莓派] │ ├── Entity │ │ ├── JobBriefInfoEntity.cs │ │ ├── JobInfoEntity.cs │ │ ├── LoginInfoEntity.cs │ │ ├── LoginInfoOutput.cs │ │ ├── MailEntity.cs │ │ ├── ModifyJobInput.cs │ │ ├── MqttOptionsEntity.cs │ │ ├── RabbitOptionsEntity.cs │ │ ├── RefreshIntervalEntity.cs │ │ ├── ScheduleEntity.cs │ │ └── UpdateLoginInfoEntity.cs │ ├── File │ │ ├── RefreshInterval.json │ │ └── rabbitmq.json │ ├── Filters │ │ └── AuthorizationFilter.cs │ ├── Host.csproj │ ├── Host.csproj.user │ ├── IJobs │ │ ├── HttpJob.cs │ │ ├── JobBase.cs │ │ ├── MailJob.cs │ │ ├── Model │ │ │ ├── LogMailModel.cs │ │ │ ├── LogModel.cs │ │ │ ├── LogMqttModel.cs │ │ │ ├── LogRabbitModel.cs │ │ │ └── LogUrlModel.cs │ │ ├── MqttJob.cs │ │ └── RabbitJob.cs │ ├── Managers │ │ ├── MqttManager.cs │ │ ├── RabbitMQManager.cs │ │ └── SchedulerCenter.cs │ ├── Model │ │ ├── HttpResultModel.cs │ │ ├── LogInfoModel.cs │ │ └── SendMailModel.cs │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ ├── FolderProfile.pubxml │ │ │ └── FolderProfile.pubxml.user │ │ └── launchSettings.json │ ├── Repositories │ │ ├── IRepositorie.cs │ │ ├── OracleDynamicParameters.cs │ │ ├── RepositorieFactory.cs │ │ ├── RepositorieMySql.cs │ │ ├── RepositorieOracle.cs │ │ ├── RepositoriePostgreSQL.cs │ │ ├── RepositorieSQLite.cs │ │ └── RepositorieSqlServer.cs │ ├── ScheduleManage.cs │ ├── Services │ │ └── HostedService.cs │ ├── Startup.cs │ ├── Tables │ │ ├── tables_firebird.sql │ │ ├── tables_mysql_innodb.sql │ │ ├── tables_oracle.sql │ │ ├── tables_postgres.sql │ │ ├── tables_sqlServer.sql │ │ ├── tables_sqlServerMOT.sql │ │ └── tables_sqlite.sql │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── 1-es2015.f3b9d43ee6db9fa820da.js │ │ ├── 1-es5.f3b9d43ee6db9fa820da.js │ │ ├── 3rdpartylicenses.txt │ │ ├── 6-es2015.a4e363a7248c7daffe8a.js │ │ ├── 6-es5.a4e363a7248c7daffe8a.js │ │ ├── 7-es2015.bfb7deef134855a4f9fd.js │ │ ├── 7-es5.bfb7deef134855a4f9fd.js │ │ ├── 8-es2015.a1b00527ed656e5e5a76.js │ │ ├── 8-es5.a1b00527ed656e5e5a76.js │ │ ├── 9-es2015.8365ef5288043f903909.js │ │ ├── 9-es5.8365ef5288043f903909.js │ │ ├── assets │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── zh.json │ │ └── images │ │ │ ├── yanjing1.png │ │ │ └── yanjing2.png │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main-es2015.d5ed1f222b0ffea87f16.js │ │ ├── main-es2015.d5ed1f222b0ffea87f16.js.LICENSE.txt │ │ ├── main-es5.d5ed1f222b0ffea87f16.js │ │ ├── polyfills-es2015.6f19846b4ef18698dc55.js │ │ ├── polyfills-es2015.6f19846b4ef18698dc55.js.LICENSE.txt │ │ ├── polyfills-es5-es2015.06082d8ddd1aae402438.js.LICENSE.txt │ │ ├── polyfills-es5.06082d8ddd1aae402438.js │ │ ├── runtime-es2015.d1d4fa10751b40a173bf.js │ │ ├── runtime-es5.d1d4fa10751b40a173bf.js │ │ └── styles.01dbed4115a46d357332.css ├── QuartzNetUI.sln └── 备忘.txt ├── QuartzNetWeb ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── browserslist ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── protractor.conf.js ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── explain │ │ │ ├── explain-routing.module.ts │ │ │ ├── explain.module.spec.ts │ │ │ ├── explain.module.ts │ │ │ └── explain │ │ │ │ ├── explain.component.css │ │ │ │ ├── explain.component.html │ │ │ │ ├── explain.component.spec.ts │ │ │ │ └── explain.component.ts │ │ ├── layout │ │ │ ├── layout-routing.module.ts │ │ │ ├── layout.module.ts │ │ │ └── layout │ │ │ │ ├── layout.component.css │ │ │ │ ├── layout.component.html │ │ │ │ ├── layout.component.spec.ts │ │ │ │ └── layout.component.ts │ │ ├── login │ │ │ ├── login.component.css │ │ │ ├── login.component.html │ │ │ ├── login.component.spec.ts │ │ │ └── login.component.ts │ │ ├── seting │ │ │ ├── seting-routing.module.ts │ │ │ ├── seting.module.ts │ │ │ └── seting │ │ │ │ ├── seting.component.css │ │ │ │ ├── seting.component.html │ │ │ │ ├── seting.component.spec.ts │ │ │ │ └── seting.component.ts │ │ └── task-list │ │ │ ├── task-list-routing.module.ts │ │ │ ├── task-list.module.ts │ │ │ └── task-list │ │ │ ├── task-list.component.css │ │ │ ├── task-list.component.html │ │ │ ├── task-list.component.spec.ts │ │ │ └── task-list.component.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── zh.json │ │ └── images │ │ │ ├── yanjing1.png │ │ │ └── yanjing2.png │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── shared │ │ ├── myhttp.ts │ │ └── util.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json ├── README.md └── 注意.md /.gitignore: -------------------------------------------------------------------------------- 1 | /QuartzNetAPI/Host/File/logs 2 | /QuartzNetAPI/Host/File/sqliteScheduler.db 3 | /QuartzNetAPI/Host/bin 4 | /QuartzNetAPI/Host/obj 5 | /QuartzNetAPI/Host.Tests/obj 6 | /QuartzNetAPI/Host.Tests/bin 7 | /QuartzNetAPI/.vs 8 | /QuartzNetAPI/Host/File/Mail.txt 9 | /QuartzNetAPI/Host/RaspberryPi 10 | /QuartzNetWeb/.vscode 11 | /QuartzNetAPI/Host/File/sqliteScheduler.db-journal 12 | /QuartzNetAPI/Host/File/LoginPassword.json 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 农码一生 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host.Tests/Host.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host.Tests/HttpHelperTests.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetAPI/Host.Tests/HttpHelperTests.cs -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Attributes/NoLoginAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Host.Attributes 4 | { 5 | /// 6 | /// 标记了此特性的方法,不需要进行登录和授权认证 7 | /// 8 | public class NoLoginAttribute : Attribute 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/AppConfig.cs: -------------------------------------------------------------------------------- 1 | using Talk.Extensions; 2 | 3 | namespace Host.Common 4 | { 5 | public static class AppConfig 6 | { 7 | public static string DbProviderName => ConfigurationManager.GetTryConfig("Quartz:dbProviderName"); 8 | public static string ConnectionString => ConfigurationManager.GetTryConfig("Quartz:connectionString"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/AppSetting.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Serialization; 3 | 4 | namespace Host.Common 5 | { 6 | public class AppSetting 7 | { 8 | /// 9 | /// 小驼峰命名 10 | /// 11 | public static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings 12 | { 13 | ContractResolver = new CamelCasePropertyNamesContractResolver() 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/BaseResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host 7 | { 8 | public class BaseResult 9 | { 10 | public int Code { get; set; } = 200; 11 | public string Msg { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Constant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Common 7 | { 8 | public class Constant 9 | { 10 | /// 11 | /// 请求url RequestUrl 12 | /// 13 | public const string REQUESTURL = "RequestUrl"; 14 | /// 15 | /// 请求参数 RequestParameters 16 | /// 17 | public const string REQUESTPARAMETERS = "RequestParameters"; 18 | /// 19 | /// Headers(可以包含:Authorization授权认证) 20 | /// 21 | public const string HEADERS = "Headers"; 22 | /// 23 | /// 是否发送邮件 24 | /// 25 | public const string MAILMESSAGE = "MailMessage"; 26 | /// 27 | /// 请求类型 RequestType 28 | /// 29 | public const string REQUESTTYPE = "RequestType"; 30 | /// 31 | /// 日志 LogList 32 | /// 33 | public const string LOGLIST = "LogList"; 34 | /// 35 | /// 异常 Exception 36 | /// 37 | public const string EXCEPTION = "Exception"; 38 | /// 39 | /// 执行次数 40 | /// 41 | public const string RUNNUMBER = "RunNumber"; 42 | 43 | public const string MailTitle = "MailTitle"; 44 | public const string MailContent = "MailContent"; 45 | public const string MailTo = "MailTo"; 46 | 47 | public const string JobTypeEnum = "JobTypeEnum"; 48 | 49 | public const string EndAt = "EndAt"; 50 | 51 | public const string ClientID = "ClientID"; 52 | public const string Host = "Host"; 53 | public const string Password = "Password"; 54 | public const string Port = "Port"; 55 | public const string UserName = "UserName"; 56 | 57 | public static string Topic = "Topic"; 58 | public static string Payload = "Payload"; 59 | 60 | public static string RabbitQueue = "RabbitQueue"; 61 | public static string RabbitBody = "RabbitBody"; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/EncryptDecryptExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Text; 4 | using Talk.Extensions; 5 | 6 | namespace Host.Common 7 | { 8 | public static class EncryptDecryptExtension 9 | { 10 | 11 | //可在配置文件配置自己的DES3Key - 必须16位 12 | private static readonly string des3key = ConfigurationManager.GetTryConfig("DES3Key", "73495773n~@^v&B6"); 13 | 14 | /// 15 | /// 加密 16 | /// 17 | /// 18 | /// 19 | public static string DES3Encrypt(this string data) 20 | { 21 | byte[] inputArray = Encoding.UTF8.GetBytes(data); 22 | var tripleDES = TripleDES.Create(); 23 | var byteKey = Encoding.UTF8.GetBytes(des3key); 24 | byte[] allKey = new byte[24]; 25 | Buffer.BlockCopy(byteKey, 0, allKey, 0, 16); 26 | Buffer.BlockCopy(byteKey, 0, allKey, 16, 8); 27 | tripleDES.Key = allKey; 28 | tripleDES.Mode = CipherMode.ECB; 29 | tripleDES.Padding = PaddingMode.PKCS7; 30 | ICryptoTransform cTransform = tripleDES.CreateEncryptor(); 31 | byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); 32 | return Convert.ToBase64String(resultArray, 0, resultArray.Length); 33 | } 34 | 35 | /// 36 | /// 解密 37 | /// 38 | /// 39 | /// 40 | /// 41 | public static string DES3Decrypt(this string data) 42 | { 43 | byte[] inputArray = Convert.FromBase64String(data); 44 | var tripleDES = TripleDES.Create(); 45 | var byteKey = Encoding.UTF8.GetBytes(des3key); 46 | byte[] allKey = new byte[24]; 47 | Buffer.BlockCopy(byteKey, 0, allKey, 0, 16); 48 | Buffer.BlockCopy(byteKey, 0, allKey, 16, 8); 49 | tripleDES.Key = allKey; 50 | tripleDES.Mode = CipherMode.ECB; 51 | tripleDES.Padding = PaddingMode.PKCS7; 52 | ICryptoTransform cTransform = tripleDES.CreateDecryptor(); 53 | byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); 54 | return Encoding.UTF8.GetString(resultArray); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Enums/ConnectionMethod.cs: -------------------------------------------------------------------------------- 1 | namespace Host.Common.Enums 2 | { 3 | public enum ConnectionMethod 4 | { 5 | None = 0, 6 | TCP = 1, 7 | TCP_SSL = 2, 8 | WS = 3, 9 | WSS = 4, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Enums/JobTypeEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Host.Common.Enums 2 | { 3 | public enum JobTypeEnum 4 | { 5 | None = 0, 6 | Url = 1, 7 | Emial = 2, 8 | Mqtt = 3, 9 | RabbitMQ = 4, 10 | Hotreload = 5, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Enums/MailMessageEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Host.Common 2 | { 3 | public enum MailMessageEnum 4 | { 5 | None = 0, 6 | Err = 1, 7 | All = 2 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Enums/RequestTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host 7 | { 8 | public enum RequestTypeEnum 9 | { 10 | None = 0, 11 | Get = 1, 12 | Post = 2, 13 | Put = 4, 14 | Delete = 8 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/Enums/TriggerTypeEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Common 7 | { 8 | public enum TriggerTypeEnum 9 | { 10 | None = 0, 11 | Cron = 1, 12 | Simple = 2, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/FileConfig.cs: -------------------------------------------------------------------------------- 1 | using Host.Entity; 2 | using Newtonsoft.Json; 3 | using System.Threading.Tasks; 4 | 5 | namespace Host.Common 6 | { 7 | public static class FileConfig 8 | { 9 | private static string filePath = "File/Mail.txt"; 10 | 11 | private static string mqttFilePath = "File/mqtt.json"; 12 | private static string rabbitFilePath = "File/rabbitmq.json"; 13 | 14 | private static MailEntity mailData = null; 15 | public static async Task GetMailInfoAsync() 16 | { 17 | if (mailData == null) 18 | { 19 | if (!System.IO.File.Exists(filePath)) return new MailEntity(); 20 | var mail = await System.IO.File.ReadAllTextAsync(filePath); 21 | mailData = JsonConvert.DeserializeObject(mail); 22 | } 23 | //深度复制,调用方修改。 24 | return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(mailData)); 25 | } 26 | 27 | public static async Task SaveMailInfoAsync(MailEntity mailEntity) 28 | { 29 | mailData = mailEntity; 30 | await System.IO.File.WriteAllTextAsync(filePath, JsonConvert.SerializeObject(mailEntity)); 31 | return true; 32 | } 33 | 34 | /// 35 | /// 保存Mqtt 配置 36 | /// 37 | /// 38 | /// 39 | public static async Task SaveMqttSetAsync(MqttOptionsEntity input) 40 | { 41 | await System.IO.File.WriteAllTextAsync(mqttFilePath, JsonConvert.SerializeObject(input)); 42 | return true; 43 | } 44 | 45 | /// 46 | /// 获取Mqtt 配置 47 | /// 48 | /// 49 | public static async Task GetMqttSetAsync() 50 | { 51 | if (!System.IO.File.Exists(mqttFilePath)) return new MqttOptionsEntity(); 52 | 53 | var entity = await System.IO.File.ReadAllTextAsync(mqttFilePath); 54 | return JsonConvert.DeserializeObject(entity); 55 | } 56 | 57 | /// 58 | /// 保存Rabbit 配置 59 | /// 60 | /// 61 | /// 62 | public static async Task SaveRabbitSetAsync(RabbitOptionsEntity input) 63 | { 64 | await System.IO.File.WriteAllTextAsync(rabbitFilePath, JsonConvert.SerializeObject(input)); 65 | return true; 66 | } 67 | 68 | /// 69 | /// 获取Rabbit 配置 70 | /// 71 | /// 72 | public static async Task GetRabbitSetAsync() 73 | { 74 | if (!System.IO.File.Exists(rabbitFilePath)) return new RabbitOptionsEntity(); 75 | 76 | var entity = await System.IO.File.ReadAllTextAsync(rabbitFilePath); 77 | return JsonConvert.DeserializeObject(entity) ?? new RabbitOptionsEntity(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/HttpHelper.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net.Http; 7 | using System.Net.Http.Headers; 8 | using System.Threading.Tasks; 9 | 10 | 11 | namespace Host 12 | { 13 | /// 14 | /// 请求帮助类 15 | /// 16 | public class HttpHelper 17 | { 18 | public static readonly HttpHelper Instance; 19 | static HttpHelper() 20 | { 21 | Instance = new HttpHelper(); 22 | } 23 | /// 24 | /// 不同url分配不同HttpClient 25 | /// 26 | public static ConcurrentDictionary dictionary = new ConcurrentDictionary(); 27 | 28 | private HttpClient GetHttpClient(string url) 29 | { 30 | var uri = new Uri(url); 31 | var key = uri.Scheme + uri.Host; 32 | //if (!dictionary.Keys.Contains(key)) 33 | return dictionary.GetOrAdd(key, new HttpClient()); 34 | //return dictionary[key]; 35 | } 36 | 37 | /// 38 | /// Post请求 39 | /// 40 | /// url地址 41 | /// 请求参数(Json字符串) 42 | /// webapi做用户认证 43 | /// 44 | public async Task PostAsync(string url, string jsonString, Dictionary headers = null) 45 | { 46 | if (string.IsNullOrWhiteSpace(jsonString)) 47 | jsonString = "{}"; 48 | StringContent content = new StringContent(jsonString); 49 | content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 50 | 51 | if (headers != null && headers.Any()) 52 | { 53 | //如果有headers认证等信息,则每个请求实例一个HttpClient 54 | using (HttpClient http = new HttpClient()) 55 | { 56 | foreach (var item in headers) 57 | { 58 | http.DefaultRequestHeaders.Remove(item.Key); 59 | http.DefaultRequestHeaders.TryAddWithoutValidation(item.Key, item.Value); 60 | } 61 | return await http.PostAsync(new Uri(url), content); 62 | } 63 | } 64 | else 65 | { 66 | return await GetHttpClient(url).PostAsync(new Uri(url), content); 67 | } 68 | } 69 | 70 | /// 71 | /// Post请求 72 | /// 73 | /// 74 | /// url地址 75 | /// 请求参数 76 | /// webapi做用户认证 77 | /// 78 | public async Task PostAsync(string url, T content, Dictionary headers = null) where T : class 79 | { 80 | return await PostAsync(url, JsonConvert.SerializeObject(content), headers); 81 | } 82 | 83 | /// 84 | /// Get请求 85 | /// 86 | /// url地址 87 | /// webapi做用户认证 88 | /// 89 | public async Task GetAsync(string url, Dictionary headers = null) 90 | { 91 | if (headers != null && headers.Any()) 92 | { 93 | //如果有headers认证等信息,则每个请求实例一个HttpClient 94 | using (HttpClient http = new HttpClient()) 95 | { 96 | foreach (var item in headers) 97 | { 98 | http.DefaultRequestHeaders.Remove(item.Key); 99 | http.DefaultRequestHeaders.TryAddWithoutValidation(item.Key, item.Value); 100 | } 101 | return await http.GetAsync(url); 102 | } 103 | } 104 | else 105 | { 106 | return await GetHttpClient(url).GetAsync(url); 107 | } 108 | } 109 | 110 | /// 111 | /// Put请求 112 | /// 113 | /// url地址 114 | /// 请求参数(Json字符串) 115 | /// webapi做用户认证 116 | /// 117 | public async Task PutAsync(string url, string jsonString, Dictionary headers = null) 118 | { 119 | if (string.IsNullOrWhiteSpace(jsonString)) 120 | jsonString = "{}"; 121 | StringContent content = new StringContent(jsonString); 122 | content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 123 | if (headers != null && headers.Any()) 124 | { 125 | //如果有headers认证等信息,则每个请求实例一个HttpClient 126 | using (HttpClient http = new HttpClient()) 127 | { 128 | foreach (var item in headers) 129 | { 130 | http.DefaultRequestHeaders.Remove(item.Key); 131 | http.DefaultRequestHeaders.TryAddWithoutValidation(item.Key, item.Value); 132 | } 133 | return await http.PutAsync(url, content); 134 | } 135 | } 136 | else 137 | { 138 | return await GetHttpClient(url).PutAsync(url, content); 139 | } 140 | } 141 | 142 | /// 143 | /// Put请求 144 | /// 145 | /// 146 | /// url地址 147 | /// 请求参数 148 | /// webapi做用户认证 149 | /// 150 | public async Task PutAsync(string url, T content, Dictionary headers = null) 151 | { 152 | return await PutAsync(url, JsonConvert.SerializeObject(content), headers); 153 | } 154 | 155 | /// 156 | /// Delete请求 157 | /// 158 | /// 159 | /// webapi做用户认证 160 | /// 161 | public async Task DeleteAsync(string url, Dictionary headers = null) 162 | { 163 | if (headers != null && headers.Any()) 164 | { 165 | //如果有headers认证等信息,则每个请求实例一个HttpClient 166 | using (HttpClient http = new HttpClient()) 167 | { 168 | foreach (var item in headers) 169 | { 170 | http.DefaultRequestHeaders.Remove(item.Key); 171 | http.DefaultRequestHeaders.TryAddWithoutValidation(item.Key, item.Value); 172 | } 173 | return await http.DeleteAsync(url); 174 | } 175 | } 176 | else 177 | { 178 | return await GetHttpClient(url).DeleteAsync(url); 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/MailHelper.cs: -------------------------------------------------------------------------------- 1 | using Host.Entity; 2 | using MimeKit; 3 | using System; 4 | using System.Security.Authentication; 5 | using System.Threading.Tasks; 6 | using Talk.Extensions; 7 | 8 | namespace Host.Common 9 | { 10 | public static class MailHelper 11 | { 12 | public static async Task SendMail(string title, string content, MailEntity mailInfo = null) 13 | { 14 | if (mailInfo == null) 15 | { 16 | mailInfo = await FileConfig.GetMailInfoAsync(); 17 | if (mailInfo.MailPwd.IsNullOrWhiteSpace() || 18 | mailInfo.MailFrom.IsNullOrWhiteSpace() || 19 | mailInfo.MailHost.IsNullOrWhiteSpace()) 20 | { 21 | throw new Exception("请先在 [/seting] 页面配置邮箱设置。"); 22 | } 23 | } 24 | else 25 | { 26 | mailInfo.MailFrom = mailInfo.MailFrom.Trim(); 27 | mailInfo.MailHost = mailInfo.MailHost.Trim(); 28 | mailInfo.MailTo = mailInfo.MailTo.Trim(); 29 | } 30 | 31 | var message = new MimeMessage(); 32 | message.From.Add(new MailboxAddress(mailInfo.MailFrom, mailInfo.MailFrom)); 33 | foreach (var mailTo in mailInfo.MailTo.Replace(";", ";").Replace(",", ";").Replace(",", ";").Split(';')) 34 | { 35 | message.To.Add(new MailboxAddress(mailTo, mailTo)); 36 | } 37 | message.Subject = string.Format(title); 38 | message.Body = new TextPart("html") 39 | { 40 | Text = content 41 | }; 42 | using (var client = new MailKit.Net.Smtp.SmtpClient()) 43 | { 44 | await client.ConnectAsync(mailInfo.MailHost, 465, true); 45 | await client.AuthenticateAsync(mailInfo.MailFrom, mailInfo.MailPwd); 46 | await client.SendAsync(message); 47 | await client.DisconnectAsync(true); 48 | } 49 | return true; 50 | } 51 | 52 | public static async Task SendMail(string title, string content, string mailTo) 53 | { 54 | var info = await FileConfig.GetMailInfoAsync(); 55 | if (info.MailPwd.IsNullOrWhiteSpace() || info.MailFrom.IsNullOrWhiteSpace() || info.MailHost.IsNullOrWhiteSpace()) 56 | throw new Exception("请先在 [/seting] 页面配置邮箱设置。"); 57 | info.MailTo = mailTo; 58 | return await SendMail(title, content, info); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Common/StringExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Common 7 | { 8 | public static class StringExtension 9 | { 10 | public static string ToBase64(this string str) 11 | { 12 | byte[] base64 = System.Text.Encoding.Default.GetBytes(str); 13 | return Convert.ToBase64String(base64); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Controllers/SetingController.cs: -------------------------------------------------------------------------------- 1 | using Host.Attributes; 2 | using Host.Common; 3 | using Host.Entity; 4 | using Host.Managers; 5 | using Host.Model; 6 | using Microsoft.AspNetCore.Cors; 7 | using Microsoft.AspNetCore.Mvc; 8 | using MimeKit; 9 | using Newtonsoft.Json; 10 | using System; 11 | using System.Threading.Tasks; 12 | using Talk.Extensions; 13 | 14 | namespace Host.Controllers 15 | { 16 | /// 17 | /// 设置 18 | /// 19 | [Route("api/[controller]/[Action]")] 20 | [EnableCors("AllowSameDomain")] //允许跨域 21 | public class SetingController : Controller 22 | { 23 | private static string refreshIntervalPath = "File/RefreshInterval.json"; 24 | private static string loginPasswordPath = "File/LoginPassword.json"; 25 | 26 | private static UpdateLoginInfoEntity LoginInfo = null; 27 | /// 28 | /// 保存Mail信息 29 | /// 30 | /// 31 | /// 32 | [HttpPost] 33 | public async Task SaveMailInfo([FromBody] MailEntity mailEntity) 34 | { 35 | return await FileConfig.SaveMailInfoAsync(mailEntity); 36 | } 37 | 38 | /// 39 | /// 保存Mqtt的配置 40 | /// 41 | /// 42 | [HttpPost] 43 | public async Task SaveMqttSet([FromBody] MqttOptionsEntity input) 44 | { 45 | await FileConfig.SaveMqttSetAsync(input); 46 | await MqttManager.Instance.RestartAsync(); 47 | return true; 48 | } 49 | 50 | /// 51 | /// 获取Mqtt的配置 52 | /// 53 | /// 54 | [HttpPost] 55 | public async Task GetMqttSet() 56 | { 57 | return await FileConfig.GetMqttSetAsync(); 58 | } 59 | 60 | /// 61 | /// 保存Rabbit 配置 62 | /// 63 | /// 64 | /// 65 | [HttpPost] 66 | public async Task SaveRabbitSet([FromBody] RabbitOptionsEntity input) 67 | { 68 | await FileConfig.SaveRabbitSetAsync(input); 69 | return true; 70 | } 71 | 72 | /// 73 | /// 重启Rabbit 74 | /// 75 | /// 76 | [HttpPost] 77 | public async Task RestartRabbit() 78 | { 79 | return await RabbitMQManager.Instance.RestartAsync(); 80 | } 81 | 82 | /// 83 | /// 获取Rabbit的配置 84 | /// 85 | /// 86 | [HttpPost] 87 | public async Task GetRabbitSet() 88 | { 89 | return await FileConfig.GetRabbitSetAsync(); 90 | } 91 | 92 | /// 93 | /// 保存刷新间隔 94 | /// 95 | /// 96 | /// 97 | [HttpPost] 98 | public async Task SaveRefreshInterval([FromBody] RefreshIntervalEntity entity) 99 | { 100 | await System.IO.File.WriteAllTextAsync(refreshIntervalPath, JsonConvert.SerializeObject(entity)); 101 | return true; 102 | } 103 | 104 | /// 105 | /// 保存登录密码 106 | /// 107 | /// 108 | /// 109 | [HttpPost] 110 | public async Task SaveLoginInfo([FromBody] UpdateLoginInfoEntity entity) 111 | { 112 | LoginInfo = await GetLoginAsync(); 113 | if (LoginInfo.NewPassword == entity.OldPassword) 114 | { 115 | await System.IO.File.WriteAllTextAsync(loginPasswordPath, JsonConvert.SerializeObject(entity)); 116 | LoginInfo = entity; 117 | return true; 118 | } 119 | return false; 120 | } 121 | 122 | private static DateTime ErrLoginTime = DateTime.MinValue; 123 | private static int LoginNumber = 0; 124 | /// 125 | /// 登录 126 | /// 127 | /// 128 | /// 129 | [HttpPost] 130 | [NoLogin] 131 | public async Task VerifyLoginInfo([FromBody] LoginInfoEntity input) 132 | { 133 | var output = new LoginInfoOutput(); 134 | 135 | //防止暴力破解,2分钟内只允许错误20次。 136 | if (LoginNumber++ >= 20 || ErrLoginTime.AddMinutes(2) >= DateTime.Now) 137 | { 138 | ErrLoginTime = DateTime.Now; 139 | LoginNumber = 0; 140 | return output; 141 | } 142 | 143 | LoginInfo = await GetLoginAsync(); 144 | if (input.Password == LoginInfo.NewPassword.ToBase64()) 145 | { 146 | output.Token = $"{DateTime.Now}".DES3Encrypt(); 147 | LoginNumber = 0; 148 | } 149 | else 150 | { 151 | var defaultPassword = ConfigurationManager.GetTryConfig("DefaultPassword"); 152 | if (!string.IsNullOrWhiteSpace(defaultPassword) && input.Password == defaultPassword.ToBase64()) 153 | { 154 | output.Token = $"{DateTime.Now}".DES3Encrypt(); 155 | LoginNumber = 0; 156 | } 157 | } 158 | return output; 159 | } 160 | 161 | /// 162 | /// 获取登录信息 163 | /// 164 | /// 165 | private async Task GetLoginAsync() 166 | { 167 | if (LoginInfo == null) 168 | { 169 | if (!System.IO.File.Exists(loginPasswordPath)) 170 | await System.IO.File.WriteAllTextAsync(loginPasswordPath, JsonConvert.SerializeObject(new UpdateLoginInfoEntity())); 171 | LoginInfo = JsonConvert.DeserializeObject(await System.IO.File.ReadAllTextAsync(loginPasswordPath)) ?? new UpdateLoginInfoEntity(); 172 | } 173 | return LoginInfo; 174 | } 175 | 176 | /// 177 | /// 获取 178 | /// 179 | /// 180 | [HttpPost] 181 | public async Task GetRefreshInterval() 182 | { 183 | return JsonConvert.DeserializeObject(await System.IO.File.ReadAllTextAsync(refreshIntervalPath)) ?? new RefreshIntervalEntity(); 184 | } 185 | 186 | /// 187 | /// 获取eMail信息 188 | /// 189 | /// 190 | [HttpPost] 191 | public async Task GetMailInfo() 192 | { 193 | return await FileConfig.GetMailInfoAsync(); 194 | } 195 | 196 | /// 197 | /// 发送邮件 198 | /// 199 | /// 200 | /// 201 | [HttpPost] 202 | [NoLogin] 203 | public async Task SendMail([FromBody] SendMailModel model) 204 | { 205 | return await MailHelper.SendMail(model.Title, model.Content, model.MailInfo); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | #基础镜像(用来构建镜像) 3 | FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | RUN apk add -U tzdata 7 | RUN apk add icu-libs 8 | ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false 9 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 10 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Beijing 11 | 12 | #编译(临时镜像,主要用来编译发布项目) 13 | FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS publish 14 | WORKDIR /src 15 | COPY . . 16 | WORKDIR /src/Host 17 | RUN dotnet publish -c Release -o /app 18 | 19 | #构建镜像 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app . 23 | CMD ["dotnet", "Host.dll"] -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Dockerfile[树莓派]: -------------------------------------------------------------------------------- 1 | #基础镜像(用来构建镜像) 2 | FROM mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim-arm32v7 AS base 3 | WORKDIR /app 4 | EXPOSE 80 5 | ENV TZ=Asia/Shanghai 6 | CMD cp /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Beijing 7 | CMD ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 8 | 9 | #编译(临时镜像,主要用来编译发布项目) 10 | FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS publish 11 | WORKDIR /src 12 | COPY . . 13 | WORKDIR /src/Host 14 | #RUN dotnet publish -c Release -o /app 15 | RUN dotnet publish -r debian-arm -c Release -o /app 16 | 17 | #构建镜像 18 | FROM base AS final 19 | WORKDIR /app 20 | COPY --from=publish /app . 21 | CMD ["dotnet", "Host.dll"] -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/JobBriefInfoEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Quartz; 6 | 7 | namespace Host.Entity 8 | { 9 | public class JobBriefInfoEntity 10 | { 11 | /// 12 | /// 任务组名 13 | /// 14 | public string GroupName { get; set; } 15 | 16 | /// 17 | /// 任务信息 18 | /// 19 | public List JobInfoList { get; set; } = new List(); 20 | } 21 | 22 | public class JobBriefInfo 23 | { 24 | /// 25 | /// 任务名称 26 | /// 27 | public string Name { get; set; } 28 | 29 | /// 30 | /// 下次执行时间 31 | /// 32 | public DateTime? NextFireTime { get; set; } 33 | 34 | /// 35 | /// 上次执行时间 36 | /// 37 | public DateTime? PreviousFireTime { get; set; } 38 | 39 | /// 40 | /// 上次执行的异常信息 41 | /// 42 | public string LastErrMsg { get; set; } 43 | 44 | /// 45 | /// 任务状态 46 | /// 47 | public TriggerState TriggerState { get; set; } 48 | 49 | /// 50 | /// 显示状态 51 | /// 52 | public string DisplayState 53 | { 54 | get 55 | { 56 | var state = string.Empty; 57 | switch (TriggerState) 58 | { 59 | case TriggerState.Normal: 60 | state = "正常"; 61 | break; 62 | case TriggerState.Paused: 63 | state = "暂停"; 64 | break; 65 | case TriggerState.Complete: 66 | state = "完成"; 67 | break; 68 | case TriggerState.Error: 69 | state = "异常"; 70 | break; 71 | case TriggerState.Blocked: 72 | state = "阻塞"; 73 | break; 74 | case TriggerState.None: 75 | state = "不存在"; 76 | break; 77 | default: 78 | state = "未知"; 79 | break; 80 | } 81 | return state; 82 | } 83 | } 84 | 85 | /// 86 | /// 已经执行次数 87 | /// 88 | public long RunNumber { get; set; } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/JobInfoEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Quartz; 6 | 7 | namespace Host.Entity 8 | { 9 | public class JobInfoEntity 10 | { 11 | /// 12 | /// 任务组名 13 | /// 14 | public string GroupName { get; set; } 15 | 16 | /// 17 | /// 任务信息 18 | /// 19 | public List JobInfoList { get; set; } = new List(); 20 | } 21 | 22 | public class JobInfo 23 | { 24 | /// 25 | /// 任务名称 26 | /// 27 | public string Name { get; set; } 28 | 29 | /// 30 | /// 下次执行时间 31 | /// 32 | public DateTime? NextFireTime { get; set; } 33 | 34 | /// 35 | /// 上次执行时间 36 | /// 37 | public DateTime? PreviousFireTime { get; set; } 38 | 39 | /// 40 | /// 开始时间 41 | /// 42 | public DateTime BeginTime { get; set; } 43 | 44 | /// 45 | /// 结束时间 46 | /// 47 | public DateTime? EndTime { get; set; } 48 | 49 | /// 50 | /// 上次执行的异常信息 51 | /// 52 | public string LastErrMsg { get; set; } 53 | 54 | /// 55 | /// 任务状态 56 | /// 57 | public TriggerState TriggerState { get; set; } 58 | 59 | /// 60 | /// 描述 61 | /// 62 | public string Description { get; set; } 63 | 64 | /// 65 | /// 显示状态 66 | /// 67 | public string DisplayState 68 | { 69 | get 70 | { 71 | var state = string.Empty; 72 | switch (TriggerState) 73 | { 74 | case TriggerState.Normal: 75 | state = "正常"; 76 | break; 77 | case TriggerState.Paused: 78 | state = "暂停"; 79 | break; 80 | case TriggerState.Complete: 81 | state = "完成"; 82 | break; 83 | case TriggerState.Error: 84 | state = "异常"; 85 | break; 86 | case TriggerState.Blocked: 87 | state = "阻塞"; 88 | break; 89 | case TriggerState.None: 90 | state = "不存在"; 91 | break; 92 | default: 93 | state = "未知"; 94 | break; 95 | } 96 | return state; 97 | } 98 | } 99 | 100 | /// 101 | /// 时间间隔 102 | /// 103 | public string Interval { get; set; } 104 | 105 | /// 106 | /// 触发地址 107 | /// 108 | public string TriggerAddress { get; set; } 109 | public string RequestType { get; set; } 110 | /// 111 | /// 已经执行的次数 112 | /// 113 | public long RunNumber { get; set; } 114 | public long JobType { get; set; } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/LoginInfoEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class LoginInfoEntity 9 | { 10 | public string Password { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/LoginInfoOutput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class LoginInfoOutput 9 | { 10 | public string Token { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/MailEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class MailEntity 9 | { 10 | /// 11 | /// 发件邮箱 12 | /// 13 | public string MailFrom { get; set; } 14 | /// 15 | /// 邮箱密码 16 | /// 17 | public string MailPwd { get; set; } 18 | /// 19 | /// 发件服务器 20 | /// 21 | public string MailHost { get; set; } 22 | /// 23 | /// 收件邮箱 24 | /// 25 | public string MailTo { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/ModifyJobInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class ModifyJobInput 9 | { 10 | public ScheduleEntity NewScheduleEntity { get; set; } 11 | public ScheduleEntity OldScheduleEntity { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/MqttOptionsEntity.cs: -------------------------------------------------------------------------------- 1 | using Host.Common.Enums; 2 | 3 | namespace Host.Entity 4 | { 5 | public class MqttOptionsEntity 6 | { 7 | public string ClientId { get; set; } 8 | public string Host { get; set; } 9 | public string Port { get; set; } 10 | public string UserName { get; set; } 11 | public string Password { get; set; } 12 | 13 | public ConnectionMethod ConnectionMethod { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/RabbitOptionsEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class RabbitOptionsEntity 9 | { 10 | public string RabbitHost { get; set; } 11 | public int RabbitPort { get; set; } 12 | public string RabbitUserName { get; set; } 13 | public string RabbitPassword { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/RefreshIntervalEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class RefreshIntervalEntity 9 | { 10 | /// 11 | /// 间隔时间 12 | /// 13 | public int IntervalTime { get; set; } = 10; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/ScheduleEntity.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.Common.Enums; 3 | using System; 4 | 5 | namespace Host 6 | { 7 | public class ScheduleEntity 8 | { 9 | /// 10 | /// 任务名称 11 | /// 12 | public string JobName { get; set; } 13 | /// 14 | /// 任务分组 15 | /// 16 | public string JobGroup { get; set; } 17 | /// 18 | /// 任务类型 19 | /// 20 | public JobTypeEnum JobType { get; set; } = JobTypeEnum.Url; 21 | /// 22 | /// 开始时间 23 | /// 24 | public DateTimeOffset BeginTime { get; set; } = DateTime.Now; 25 | /// 26 | /// 结束时间 27 | /// 28 | public DateTimeOffset? EndTime { get; set; } 29 | /// 30 | /// Cron表达式 31 | /// 32 | public string Cron { get; set; } 33 | /// 34 | /// 执行次数(默认无限循环) 35 | /// 36 | public int? RunTimes { get; set; } 37 | /// 38 | /// 执行间隔时间,单位秒(如果有Cron,则IntervalSecond失效) 39 | /// 40 | public int? IntervalSecond { get; set; } 41 | /// 42 | /// 触发器类型 43 | /// 44 | public TriggerTypeEnum TriggerType { get; set; } 45 | /// 46 | /// 描述 47 | /// 48 | public string Description { get; set; } 49 | 50 | public MailMessageEnum MailMessage { get; set; } 51 | 52 | #region Url 53 | /// 54 | /// 请求url 55 | /// 56 | public string RequestUrl { get; set; } 57 | /// 58 | /// 请求参数(Post,Put请求用) 59 | /// 60 | public string RequestParameters { get; set; } 61 | /// 62 | /// Headers(可以包含如:Authorization授权认证) 63 | /// 格式:{"Authorization":"userpassword.."} 64 | /// 65 | public string Headers { get; set; } 66 | /// 67 | /// 请求类型 68 | /// 69 | public RequestTypeEnum RequestType { get; set; } = RequestTypeEnum.Post; 70 | #endregion 71 | 72 | #region Emial 73 | public string MailTitle { get; set; } 74 | public string MailContent { get; set; } 75 | public string MailTo { get; set; } 76 | #endregion 77 | 78 | #region MQTT 79 | /// Topic 主题 80 | /// 81 | public string Topic { get; set; } 82 | /// 83 | /// Payload 84 | /// 85 | public string Payload { get; set; } 86 | #endregion 87 | 88 | #region Rabbit 89 | public string RabbitQueue { get; set; } 90 | public string RabbitBody { get; set; } 91 | #endregion 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Entity/UpdateLoginInfoEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Entity 7 | { 8 | public class UpdateLoginInfoEntity 9 | { 10 | public string OldPassword { get; set; } = string.Empty; 11 | public string NewPassword { get; set; } = string.Empty; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/File/RefreshInterval.json: -------------------------------------------------------------------------------- 1 | {"IntervalTime":1} -------------------------------------------------------------------------------- /QuartzNetAPI/Host/File/rabbitmq.json: -------------------------------------------------------------------------------- 1 | {"RabbitHost":"47.100.89.194","RabbitPort":5672,"RabbitUserName":"guest","RabbitPassword":"guest"} -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Filters/AuthorizationFilter.cs: -------------------------------------------------------------------------------- 1 | using Host.Attributes; 2 | using Host.Common; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Mvc.Controllers; 5 | using Microsoft.AspNetCore.Mvc.Filters; 6 | using System; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Threading.Tasks; 10 | using Talk.Extensions; 11 | 12 | namespace Host.Filters 13 | { 14 | public class AuthorizationFilter : IAsyncAuthorizationFilter 15 | { 16 | public Task OnAuthorizationAsync(AuthorizationFilterContext context) 17 | { 18 | if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) 19 | { 20 | var noNeedLoginAttribute = controllerActionDescriptor. 21 | ControllerTypeInfo. 22 | GetCustomAttributes(true) 23 | .Where(a => a.GetType().Equals(typeof(NoLoginAttribute))) 24 | .ToList(); 25 | noNeedLoginAttribute.AddRange(controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true) 26 | .Where(a => a.GetType().Equals(typeof(NoLoginAttribute))).ToList()); 27 | 28 | //如果标记了 NoLoginAttribute 则不验证其登录状态 29 | if (noNeedLoginAttribute.Any()) 30 | { 31 | return Task.CompletedTask; 32 | } 33 | } 34 | 35 | var token = context.HttpContext.Request.Headers["token"].ToString(); 36 | if (!token.IsNullOrWhiteSpace()) 37 | { 38 | var time = token.DES3Decrypt().ToDateTime(); 39 | //登录信息有效期为当天 40 | if (DateTime.Now.Date == time.Date) 41 | { 42 | return Task.CompletedTask; 43 | } 44 | } 45 | 46 | context.Result = new JsonResult(new 47 | { 48 | ErrorMsg = "请登录", 49 | ResultUrl = "/signin", 50 | }); 51 | context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 52 | return Task.CompletedTask; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Host.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | bin\Debug\netcoreapp2.0\Host.xml 9 | NU1605 10 | 1701;1702;CS1591;CS1572 11 | 12 | 13 | 14 | bin\Release\netcoreapp2.0\Host.xml 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | PreserveNewest 67 | 68 | 69 | PreserveNewest 70 | 71 | 72 | Always 73 | 74 | 75 | Always 76 | 77 | 78 | Always 79 | 80 | 81 | Always 82 | 83 | 84 | PreserveNewest 85 | 86 | 87 | Always 88 | 89 | 90 | Always 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Host.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Host 5 | FolderProfile 6 | 7 | 8 | ProjectDebugger 9 | 10 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/HttpJob.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.IJobs; 3 | using Host.IJobs.Model; 4 | using Host.Model; 5 | using Newtonsoft.Json; 6 | using Quartz; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Net.Http; 10 | using System.Threading.Tasks; 11 | using System.Web; 12 | using Talk.Extensions; 13 | 14 | namespace Host 15 | { 16 | public class HttpJob : JobBase, IJob 17 | { 18 | public HttpJob() : base(new LogUrlModel()) 19 | { } 20 | 21 | public override async Task NextExecute(IJobExecutionContext context) 22 | { 23 | //获取相关参数 24 | var requestUrl = context.JobDetail.JobDataMap.GetString(Constant.REQUESTURL)?.Trim(); 25 | requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl; 26 | var requestParameters = context.JobDetail.JobDataMap.GetString(Constant.REQUESTPARAMETERS); 27 | var headersString = context.JobDetail.JobDataMap.GetString(Constant.HEADERS); 28 | var headers = headersString != null ? JsonConvert.DeserializeObject>(headersString?.Trim()) : null; 29 | var requestType = (RequestTypeEnum)int.Parse(context.JobDetail.JobDataMap.GetString(Constant.REQUESTTYPE)); 30 | 31 | 32 | LogInfo.Url = requestUrl; 33 | LogInfo.RequestType = requestType.ToString(); 34 | LogInfo.Parameters = requestParameters; 35 | 36 | HttpResponseMessage response = new HttpResponseMessage(); 37 | var http = HttpHelper.Instance; 38 | switch (requestType) 39 | { 40 | case RequestTypeEnum.Get: 41 | response = await http.GetAsync(requestUrl, headers); 42 | break; 43 | case RequestTypeEnum.Post: 44 | response = await http.PostAsync(requestUrl, requestParameters, headers); 45 | break; 46 | case RequestTypeEnum.Put: 47 | response = await http.PutAsync(requestUrl, requestParameters, headers); 48 | break; 49 | case RequestTypeEnum.Delete: 50 | response = await http.DeleteAsync(requestUrl, headers); 51 | break; 52 | } 53 | var result = HttpUtility.HtmlEncode(await response.Content.ReadAsStringAsync()); 54 | LogInfo.Result = $"{result.MaxLeft(1000)}"; 55 | if (!response.IsSuccessStatusCode) 56 | { 57 | LogInfo.ErrorMsg = $"{result.MaxLeft(3000)}"; 58 | await ErrorAsync(LogInfo.JobName, new Exception(result.MaxLeft(3000)), JsonConvert.SerializeObject(LogInfo), MailLevel); 59 | context.JobDetail.JobDataMap[Constant.EXCEPTION] = $"
{LogInfo.BeginTime}
{JsonConvert.SerializeObject(LogInfo)}"; 60 | } 61 | else 62 | { 63 | try 64 | { 65 | //这里需要和请求方约定好返回结果约定为HttpResultModel模型 66 | var httpResult = JsonConvert.DeserializeObject(HttpUtility.HtmlDecode(result)); 67 | if (!httpResult.IsSuccess) 68 | { 69 | LogInfo.ErrorMsg = $"{httpResult.ErrorMsg}"; 70 | await ErrorAsync(LogInfo.JobName, new Exception(httpResult.ErrorMsg), JsonConvert.SerializeObject(LogInfo), MailLevel); 71 | context.JobDetail.JobDataMap[Constant.EXCEPTION] = $"
{LogInfo.BeginTime}
{JsonConvert.SerializeObject(LogInfo)}"; 72 | } 73 | else 74 | await InformationAsync(LogInfo.JobName, JsonConvert.SerializeObject(LogInfo), MailLevel); 75 | } 76 | catch (Exception) 77 | { 78 | await InformationAsync(LogInfo.JobName, JsonConvert.SerializeObject(LogInfo), MailLevel); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/JobBase.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.Controllers; 3 | using Host.IJobs.Model; 4 | using Host.Model; 5 | using Newtonsoft.Json; 6 | using Quartz; 7 | using Serilog; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Diagnostics; 11 | using System.Threading.Tasks; 12 | 13 | namespace Host.IJobs 14 | { 15 | [DisallowConcurrentExecution] 16 | [PersistJobDataAfterExecution] 17 | public abstract class JobBase where T : LogModel, new() 18 | { 19 | protected readonly int maxLogCount = 20;//最多保存日志数量 20 | protected readonly int warnTime = 20;//接口请求超过多少秒记录警告日志 21 | protected Stopwatch stopwatch = new Stopwatch(); 22 | protected T LogInfo { get; private set; } 23 | protected MailMessageEnum MailLevel = MailMessageEnum.None; 24 | 25 | public JobBase(T logInfo) 26 | { 27 | LogInfo = logInfo; 28 | } 29 | 30 | public async Task Execute(IJobExecutionContext context) 31 | { 32 | //如果结束时间超过当前时间,则暂停当前任务。 33 | var endTime = context.JobDetail.JobDataMap.GetString("EndAt"); 34 | if (!string.IsNullOrWhiteSpace(endTime) && DateTime.Parse(endTime) <= DateTime.Now) 35 | { 36 | await context.Scheduler.PauseJob(new JobKey(context.JobDetail.Key.Name, context.JobDetail.Key.Group)); 37 | return; 38 | } 39 | 40 | MailLevel = (MailMessageEnum)int.Parse(context.JobDetail.JobDataMap.GetString(Constant.MAILMESSAGE) ?? "0"); 41 | //记录执行次数 42 | var runNumber = context.JobDetail.JobDataMap.GetLong(Constant.RUNNUMBER); 43 | context.JobDetail.JobDataMap[Constant.RUNNUMBER] = ++runNumber; 44 | 45 | var logs = context.JobDetail.JobDataMap[Constant.LOGLIST] as List ?? new List(); 46 | if (logs.Count >= maxLogCount) 47 | logs.RemoveRange(0, logs.Count - maxLogCount); 48 | 49 | stopwatch.Restart(); // 开始监视代码运行时间 50 | try 51 | { 52 | LogInfo.BeginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 53 | LogInfo.JobName = $"{context.JobDetail.Key.Group}.{context.JobDetail.Key.Name}"; 54 | 55 | await NextExecute(context); 56 | } 57 | catch (Exception ex) 58 | { 59 | LogInfo.ErrorMsg = $"{ex.Message}"; 60 | context.JobDetail.JobDataMap[Constant.EXCEPTION] = $"
{LogInfo.BeginTime}
{JsonConvert.SerializeObject(LogInfo)}"; 61 | await ErrorAsync(LogInfo.JobName, ex, JsonConvert.SerializeObject(LogInfo), MailLevel); 62 | } 63 | finally 64 | { 65 | stopwatch.Stop(); // 停止监视 66 | double seconds = stopwatch.Elapsed.TotalSeconds; //总秒数 67 | LogInfo.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 68 | 69 | if (seconds >= 1) 70 | LogInfo.ExecuteTime = seconds + "秒"; 71 | else 72 | LogInfo.ExecuteTime = stopwatch.Elapsed.TotalMilliseconds + "毫秒"; 73 | 74 | var classErr = string.IsNullOrWhiteSpace(LogInfo.ErrorMsg) ? "" : "error"; 75 | logs.Add($"

{LogInfo.BeginTime} 至 {LogInfo.EndTime} 【耗时】{LogInfo.ExecuteTime}{JsonConvert.SerializeObject(LogInfo)}

"); 76 | context.JobDetail.JobDataMap[Constant.LOGLIST] = logs; 77 | if (seconds >= warnTime)//如果请求超过20秒,记录警告日志 78 | { 79 | await WarningAsync(LogInfo.JobName, "耗时过长 - " + JsonConvert.SerializeObject(LogInfo), MailLevel); 80 | } 81 | } 82 | } 83 | 84 | public abstract Task NextExecute(IJobExecutionContext context); 85 | 86 | public async Task WarningAsync(string title, string msg, MailMessageEnum mailMessage) 87 | { 88 | Log.Logger.Warning(msg); 89 | if (mailMessage == MailMessageEnum.All) 90 | { 91 | await new SetingController().SendMail(new SendMailModel() 92 | { 93 | Title = $"任务调度-{title}【警告】消息", 94 | Content = msg 95 | }); 96 | } 97 | } 98 | 99 | public async Task InformationAsync(string title, string msg, MailMessageEnum mailMessage) 100 | { 101 | Log.Logger.Information(msg); 102 | if (mailMessage == MailMessageEnum.All) 103 | { 104 | await new SetingController().SendMail(new SendMailModel() 105 | { 106 | Title = $"任务调度-{title}消息", 107 | Content = msg 108 | }); 109 | } 110 | } 111 | 112 | public async Task ErrorAsync(string title, Exception ex, string msg, MailMessageEnum mailMessage) 113 | { 114 | Log.Logger.Error(ex, msg); 115 | if (mailMessage == MailMessageEnum.Err || mailMessage == MailMessageEnum.All) 116 | { 117 | await new SetingController().SendMail(new SendMailModel() 118 | { 119 | Title = $"任务调度-{title}【异常】消息", 120 | Content = msg 121 | }); 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/MailJob.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.IJobs.Model; 3 | using Quartz; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.IJobs 7 | { 8 | public class MailJob : JobBase, IJob 9 | { 10 | public MailJob() : base(new LogMailModel()) 11 | { } 12 | 13 | public override async Task NextExecute(IJobExecutionContext context) 14 | { 15 | var title = context.JobDetail.JobDataMap.GetString(Constant.MailTitle); 16 | var content = context.JobDetail.JobDataMap.GetString(Constant.MailContent); 17 | var mailTo = context.JobDetail.JobDataMap.GetString(Constant.MailTo); 18 | 19 | LogInfo.Title = title; 20 | LogInfo.Content = content; 21 | LogInfo.MailTo = mailTo; 22 | 23 | await MailHelper.SendMail(title, content, mailTo); 24 | 25 | LogInfo.Result = "发送成功!"; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/Model/LogMailModel.cs: -------------------------------------------------------------------------------- 1 | namespace Host.IJobs.Model 2 | { 3 | public class LogMailModel : LogModel 4 | { 5 | public string Title { get; set; } 6 | public string Content { get; set; } 7 | /// 8 | /// 收件邮箱 9 | /// 10 | public string MailTo { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/Model/LogModel.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Host.IJobs.Model 4 | { 5 | public abstract class LogModel 6 | { 7 | /// 8 | /// 开始执行时间 9 | /// 10 | [JsonIgnore] 11 | public string BeginTime { get; set; } 12 | /// 13 | /// 结束时间 14 | /// 15 | [JsonIgnore] 16 | public string EndTime { get; set; } 17 | /// 18 | /// 耗时(秒) 19 | /// 20 | [JsonIgnore] 21 | public string ExecuteTime { get; set; } 22 | /// 23 | /// 任务名称 24 | /// 25 | public string JobName { get; set; } 26 | /// 27 | /// 结果 28 | /// 29 | public string Result { get; set; } 30 | /// 31 | /// 异常消息 32 | /// 33 | public string ErrorMsg { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/Model/LogMqttModel.cs: -------------------------------------------------------------------------------- 1 | namespace Host.IJobs.Model 2 | { 3 | public class LogMqttModel : LogModel 4 | { 5 | public string Topic { get; set; } 6 | public string Payload { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/Model/LogRabbitModel.cs: -------------------------------------------------------------------------------- 1 | namespace Host.IJobs.Model 2 | { 3 | public class LogRabbitModel : LogModel 4 | { 5 | public string RabbitQueue { get; set; } 6 | public string RabbitBody { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/Model/LogUrlModel.cs: -------------------------------------------------------------------------------- 1 | namespace Host.IJobs.Model 2 | { 3 | public class LogUrlModel : LogModel 4 | { 5 | /// 6 | /// 请求地址 7 | /// 8 | public string Url { get; set; } 9 | /// 10 | /// 请求类型 11 | /// 12 | public string RequestType { get; set; } 13 | /// 14 | /// 请求参数 15 | /// 16 | public string Parameters { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/MqttJob.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.IJobs.Model; 3 | using Host.Managers; 4 | using MQTTnet.Client.Publishing; 5 | using Newtonsoft.Json; 6 | using Quartz; 7 | using System.Threading.Tasks; 8 | 9 | namespace Host.IJobs 10 | { 11 | public class MqttJob : JobBase, IJob 12 | { 13 | private MqttManager mqttManager; 14 | public MqttJob() : base(new LogMqttModel()) 15 | { 16 | mqttManager = MqttManager.Instance; 17 | } 18 | 19 | public override async Task NextExecute(IJobExecutionContext context) 20 | { 21 | var topic = context.JobDetail.JobDataMap.GetString(Constant.Topic); 22 | var payload = context.JobDetail.JobDataMap.GetString(Constant.Payload); 23 | LogInfo.Topic = topic; 24 | LogInfo.Payload = payload; 25 | 26 | var mqttSet = await FileConfig.GetMqttSetAsync(); 27 | if (string.IsNullOrWhiteSpace(mqttSet.Host) || string.IsNullOrWhiteSpace(mqttSet.Port)) 28 | LogInfo.ErrorMsg = $"请先在 [/seting] 页面配置MQTT设置。"; 29 | else if (!mqttManager.MqttClient.IsConnected) 30 | LogInfo.ErrorMsg = $"Mqtt服务连接失败"; 31 | else if (!mqttManager.MqttClient.IsStarted) 32 | LogInfo.ErrorMsg = $"Mqtt服务启动失败"; 33 | else 34 | { 35 | var detectionrResult = await mqttManager.PublishAsync(topic, payload); 36 | if (detectionrResult.ReasonCode != MqttClientPublishReasonCode.Success) 37 | LogInfo.ErrorMsg = $"topic:{topic} reason:{detectionrResult.ReasonString} {detectionrResult.ReasonCode}"; 38 | } 39 | 40 | if (!string.IsNullOrWhiteSpace(LogInfo.ErrorMsg)) 41 | context.JobDetail.JobDataMap[Constant.EXCEPTION] = $"
{LogInfo.BeginTime}
{JsonConvert.SerializeObject(LogInfo)}"; 42 | else 43 | LogInfo.Result = "发送成功!"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/IJobs/RabbitJob.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.IJobs.Model; 3 | using Host.Managers; 4 | using Quartz; 5 | using RabbitMQ.Client; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Host.IJobs 10 | { 11 | public class RabbitJob : JobBase, IJob 12 | { 13 | private IConnection connection; 14 | public RabbitJob() : base(new LogRabbitModel()) 15 | { 16 | connection = RabbitMQManager.Instance.Connection; 17 | } 18 | 19 | public override async Task NextExecute(IJobExecutionContext context) 20 | { 21 | var queue = context.JobDetail.JobDataMap.GetString(Constant.RabbitQueue); 22 | var body = context.JobDetail.JobDataMap.GetString(Constant.RabbitBody); 23 | LogInfo.RabbitQueue = queue; 24 | LogInfo.RabbitBody = body; 25 | 26 | var rabbitSet = await FileConfig.GetRabbitSetAsync(); 27 | if (string.IsNullOrWhiteSpace(rabbitSet.RabbitHost) || string.IsNullOrWhiteSpace(rabbitSet.RabbitUserName)) 28 | LogInfo.ErrorMsg = $"请先在 [/seting] 页面配置RabbitMQ设置。"; 29 | else if (!connection?.IsOpen ?? true) 30 | LogInfo.ErrorMsg = $"RabbitMQ服务连接失败。"; 31 | else 32 | { 33 | //创建通道 34 | using (var channel = connection.CreateModel()) 35 | { 36 | //声明一个队列 37 | channel.QueueDeclare(queue, false, false, false, null); 38 | //发布消息 39 | channel.BasicPublish("", queue, null, Encoding.UTF8.GetBytes(body)); 40 | channel.Close(); 41 | } 42 | 43 | LogInfo.Result = "发送成功!"; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Managers/MqttManager.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using Host.Common.Enums; 3 | using Host.Entity; 4 | using MQTTnet; 5 | using MQTTnet.Client; 6 | using MQTTnet.Client.Options; 7 | using MQTTnet.Client.Publishing; 8 | using MQTTnet.Extensions.ManagedClient; 9 | using MQTTnet.Protocol; 10 | using Newtonsoft.Json; 11 | using Serilog; 12 | using System; 13 | using System.Threading.Tasks; 14 | 15 | namespace Host.Managers 16 | { 17 | /// 18 | /// Mqtt - 单例 19 | /// 20 | public class MqttManager 21 | { 22 | public static readonly MqttManager Instance; 23 | static MqttManager() 24 | { 25 | Instance = new MqttManager(); 26 | } 27 | 28 | public IManagedMqttClient MqttClient { get; private set; } 29 | 30 | /// 31 | /// 重启启动 32 | /// 33 | /// 34 | /// 35 | public async Task RestartAsync() 36 | { 37 | try 38 | { 39 | await StopAsync(); 40 | 41 | var model = await FileConfig.GetMqttSetAsync(); 42 | MqttClient = new MqttFactory().CreateManagedMqttClient(); 43 | var mqttClientOptions = new MqttClientOptionsBuilder() 44 | .WithKeepAlivePeriod(TimeSpan.FromSeconds(29)) 45 | .WithClientId(model.ClientId) 46 | .WithWebSocketServer($"{model.Host}:{model.Port}/mqtt") 47 | .WithCredentials(model.UserName, model.Password); 48 | 49 | if (model.ConnectionMethod == ConnectionMethod.WSS) 50 | mqttClientOptions = mqttClientOptions.WithTls(); 51 | 52 | var options = new ManagedMqttClientOptionsBuilder() 53 | .WithAutoReconnectDelay(TimeSpan.FromSeconds(5)) 54 | .WithClientOptions(mqttClientOptions.Build()) 55 | .Build(); 56 | 57 | await MqttClient.StartAsync(options); 58 | } 59 | catch (Exception ex) 60 | { 61 | Log.Logger.Error($"MQTT启动异常,{ex.Message}"); 62 | } 63 | } 64 | 65 | /// 66 | /// 发布 67 | /// 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | /// 74 | public async Task PublishAsync(string topic, T payloadData, bool retain = false, MqttQualityOfServiceLevel serviceLevel = MqttQualityOfServiceLevel.AtMostOnce) //where T : class, new() 75 | { 76 | var payload = JsonConvert.SerializeObject(payloadData, Formatting.None, AppSetting.SerializerSettings); 77 | return await PublishAsync(topic, payload, retain); 78 | } 79 | 80 | /// 81 | /// 发布 82 | /// 83 | /// 84 | /// 85 | /// 86 | /// 87 | /// 88 | public async Task PublishAsync(string topic, string payload, bool retain = false, MqttQualityOfServiceLevel serviceLevel = MqttQualityOfServiceLevel.AtMostOnce) 89 | { 90 | return await MqttClient.PublishAsync(topic, payload, serviceLevel, retain); 91 | } 92 | 93 | /// 94 | /// Stop 95 | /// 96 | /// 97 | private async Task StopAsync() 98 | { 99 | if (MqttClient?.IsStarted ?? false) 100 | await MqttClient?.StopAsync(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Managers/RabbitMQManager.cs: -------------------------------------------------------------------------------- 1 | using Host.Common; 2 | using RabbitMQ.Client; 3 | using System.Threading.Tasks; 4 | 5 | namespace Host.Managers 6 | { 7 | public class RabbitMQManager 8 | { 9 | public static readonly RabbitMQManager Instance; 10 | static RabbitMQManager() 11 | { 12 | Instance = new RabbitMQManager(); 13 | } 14 | 15 | 16 | public IConnection Connection { get; private set; } 17 | 18 | /// 19 | /// 重启启动 20 | /// 21 | /// 22 | /// 23 | public async Task RestartAsync() 24 | { 25 | Stop(); 26 | 27 | var entity = await FileConfig.GetRabbitSetAsync(); 28 | //创建连接工厂 29 | var factory = new ConnectionFactory 30 | { 31 | UserName = entity.RabbitUserName,//用户名 32 | Password = entity.RabbitPassword,//密码 33 | HostName = entity.RabbitHost,//rabbitmq ip 34 | Port = entity.RabbitPort, 35 | }; 36 | try 37 | { 38 | //创建连接 39 | Connection = factory.CreateConnection(); 40 | } 41 | catch (System.Exception ex) 42 | { 43 | //log 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | /// 50 | /// Stop 51 | /// 52 | /// 53 | private void Stop() 54 | { 55 | if (Connection?.IsOpen ?? false) 56 | { 57 | Connection?.Close(); 58 | Connection?.Dispose(); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Model/HttpResultModel.cs: -------------------------------------------------------------------------------- 1 | namespace Host.Model 2 | { 3 | /// 4 | /// Job任务结果 5 | /// 6 | public class HttpResultModel 7 | { 8 | /// 9 | /// 请求是否成功 10 | /// 11 | public bool IsSuccess { get; set; } = true; 12 | /// 13 | /// 异常消息 14 | /// 15 | public string ErrorMsg { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Model/LogInfoModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Host.Model 4 | { 5 | public class LogInfoModel 6 | { 7 | /// 8 | /// 开始执行时间 9 | /// 10 | public string BeginTime { get; set; } 11 | /// 12 | /// 结束时间 13 | /// 14 | public string EndTime { get; set; } 15 | /// 16 | /// 耗时(秒) 17 | /// 18 | public string ExecuteTime { get; set; } 19 | /// 20 | /// 任务名称 21 | /// 22 | public string JobName { get; set; } 23 | /// 24 | /// 请求地址 25 | /// 26 | public string Url { get; set; } 27 | /// 28 | /// 请求类型 29 | /// 30 | public string RequestType { get; set; } 31 | /// 32 | /// 请求参数 33 | /// 34 | public string Parameters { get; set; } 35 | /// 36 | /// 请求结果 37 | /// 38 | public string Result { get; set; } 39 | /// 40 | /// 异常消息 41 | /// 42 | public string ErrorMsg { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Model/SendMailModel.cs: -------------------------------------------------------------------------------- 1 | using Host.Entity; 2 | 3 | namespace Host.Model 4 | { 5 | public class SendMailModel 6 | { 7 | public string Title { get; set; } 8 | public string Content { get; set; } 9 | public MailEntity MailInfo { get; set; } = null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace Host 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | FileSystem 9 | FileSystem 10 | Release 11 | Any CPU 12 | 13 | True 14 | False 15 | 62c51804-d792-491e-82e6-ff6fbae2983c 16 | D:\Users\benny\Desktop\quartzUI 17 | False 18 | 19 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Properties/PublishProfiles/FolderProfile.pubxml.user: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | <_PublishTargetUrl>D:\Users\benny\Desktop\quartzUI 10 | 11 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Host": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "applicationUrl": "http://localhost:8100/" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/IRepositorie.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Repositories 7 | { 8 | public interface IRepositorie 9 | { 10 | /// 11 | /// 初始化表结构 12 | /// 13 | /// 14 | Task InitTable(); 15 | Task RemoveErrLogAsync(string jobGroup, string jobName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositorieFactory.cs: -------------------------------------------------------------------------------- 1 | using Quartz.Impl.AdoJobStore; 2 | using Quartz.Impl.AdoJobStore.Common; 3 | 4 | namespace Host.Repositories 5 | { 6 | public class RepositorieFactory 7 | { 8 | public static IRepositorie CreateRepositorie(string driverDelegateType, IDbProvider dbProvider) 9 | { 10 | 11 | if (driverDelegateType == typeof(SQLiteDelegate).AssemblyQualifiedName) 12 | { 13 | return new RepositorieSQLite(dbProvider); 14 | } 15 | else if (driverDelegateType == typeof(MySQLDelegate).AssemblyQualifiedName) 16 | { 17 | return new RepositorieMySql(dbProvider); 18 | } 19 | else if (driverDelegateType == typeof(PostgreSQLDelegate).AssemblyQualifiedName) 20 | { 21 | return new RepositoriePostgreSQL(dbProvider); 22 | } 23 | else if (driverDelegateType == typeof(OracleDelegate).AssemblyQualifiedName) 24 | { 25 | return new RepositorieOracle(dbProvider); 26 | } 27 | else if (driverDelegateType == typeof(SqlServerDelegate).AssemblyQualifiedName) 28 | { 29 | return new RepositorieSqlServer(dbProvider); 30 | } 31 | else 32 | { 33 | return null; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositorieMySql.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Host.Common; 3 | using MySql.Data.MySqlClient; 4 | using Newtonsoft.Json.Linq; 5 | using Quartz.Impl.AdoJobStore.Common; 6 | using System.IO; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Host.Repositories 11 | { 12 | public class RepositorieMySql : IRepositorie 13 | { 14 | private IDbProvider DBProvider { get; } 15 | public RepositorieMySql(IDbProvider dbProvider) 16 | { 17 | DBProvider = dbProvider; 18 | } 19 | 20 | public async Task InitTable() 21 | { 22 | using (var connection = new MySqlConnection(DBProvider.ConnectionString)) 23 | { 24 | var check_sql = @"SELECT 25 | COUNT(1) 26 | FROM 27 | information_schema. TABLES 28 | WHERE 29 | table_name IN ( 30 | 'QRTZ_BLOB_TRIGGERS', 31 | 'QRTZ_CALENDARS', 32 | 'QRTZ_CRON_TRIGGERS', 33 | 'QRTZ_FIRED_TRIGGERS', 34 | 'QRTZ_JOB_DETAILS', 35 | 'QRTZ_LOCKS', 36 | 'QRTZ_PAUSED_TRIGGER_GRPS', 37 | 'QRTZ_SCHEDULER_STATE', 38 | 'QRTZ_SIMPLE_TRIGGERS', 39 | 'QRTZ_SIMPROP_TRIGGERS', 40 | 'QRTZ_TRIGGERS' 41 | );"; 42 | var count = await connection.QueryFirstOrDefaultAsync(check_sql); 43 | //初始化 建表 44 | if (count == 0) 45 | { 46 | string init_sql = await File.ReadAllTextAsync("Tables/tables_mysql_innodb.sql"); 47 | return await connection.ExecuteAsync(init_sql); 48 | } 49 | } 50 | return 0; 51 | } 52 | 53 | public async Task RemoveErrLogAsync(string jobGroup, string jobName) 54 | { 55 | try 56 | { 57 | using (var connection = new MySqlConnection(DBProvider.ConnectionString)) 58 | { 59 | string sql = $@"SELECT 60 | JOB_DATA 61 | FROM 62 | QRTZ_JOB_DETAILS 63 | WHERE 64 | JOB_NAME = @jobName 65 | AND JOB_GROUP = @jobGroup"; 66 | 67 | var byteArray = await connection.ExecuteScalarAsync(sql, new { jobName, jobGroup }); 68 | var jsonStr = Encoding.Default.GetString(byteArray); 69 | JObject source = JObject.Parse(jsonStr); 70 | source.Remove("Exception");//移除异常日志 71 | var modifySql = $@"UPDATE QRTZ_JOB_DETAILS 72 | SET JOB_DATA = @jobData 73 | WHERE 74 | JOB_NAME = @jobName 75 | AND JOB_GROUP = @jobGroup"; 76 | await connection.ExecuteAsync(modifySql, new { jobName, jobGroup, jobData = source.ToString() }); 77 | } 78 | 79 | return true; 80 | } 81 | catch 82 | { 83 | return false; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositorieOracle.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Newtonsoft.Json.Linq; 3 | using Oracle.ManagedDataAccess.Client; 4 | using Quartz.Impl.AdoJobStore.Common; 5 | using System; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Host.Repositories 10 | { 11 | public class RepositorieOracle : IRepositorie 12 | { 13 | private IDbProvider DBProvider { get; } 14 | 15 | public RepositorieOracle(IDbProvider dbProvider) 16 | { 17 | DBProvider = dbProvider; 18 | } 19 | 20 | public async Task RemoveErrLogAsync(string jobGroup, string jobName) 21 | { 22 | try 23 | { 24 | using (var connection = new OracleConnection(DBProvider.ConnectionString)) 25 | { 26 | string sql = $@"SELECT 27 | JOB_DATA 28 | FROM 29 | QRTZ_JOB_DETAILS 30 | WHERE 31 | JOB_NAME = :jobName 32 | AND JOB_GROUP = :jobGroup"; 33 | 34 | var byteArray = await connection.ExecuteScalarAsync(sql, new { jobName, jobGroup }); 35 | var jsonStr = Encoding.UTF8.GetString(byteArray); 36 | JObject source = JObject.Parse(jsonStr); 37 | source.Remove("Exception");//移除异常日志 38 | var modifySql = $@"UPDATE QRTZ_JOB_DETAILS 39 | SET JOB_DATA = :jobData 40 | WHERE 41 | JOB_NAME = :jobName 42 | AND JOB_GROUP = :jobGroup"; 43 | await connection.ExecuteAsync(modifySql, new { jobName, jobGroup, jobData = Encoding.UTF8.GetBytes(source.ToString()) }); 44 | } 45 | return true; 46 | } 47 | catch (Exception ex) 48 | { 49 | return false; 50 | } 51 | } 52 | 53 | public Task InitTable() 54 | { 55 | //TODO 待实现... 56 | return Task.FromResult(-1); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositoriePostgreSQL.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Host.Common; 3 | using Newtonsoft.Json.Linq; 4 | using Npgsql; 5 | using Quartz.Impl.AdoJobStore.Common; 6 | using System; 7 | using System.IO; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Host.Repositories 12 | { 13 | public class RepositoriePostgreSQL : IRepositorie 14 | { 15 | private IDbProvider DBProvider { get; } 16 | public RepositoriePostgreSQL(IDbProvider dbProvider) 17 | { 18 | DBProvider = dbProvider; 19 | } 20 | 21 | public async Task InitTable() 22 | { 23 | using (var connection = new NpgsqlConnection(DBProvider.ConnectionString)) 24 | { 25 | var check_sql = @"SELECT 26 | COUNT (1) 27 | FROM 28 | pg_class 29 | WHERE 30 | relname IN ( 31 | 'qrtz_blob_triggers', 32 | 'qrtz_calendars', 33 | 'qrtz_cron_triggers', 34 | 'qrtz_fired_triggers', 35 | 'qrtz_job_details', 36 | 'qrtz_locks', 37 | 'qrtz_paused_trigger_grps', 38 | 'qrtz_scheduler_state', 39 | 'qrtz_simple_triggers', 40 | 'qrtz_simprop_triggers', 41 | 'qrtz_triggers' 42 | );"; 43 | var count = await connection.QueryFirstOrDefaultAsync(check_sql); 44 | //初始化 建表 45 | if (count == 0) 46 | { 47 | string init_sql = await File.ReadAllTextAsync("Tables/tables_postgres.sql"); 48 | return await connection.ExecuteAsync(init_sql); 49 | } 50 | } 51 | return 0; 52 | } 53 | 54 | public async Task RemoveErrLogAsync(string jobGroup, string jobName) 55 | { 56 | try 57 | { 58 | using (var connection = new NpgsqlConnection(DBProvider.ConnectionString)) 59 | { 60 | string sql = $@"SELECT 61 | JOB_DATA 62 | FROM 63 | QRTZ_JOB_DETAILS 64 | WHERE 65 | JOB_NAME = @jobName 66 | AND JOB_GROUP = @jobGroup"; 67 | 68 | var byteArray = await connection.ExecuteScalarAsync(sql, new { jobName, jobGroup }); 69 | var jsonStr = Encoding.Default.GetString(byteArray); 70 | JObject source = JObject.Parse(jsonStr); 71 | source.Remove("Exception");//移除异常日志 72 | var modifySql = $@"UPDATE QRTZ_JOB_DETAILS 73 | SET JOB_DATA = @jobData 74 | WHERE 75 | JOB_NAME = @jobName 76 | AND JOB_GROUP = @jobGroup"; 77 | await connection.ExecuteAsync(modifySql, new { jobName, jobGroup, jobData = Encoding.Default.GetBytes(source.ToString()) }); 78 | } 79 | 80 | return true; 81 | } 82 | catch (Exception ex) 83 | { 84 | return false; 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositorieSQLite.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Host.Common; 3 | using Microsoft.Data.Sqlite; 4 | using Newtonsoft.Json.Linq; 5 | using Quartz.Impl.AdoJobStore.Common; 6 | using System.IO; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Host.Repositories 11 | { 12 | public class RepositorieSQLite : IRepositorie 13 | { 14 | private IDbProvider DBProvider { get; } 15 | 16 | public RepositorieSQLite(IDbProvider dbProvider) 17 | { 18 | DBProvider = dbProvider; 19 | } 20 | 21 | public async Task InitTable() 22 | { 23 | if (!Directory.Exists("File")) Directory.CreateDirectory("File"); 24 | 25 | using (var connection = new SqliteConnection(DBProvider.ConnectionString)) 26 | { 27 | var check_sql = @$"SELECT 28 | count(1) 29 | FROM 30 | sqlite_master 31 | WHERE 32 | type = 'table' 33 | AND name IN ( 34 | 'QRTZ_JOB_DETAILS', 35 | 'QRTZ_TRIGGERS', 36 | 'QRTZ_SIMPLE_TRIGGERS', 37 | 'QRTZ_SIMPROP_TRIGGERS', 38 | 'QRTZ_CRON_TRIGGERS', 39 | 'QRTZ_BLOB_TRIGGERS', 40 | 'QRTZ_CALENDARS', 41 | 'QRTZ_PAUSED_TRIGGER_GRPS', 42 | 'QRTZ_FIRED_TRIGGERS', 43 | 'QRTZ_SCHEDULER_STATE', 44 | 'QRTZ_LOCKS' 45 | );"; 46 | var count = await connection.QueryFirstOrDefaultAsync(check_sql); 47 | //初始化 建表 48 | if (count == 0) 49 | { 50 | string init_sql = await File.ReadAllTextAsync("Tables/tables_sqlite.sql"); 51 | return await connection.ExecuteAsync(init_sql); 52 | } 53 | } 54 | return 0; 55 | } 56 | public async Task RemoveErrLogAsync(string jobGroup, string jobName) 57 | { 58 | try 59 | { 60 | using (var connection = new SqliteConnection(DBProvider.ConnectionString)) 61 | { 62 | string sql = $@"SELECT 63 | JOB_DATA 64 | FROM 65 | QRTZ_JOB_DETAILS 66 | WHERE 67 | JOB_NAME = @jobName 68 | AND JOB_GROUP = @jobGroup"; 69 | 70 | var byteArray = await connection.ExecuteScalarAsync(sql, new { jobName, jobGroup }); 71 | var jsonStr = Encoding.Default.GetString(byteArray); 72 | JObject source = JObject.Parse(jsonStr); 73 | source.Remove("Exception");//移除异常日志 74 | var modifySql = $@"UPDATE QRTZ_JOB_DETAILS 75 | SET JOB_DATA = @jobData 76 | WHERE 77 | JOB_NAME = @jobName 78 | AND JOB_GROUP = @jobGroup"; 79 | await connection.ExecuteAsync(modifySql, new { jobName, jobGroup, jobData = source.ToString() }); 80 | } 81 | 82 | return true; 83 | } 84 | catch 85 | { 86 | return false; 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Repositories/RepositorieSqlServer.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Microsoft.Data.SqlClient; 3 | using Newtonsoft.Json.Linq; 4 | using Quartz.Impl.AdoJobStore.Common; 5 | using System; 6 | using System.IO; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Host.Repositories 11 | { 12 | public class RepositorieSqlServer : IRepositorie 13 | { 14 | private IDbProvider DBProvider { get; } 15 | public RepositorieSqlServer(IDbProvider dbProvider) 16 | { 17 | DBProvider = dbProvider; 18 | } 19 | 20 | public async Task InitTable() 21 | { 22 | using (var connection = new SqlConnection(DBProvider.ConnectionString)) 23 | { 24 | var check_sql = @"SELECT 25 | COUNT (1) 26 | FROM 27 | sys.tables 28 | WHERE 29 | name IN ( 30 | 'QRTZ_BLOB_TRIGGERS', 31 | 'QRTZ_CALENDARS', 32 | 'QRTZ_CRON_TRIGGERS', 33 | 'QRTZ_FIRED_TRIGGERS', 34 | 'QRTZ_JOB_DETAILS', 35 | 'QRTZ_LOCKS', 36 | 'QRTZ_PAUSED_TRIGGER_GRPS', 37 | 'QRTZ_SCHEDULER_STATE', 38 | 'QRTZ_SIMPLE_TRIGGERS', 39 | 'QRTZ_SIMPROP_TRIGGERS', 40 | 'QRTZ_TRIGGERS' 41 | );"; 42 | var count = await connection.QueryFirstOrDefaultAsync(check_sql); 43 | //初始化 建表 44 | if (count == 0) 45 | { 46 | string init_sql = await File.ReadAllTextAsync("Tables/tables_sqlServer.sql"); 47 | return await connection.ExecuteAsync(init_sql); 48 | } 49 | } 50 | return 0; 51 | } 52 | 53 | public async Task RemoveErrLogAsync(string jobGroup, string jobName) 54 | { 55 | try 56 | { 57 | using (var connection = new SqlConnection(DBProvider.ConnectionString)) 58 | { 59 | string sql = $@"SELECT 60 | JOB_DATA 61 | FROM 62 | QRTZ_JOB_DETAILS 63 | WHERE 64 | JOB_NAME = @jobName 65 | AND JOB_GROUP = @jobGroup"; 66 | 67 | var byteArray = await connection.ExecuteScalarAsync(sql, new { jobName, jobGroup }); 68 | var jsonStr = Encoding.Default.GetString(byteArray); 69 | JObject source = JObject.Parse(jsonStr); 70 | source.Remove("Exception");//移除异常日志 71 | var modifySql = $@"UPDATE QRTZ_JOB_DETAILS 72 | SET JOB_DATA = @jobData 73 | WHERE 74 | JOB_NAME = @jobName 75 | AND JOB_GROUP = @jobGroup"; 76 | await connection.ExecuteAsync(modifySql, new { jobName, jobGroup, jobData = Encoding.Default.GetBytes(source.ToString()) }); 77 | } 78 | 79 | return true; 80 | } 81 | catch (Exception ex) 82 | { 83 | return false; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/ScheduleManage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host 7 | { 8 | public class ScheduleManage 9 | { 10 | internal ScheduleEntity GetScheduleModel(string jobGroup, string jobName) 11 | { 12 | throw new NotImplementedException(); 13 | } 14 | 15 | internal void UpdateScheduleStatus(ScheduleEntity scheduleModel) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | 20 | internal void RemoveScheduleModel(string jobGroup, string jobName) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Services/HostedService.cs: -------------------------------------------------------------------------------- 1 | using Host.Managers; 2 | using Microsoft.Extensions.Hosting; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Host.Services 7 | { 8 | public class HostedService : IHostedService 9 | { 10 | private SchedulerCenter schedulerCenter; 11 | private MqttManager mqttManager; 12 | public HostedService(SchedulerCenter schedulerCenter) 13 | { 14 | this.schedulerCenter = schedulerCenter; 15 | mqttManager = MqttManager.Instance; 16 | } 17 | 18 | public async Task StartAsync(CancellationToken cancellationToken) 19 | { 20 | //开启调度器 21 | await schedulerCenter.StartScheduleAsync(); 22 | 23 | //启动mqtt 24 | await mqttManager.RestartAsync(); 25 | 26 | //启动Rabbit 27 | await RabbitMQManager.Instance.RestartAsync(); 28 | } 29 | 30 | public Task StopAsync(CancellationToken cancellationToken) 31 | { 32 | return Task.CompletedTask; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Tables/tables_mysql_innodb.sql: -------------------------------------------------------------------------------- 1 | # By: Ron Cordell - roncordell 2 | # I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM. 3 | 4 | 5 | # make sure you have UTF-8 collaction for best .NET interoperability 6 | # CREATE DATABASE quartznet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 7 | 8 | DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; 9 | DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; 10 | DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; 11 | DROP TABLE IF EXISTS QRTZ_LOCKS; 12 | DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; 13 | DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; 14 | DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; 15 | DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; 16 | DROP TABLE IF EXISTS QRTZ_TRIGGERS; 17 | DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; 18 | DROP TABLE IF EXISTS QRTZ_CALENDARS; 19 | 20 | CREATE TABLE QRTZ_JOB_DETAILS( 21 | SCHED_NAME VARCHAR(120) NOT NULL, 22 | JOB_NAME VARCHAR(200) NOT NULL, 23 | JOB_GROUP VARCHAR(200) NOT NULL, 24 | DESCRIPTION VARCHAR(250) NULL, 25 | JOB_CLASS_NAME VARCHAR(250) NOT NULL, 26 | IS_DURABLE BOOLEAN NOT NULL, 27 | IS_NONCONCURRENT BOOLEAN NOT NULL, 28 | IS_UPDATE_DATA BOOLEAN NOT NULL, 29 | REQUESTS_RECOVERY BOOLEAN NOT NULL, 30 | JOB_DATA BLOB NULL, 31 | PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)) 32 | ENGINE=InnoDB; 33 | 34 | CREATE TABLE QRTZ_TRIGGERS ( 35 | SCHED_NAME VARCHAR(120) NOT NULL, 36 | TRIGGER_NAME VARCHAR(200) NOT NULL, 37 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 38 | JOB_NAME VARCHAR(200) NOT NULL, 39 | JOB_GROUP VARCHAR(200) NOT NULL, 40 | DESCRIPTION VARCHAR(250) NULL, 41 | NEXT_FIRE_TIME BIGINT(19) NULL, 42 | PREV_FIRE_TIME BIGINT(19) NULL, 43 | PRIORITY INTEGER NULL, 44 | TRIGGER_STATE VARCHAR(16) NOT NULL, 45 | TRIGGER_TYPE VARCHAR(8) NOT NULL, 46 | START_TIME BIGINT(19) NOT NULL, 47 | END_TIME BIGINT(19) NULL, 48 | CALENDAR_NAME VARCHAR(200) NULL, 49 | MISFIRE_INSTR SMALLINT(2) NULL, 50 | JOB_DATA BLOB NULL, 51 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 52 | FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) 53 | REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)) 54 | ENGINE=InnoDB; 55 | 56 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( 57 | SCHED_NAME VARCHAR(120) NOT NULL, 58 | TRIGGER_NAME VARCHAR(200) NOT NULL, 59 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 60 | REPEAT_COUNT BIGINT(7) NOT NULL, 61 | REPEAT_INTERVAL BIGINT(12) NOT NULL, 62 | TIMES_TRIGGERED BIGINT(10) NOT NULL, 63 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 64 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 65 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) 66 | ENGINE=InnoDB; 67 | 68 | CREATE TABLE QRTZ_CRON_TRIGGERS ( 69 | SCHED_NAME VARCHAR(120) NOT NULL, 70 | TRIGGER_NAME VARCHAR(200) NOT NULL, 71 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 72 | CRON_EXPRESSION VARCHAR(120) NOT NULL, 73 | TIME_ZONE_ID VARCHAR(80), 74 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 75 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 76 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) 77 | ENGINE=InnoDB; 78 | 79 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS 80 | ( 81 | SCHED_NAME VARCHAR(120) NOT NULL, 82 | TRIGGER_NAME VARCHAR(200) NOT NULL, 83 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 84 | STR_PROP_1 VARCHAR(512) NULL, 85 | STR_PROP_2 VARCHAR(512) NULL, 86 | STR_PROP_3 VARCHAR(512) NULL, 87 | INT_PROP_1 INT NULL, 88 | INT_PROP_2 INT NULL, 89 | LONG_PROP_1 BIGINT NULL, 90 | LONG_PROP_2 BIGINT NULL, 91 | DEC_PROP_1 NUMERIC(13,4) NULL, 92 | DEC_PROP_2 NUMERIC(13,4) NULL, 93 | BOOL_PROP_1 BOOLEAN NULL, 94 | BOOL_PROP_2 BOOLEAN NULL, 95 | TIME_ZONE_ID VARCHAR(80) NULL, 96 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 97 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 98 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) 99 | ENGINE=InnoDB; 100 | 101 | CREATE TABLE QRTZ_BLOB_TRIGGERS ( 102 | SCHED_NAME VARCHAR(120) NOT NULL, 103 | TRIGGER_NAME VARCHAR(200) NOT NULL, 104 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 105 | BLOB_DATA BLOB NULL, 106 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 107 | INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP), 108 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 109 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) 110 | ENGINE=InnoDB; 111 | 112 | CREATE TABLE QRTZ_CALENDARS ( 113 | SCHED_NAME VARCHAR(120) NOT NULL, 114 | CALENDAR_NAME VARCHAR(200) NOT NULL, 115 | CALENDAR BLOB NOT NULL, 116 | PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)) 117 | ENGINE=InnoDB; 118 | 119 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( 120 | SCHED_NAME VARCHAR(120) NOT NULL, 121 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 122 | PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)) 123 | ENGINE=InnoDB; 124 | 125 | CREATE TABLE QRTZ_FIRED_TRIGGERS ( 126 | SCHED_NAME VARCHAR(120) NOT NULL, 127 | ENTRY_ID VARCHAR(140) NOT NULL, 128 | TRIGGER_NAME VARCHAR(200) NOT NULL, 129 | TRIGGER_GROUP VARCHAR(200) NOT NULL, 130 | INSTANCE_NAME VARCHAR(200) NOT NULL, 131 | FIRED_TIME BIGINT(19) NOT NULL, 132 | SCHED_TIME BIGINT(19) NOT NULL, 133 | PRIORITY INTEGER NOT NULL, 134 | STATE VARCHAR(16) NOT NULL, 135 | JOB_NAME VARCHAR(200) NULL, 136 | JOB_GROUP VARCHAR(200) NULL, 137 | IS_NONCONCURRENT BOOLEAN NULL, 138 | REQUESTS_RECOVERY BOOLEAN NULL, 139 | PRIMARY KEY (SCHED_NAME,ENTRY_ID)) 140 | ENGINE=InnoDB; 141 | 142 | CREATE TABLE QRTZ_SCHEDULER_STATE ( 143 | SCHED_NAME VARCHAR(120) NOT NULL, 144 | INSTANCE_NAME VARCHAR(200) NOT NULL, 145 | LAST_CHECKIN_TIME BIGINT(19) NOT NULL, 146 | CHECKIN_INTERVAL BIGINT(19) NOT NULL, 147 | PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)) 148 | ENGINE=InnoDB; 149 | 150 | CREATE TABLE QRTZ_LOCKS ( 151 | SCHED_NAME VARCHAR(120) NOT NULL, 152 | LOCK_NAME VARCHAR(40) NOT NULL, 153 | PRIMARY KEY (SCHED_NAME,LOCK_NAME)) 154 | ENGINE=InnoDB; 155 | 156 | CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY); 157 | CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); 158 | 159 | CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); 160 | CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP); 161 | CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME); 162 | CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); 163 | CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE); 164 | CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); 165 | CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); 166 | CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME); 167 | CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); 168 | CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); 169 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); 170 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); 171 | 172 | CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME); 173 | CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); 174 | CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); 175 | CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP); 176 | CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); 177 | CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); 178 | 179 | commit; 180 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Tables/tables_postgres.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS qrtz_fired_triggers; 2 | DROP TABLE IF EXISTS qrtz_paused_trigger_grps; 3 | DROP TABLE IF EXISTS qrtz_scheduler_state; 4 | DROP TABLE IF EXISTS qrtz_locks; 5 | DROP TABLE IF EXISTS qrtz_simprop_triggers; 6 | DROP TABLE IF EXISTS qrtz_simple_triggers; 7 | DROP TABLE IF EXISTS qrtz_cron_triggers; 8 | DROP TABLE IF EXISTS qrtz_blob_triggers; 9 | DROP TABLE IF EXISTS qrtz_triggers; 10 | DROP TABLE IF EXISTS qrtz_job_details; 11 | DROP TABLE IF EXISTS qrtz_calendars; 12 | 13 | 14 | CREATE TABLE qrtz_job_details 15 | ( 16 | sched_name VARCHAR(120) NOT NULL, 17 | job_name VARCHAR(200) NOT NULL, 18 | job_group VARCHAR(200) NOT NULL, 19 | description VARCHAR(250) NULL, 20 | job_class_name VARCHAR(250) NOT NULL, 21 | is_durable BOOL NOT NULL, 22 | is_nonconcurrent BOOL NOT NULL, 23 | is_update_data BOOL NOT NULL, 24 | requests_recovery BOOL NOT NULL, 25 | job_data BYTEA NULL, 26 | PRIMARY KEY (sched_name,job_name,job_group) 27 | ); 28 | 29 | CREATE TABLE qrtz_triggers 30 | ( 31 | sched_name VARCHAR(120) NOT NULL, 32 | trigger_name VARCHAR(150) NOT NULL, 33 | trigger_group VARCHAR(150) NOT NULL, 34 | job_name VARCHAR(200) NOT NULL, 35 | job_group VARCHAR(200) NOT NULL, 36 | description VARCHAR(250) NULL, 37 | next_fire_time BIGINT NULL, 38 | prev_fire_time BIGINT NULL, 39 | priority INTEGER NULL, 40 | trigger_state VARCHAR(16) NOT NULL, 41 | trigger_type VARCHAR(8) NOT NULL, 42 | start_time BIGINT NOT NULL, 43 | end_time BIGINT NULL, 44 | calendar_name VARCHAR(200) NULL, 45 | misfire_instr SMALLINT NULL, 46 | job_data BYTEA NULL, 47 | PRIMARY KEY (sched_name,trigger_name,trigger_group), 48 | FOREIGN KEY (sched_name,job_name,job_group) 49 | REFERENCES qrtz_job_details(sched_name,job_name,job_group) 50 | ); 51 | 52 | CREATE TABLE qrtz_simple_triggers 53 | ( 54 | sched_name VARCHAR(120) NOT NULL, 55 | trigger_name VARCHAR(150) NOT NULL, 56 | trigger_group VARCHAR(150) NOT NULL, 57 | repeat_count BIGINT NOT NULL, 58 | repeat_interval BIGINT NOT NULL, 59 | times_triggered BIGINT NOT NULL, 60 | PRIMARY KEY (sched_name,trigger_name,trigger_group), 61 | FOREIGN KEY (sched_name,trigger_name,trigger_group) 62 | REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE 63 | ); 64 | 65 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS 66 | ( 67 | sched_name VARCHAR (120) NOT NULL, 68 | trigger_name VARCHAR (150) NOT NULL , 69 | trigger_group VARCHAR (150) NOT NULL , 70 | str_prop_1 VARCHAR (512) NULL, 71 | str_prop_2 VARCHAR (512) NULL, 72 | str_prop_3 VARCHAR (512) NULL, 73 | int_prop_1 INTEGER NULL, 74 | int_prop_2 INTEGER NULL, 75 | long_prop_1 BIGINT NULL, 76 | long_prop_2 BIGINT NULL, 77 | dec_prop_1 NUMERIC NULL, 78 | dec_prop_2 NUMERIC NULL, 79 | bool_prop_1 BOOL NULL, 80 | bool_prop_2 BOOL NULL, 81 | time_zone_id VARCHAR(80) NULL, 82 | PRIMARY KEY (sched_name,trigger_name,trigger_group), 83 | FOREIGN KEY (sched_name,trigger_name,trigger_group) 84 | REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE 85 | ); 86 | 87 | CREATE TABLE qrtz_cron_triggers 88 | ( 89 | sched_name VARCHAR (120) NOT NULL, 90 | trigger_name VARCHAR(150) NOT NULL, 91 | trigger_group VARCHAR(150) NOT NULL, 92 | cron_expression VARCHAR(250) NOT NULL, 93 | time_zone_id VARCHAR(80), 94 | PRIMARY KEY (sched_name,trigger_name,trigger_group), 95 | FOREIGN KEY (sched_name,trigger_name,trigger_group) 96 | REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE 97 | ); 98 | 99 | CREATE TABLE qrtz_blob_triggers 100 | ( 101 | sched_name VARCHAR (120) NOT NULL, 102 | trigger_name VARCHAR(150) NOT NULL, 103 | trigger_group VARCHAR(150) NOT NULL, 104 | blob_data BYTEA NULL, 105 | PRIMARY KEY (sched_name,trigger_name,trigger_group), 106 | FOREIGN KEY (sched_name,trigger_name,trigger_group) 107 | REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group) ON DELETE CASCADE 108 | ); 109 | 110 | CREATE TABLE qrtz_calendars 111 | ( 112 | sched_name VARCHAR (120) NOT NULL, 113 | calendar_name VARCHAR(200) NOT NULL, 114 | calendar BYTEA NOT NULL, 115 | PRIMARY KEY (sched_name,calendar_name) 116 | ); 117 | 118 | CREATE TABLE qrtz_paused_trigger_grps 119 | ( 120 | sched_name VARCHAR (120) NOT NULL, 121 | trigger_group VARCHAR(150) NOT NULL, 122 | PRIMARY KEY (sched_name,trigger_group) 123 | ); 124 | 125 | CREATE TABLE qrtz_fired_triggers 126 | ( 127 | sched_name VARCHAR (120) NOT NULL, 128 | entry_id VARCHAR(140) NOT NULL, 129 | trigger_name VARCHAR(150) NOT NULL, 130 | trigger_group VARCHAR(150) NOT NULL, 131 | instance_name VARCHAR(200) NOT NULL, 132 | fired_time BIGINT NOT NULL, 133 | sched_time BIGINT NOT NULL, 134 | priority INTEGER NOT NULL, 135 | state VARCHAR(16) NOT NULL, 136 | job_name VARCHAR(200) NULL, 137 | job_group VARCHAR(200) NULL, 138 | is_nonconcurrent BOOL NOT NULL, 139 | requests_recovery BOOL NULL, 140 | PRIMARY KEY (sched_name,entry_id) 141 | ); 142 | 143 | CREATE TABLE qrtz_scheduler_state 144 | ( 145 | sched_name VARCHAR (120) NOT NULL, 146 | instance_name VARCHAR(200) NOT NULL, 147 | last_checkin_time BIGINT NOT NULL, 148 | checkin_interval BIGINT NOT NULL, 149 | PRIMARY KEY (sched_name,instance_name) 150 | ); 151 | 152 | CREATE TABLE qrtz_locks 153 | ( 154 | sched_name VARCHAR (120) NOT NULL, 155 | lock_name VARCHAR(40) NOT NULL, 156 | PRIMARY KEY (sched_name,lock_name) 157 | ); 158 | 159 | create index idx_qrtz_j_req_recovery on qrtz_job_details(requests_recovery); 160 | create index idx_qrtz_t_next_fire_time on qrtz_triggers(next_fire_time); 161 | create index idx_qrtz_t_state on qrtz_triggers(trigger_state); 162 | create index idx_qrtz_t_nft_st on qrtz_triggers(next_fire_time,trigger_state); 163 | create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(trigger_name); 164 | create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(trigger_group); 165 | create index idx_qrtz_ft_trig_nm_gp on qrtz_fired_triggers(sched_name,trigger_name,trigger_group); 166 | create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(instance_name); 167 | create index idx_qrtz_ft_job_name on qrtz_fired_triggers(job_name); 168 | create index idx_qrtz_ft_job_group on qrtz_fired_triggers(job_group); 169 | create index idx_qrtz_ft_job_req_recovery on qrtz_fired_triggers(requests_recovery); -------------------------------------------------------------------------------- /QuartzNetAPI/Host/Tables/tables_sqlite.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; 2 | DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; 3 | DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; 4 | DROP TABLE IF EXISTS QRTZ_LOCKS; 5 | DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; 6 | DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; 7 | DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; 8 | DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; 9 | DROP TABLE IF EXISTS QRTZ_TRIGGERS; 10 | DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; 11 | DROP TABLE IF EXISTS QRTZ_CALENDARS; 12 | 13 | 14 | CREATE TABLE QRTZ_JOB_DETAILS 15 | ( 16 | SCHED_NAME NVARCHAR(120) NOT NULL, 17 | JOB_NAME NVARCHAR(150) NOT NULL, 18 | JOB_GROUP NVARCHAR(150) NOT NULL, 19 | DESCRIPTION NVARCHAR(250) NULL, 20 | JOB_CLASS_NAME NVARCHAR(250) NOT NULL, 21 | IS_DURABLE BIT NOT NULL, 22 | IS_NONCONCURRENT BIT NOT NULL, 23 | IS_UPDATE_DATA BIT NOT NULL, 24 | REQUESTS_RECOVERY BIT NOT NULL, 25 | JOB_DATA BLOB NULL, 26 | PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) 27 | ); 28 | 29 | CREATE TABLE QRTZ_TRIGGERS 30 | ( 31 | SCHED_NAME NVARCHAR(120) NOT NULL, 32 | TRIGGER_NAME NVARCHAR(150) NOT NULL, 33 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 34 | JOB_NAME NVARCHAR(150) NOT NULL, 35 | JOB_GROUP NVARCHAR(150) NOT NULL, 36 | DESCRIPTION NVARCHAR(250) NULL, 37 | NEXT_FIRE_TIME BIGINT NULL, 38 | PREV_FIRE_TIME BIGINT NULL, 39 | PRIORITY INTEGER NULL, 40 | TRIGGER_STATE NVARCHAR(16) NOT NULL, 41 | TRIGGER_TYPE NVARCHAR(8) NOT NULL, 42 | START_TIME BIGINT NOT NULL, 43 | END_TIME BIGINT NULL, 44 | CALENDAR_NAME NVARCHAR(200) NULL, 45 | MISFIRE_INSTR INTEGER NULL, 46 | JOB_DATA BLOB NULL, 47 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 48 | FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) 49 | REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) 50 | ); 51 | 52 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS 53 | ( 54 | SCHED_NAME NVARCHAR(120) NOT NULL, 55 | TRIGGER_NAME NVARCHAR(150) NOT NULL, 56 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 57 | REPEAT_COUNT BIGINT NOT NULL, 58 | REPEAT_INTERVAL BIGINT NOT NULL, 59 | TIMES_TRIGGERED BIGINT NOT NULL, 60 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 61 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 62 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ON DELETE CASCADE 63 | ); 64 | 65 | CREATE TRIGGER DELETE_SIMPLE_TRIGGER DELETE ON QRTZ_TRIGGERS 66 | BEGIN 67 | DELETE FROM QRTZ_SIMPLE_TRIGGERS WHERE SCHED_NAME=OLD.SCHED_NAME AND TRIGGER_NAME=OLD.TRIGGER_NAME AND TRIGGER_GROUP=OLD.TRIGGER_GROUP; 68 | END 69 | ; 70 | 71 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS 72 | ( 73 | SCHED_NAME NVARCHAR (120) NOT NULL , 74 | TRIGGER_NAME NVARCHAR (150) NOT NULL , 75 | TRIGGER_GROUP NVARCHAR (150) NOT NULL , 76 | STR_PROP_1 NVARCHAR (512) NULL, 77 | STR_PROP_2 NVARCHAR (512) NULL, 78 | STR_PROP_3 NVARCHAR (512) NULL, 79 | INT_PROP_1 INT NULL, 80 | INT_PROP_2 INT NULL, 81 | LONG_PROP_1 BIGINT NULL, 82 | LONG_PROP_2 BIGINT NULL, 83 | DEC_PROP_1 NUMERIC NULL, 84 | DEC_PROP_2 NUMERIC NULL, 85 | BOOL_PROP_1 BIT NULL, 86 | BOOL_PROP_2 BIT NULL, 87 | TIME_ZONE_ID NVARCHAR(80) NULL, 88 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 89 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 90 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ON DELETE CASCADE 91 | ); 92 | 93 | CREATE TRIGGER DELETE_SIMPROP_TRIGGER DELETE ON QRTZ_TRIGGERS 94 | BEGIN 95 | DELETE FROM QRTZ_SIMPROP_TRIGGERS WHERE SCHED_NAME=OLD.SCHED_NAME AND TRIGGER_NAME=OLD.TRIGGER_NAME AND TRIGGER_GROUP=OLD.TRIGGER_GROUP; 96 | END 97 | ; 98 | 99 | CREATE TABLE QRTZ_CRON_TRIGGERS 100 | ( 101 | SCHED_NAME NVARCHAR(120) NOT NULL, 102 | TRIGGER_NAME NVARCHAR(150) NOT NULL, 103 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 104 | CRON_EXPRESSION NVARCHAR(250) NOT NULL, 105 | TIME_ZONE_ID NVARCHAR(80), 106 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 107 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 108 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ON DELETE CASCADE 109 | ); 110 | 111 | CREATE TRIGGER DELETE_CRON_TRIGGER DELETE ON QRTZ_TRIGGERS 112 | BEGIN 113 | DELETE FROM QRTZ_CRON_TRIGGERS WHERE SCHED_NAME=OLD.SCHED_NAME AND TRIGGER_NAME=OLD.TRIGGER_NAME AND TRIGGER_GROUP=OLD.TRIGGER_GROUP; 114 | END 115 | ; 116 | 117 | CREATE TABLE QRTZ_BLOB_TRIGGERS 118 | ( 119 | SCHED_NAME NVARCHAR(120) NOT NULL, 120 | TRIGGER_NAME NVARCHAR(150) NOT NULL, 121 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 122 | BLOB_DATA BLOB NULL, 123 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), 124 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 125 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ON DELETE CASCADE 126 | ); 127 | 128 | CREATE TRIGGER DELETE_BLOB_TRIGGER DELETE ON QRTZ_TRIGGERS 129 | BEGIN 130 | DELETE FROM QRTZ_BLOB_TRIGGERS WHERE SCHED_NAME=OLD.SCHED_NAME AND TRIGGER_NAME=OLD.TRIGGER_NAME AND TRIGGER_GROUP=OLD.TRIGGER_GROUP; 131 | END 132 | ; 133 | 134 | CREATE TABLE QRTZ_CALENDARS 135 | ( 136 | SCHED_NAME NVARCHAR(120) NOT NULL, 137 | CALENDAR_NAME NVARCHAR(200) NOT NULL, 138 | CALENDAR BLOB NOT NULL, 139 | PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) 140 | ); 141 | 142 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS 143 | ( 144 | SCHED_NAME NVARCHAR(120) NOT NULL, 145 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 146 | PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) 147 | ); 148 | 149 | CREATE TABLE QRTZ_FIRED_TRIGGERS 150 | ( 151 | SCHED_NAME NVARCHAR(120) NOT NULL, 152 | ENTRY_ID NVARCHAR(140) NOT NULL, 153 | TRIGGER_NAME NVARCHAR(150) NOT NULL, 154 | TRIGGER_GROUP NVARCHAR(150) NOT NULL, 155 | INSTANCE_NAME NVARCHAR(200) NOT NULL, 156 | FIRED_TIME BIGINT NOT NULL, 157 | SCHED_TIME BIGINT NOT NULL, 158 | PRIORITY INTEGER NOT NULL, 159 | STATE NVARCHAR(16) NOT NULL, 160 | JOB_NAME NVARCHAR(150) NULL, 161 | JOB_GROUP NVARCHAR(150) NULL, 162 | IS_NONCONCURRENT BIT NULL, 163 | REQUESTS_RECOVERY BIT NULL, 164 | PRIMARY KEY (SCHED_NAME,ENTRY_ID) 165 | ); 166 | 167 | CREATE TABLE QRTZ_SCHEDULER_STATE 168 | ( 169 | SCHED_NAME NVARCHAR(120) NOT NULL, 170 | INSTANCE_NAME NVARCHAR(200) NOT NULL, 171 | LAST_CHECKIN_TIME BIGINT NOT NULL, 172 | CHECKIN_INTERVAL BIGINT NOT NULL, 173 | PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) 174 | ); 175 | 176 | CREATE TABLE QRTZ_LOCKS 177 | ( 178 | SCHED_NAME NVARCHAR(120) NOT NULL, 179 | LOCK_NAME NVARCHAR(40) NOT NULL, 180 | PRIMARY KEY (SCHED_NAME,LOCK_NAME) 181 | ); 182 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | //可跨域地址集合 3 | "AllowedHosts": [ "*" ], 4 | "Quartz": { 5 | "dbProviderName": "SQLite-Microsoft", 6 | "connectionString": "Data Source=File/sqliteScheduler.db;" 7 | }, 8 | "Logging": { 9 | "IncludeScopes": false, 10 | "Debug": { 11 | "LogLevel": { 12 | "Default": "Warning" 13 | } 14 | }, 15 | "Console": { 16 | "LogLevel": { 17 | "Default": "Warning" 18 | } 19 | } 20 | } 21 | } 22 | 23 | //数据源配置 24 | //"dbProviderName":"OracleODPManaged", 25 | //"connectionString": "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)));User Id=system;Password=oracle;" 26 | // # SqlServer 测试通过 27 | //"dbProviderName":"SqlServer", 28 | //"connectionString": "Server=localhost;Database=quartznet;User Id=SqlServerUser;Password=SqlServerPassword;" 29 | //"dbProviderName":"SQLServerMOT", 30 | //"connectionString": "Server=localhost,1444;Database=quartznet;User Id={SqlServerUser};Password={SqlServerPassword};" 31 | // # MySql 测试通过 32 | //"dbProviderName":"MySql", 33 | //"connectionString": "Server = localhost; Database = quartznet; Uid = quartznet; Pwd = quartznet" 34 | // # Npgsql 测试通过 35 | //"dbProviderName":"Npgsql", 36 | //"connectionString": "Server=127.0.0.1;Port=5432;Userid=quartznet;Password=quartznet;Pooling=true;MinPoolSize=1;MaxPoolSize=20;Timeout=15;SslMode=Disable;Database=quartznet" 37 | //"dbProviderName":"SQLite", 38 | //"connectionString": "Data Source=test.db;Version=3;" 39 | // # SQLite-Microsoft 测试通过 40 | //"dbProviderName":"SQLite-Microsoft", 41 | //"connectionString": "Data Source=test.db;" 42 | //"dbProviderName":"Firebird", 43 | //"connectionString": "User=SYSDBA;Password=masterkey;Database=/firebird/data/quartz.fdb;DataSource=localhost;Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;" 44 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/assets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "logTitle": "Task scheduling platform", 3 | "login": { 4 | "任务调度平台": "Task scheduling platform", 5 | "请输入登录口令": "Please enter your login password", 6 | "提交": "Submit" 7 | }, 8 | "task.list": { 9 | "table.th": { 10 | "任务名称": "Task Name", 11 | "状态": "State", 12 | "请求方式": "Request way", 13 | "Url": "Address", 14 | "异常信息": "Exception Info", 15 | "开始时间": "Start Time", 16 | "上次执行时间": "Last execution time", 17 | "下次执行时间": "Next execution time", 18 | "执行计划": "Execution", 19 | "描述": "Description", 20 | "请求次数": "Triggered", 21 | "任务类型": "Task type", 22 | "button": { 23 | "新增任务": "Add Task", 24 | "恢复": "Restore", 25 | "复制": "Copy", 26 | "删除": "Delete", 27 | "编辑": "Editor", 28 | "暂停": "Pause", 29 | "执行": "Execute", 30 | "日志": "Log", 31 | "更多": "More" 32 | }, 33 | "tag": { 34 | "查看": "View", 35 | "正常": "Normal", 36 | "暂停": "Paused", 37 | "完成": "Complete", 38 | "异常": "Error", 39 | "阻塞": "Blocked", 40 | "不存在": "None", 41 | "未知": "Unknown" 42 | }, 43 | "jobType": { 44 | "1": "Url", 45 | "2": "Emial", 46 | "3": "Mqtt", 47 | "4": "RabbitMQ", 48 | "5": "Hotreload" 49 | } 50 | }, 51 | "modal.label": { 52 | "任务组名": "Group name", 53 | "任务名称": "Task name", 54 | "请求地址": "Request URL", 55 | "开始时间": "Start time", 56 | "结束时间": "End time", 57 | "触发器类型": "Trigger type", 58 | "Cron表达式": "Cron", 59 | "间隔时间": "Interval time", 60 | "请求类型": "Request type", 61 | "请求头": "Request header", 62 | "请求参数": "Request parameter", 63 | "任务描述": "Task description", 64 | "邮件通知": "Email notification", 65 | "参考": "Consult", 66 | "不通知": "Not notify", 67 | "通知异常": "Notify exception", 68 | "通知所有": "Notify all", 69 | "任务类型": "Task type", 70 | "邮件内容": "Mail content", 71 | "收件邮箱": "MailTo", 72 | "邮件标题": "Mail title", 73 | "邮件": "Email", 74 | "热加载": "Hot reload", 75 | "秒": "second", 76 | "时": "hour", 77 | "分": "minute", 78 | "天": "day", 79 | "主题": "Topic", 80 | "消息": "Payload", 81 | "队列名称": "Queue", 82 | "主体内容": "Body" 83 | }, 84 | "任务列表": "Task list" 85 | }, 86 | "system.setup": { 87 | "注销": "logout", 88 | "breadcrumb": "system setup", 89 | "tabset.tab": { 90 | "邮箱设置": "Mailbox settings", 91 | "MQTT配置": "MQTT settings", 92 | "刷新设置": "Refresh settings", 93 | "登录设置": "Login settings", 94 | "RabbitMQ配置": "RabbitMQ settings" 95 | }, 96 | "label": { 97 | "页面定时刷新时间": "Page refresh time", 98 | "发件服务器": "MailHost", 99 | "发件邮箱": "MailFrom", 100 | "邮箱密码": "MailPassword", 101 | "收件邮箱": "MailTo", 102 | "秒": "second", 103 | "旧登录口令": "Old login password", 104 | "新登录口令": "New login password", 105 | "主机地址": "Host", 106 | "端口": "Port", 107 | "客户端ID": "Clinet ID", 108 | "用户名": "UserName", 109 | "密码": "Password", 110 | "连接方式": "Connection method" 111 | }, 112 | "button": { 113 | "确定": "Ok", 114 | "测试": "Test", 115 | "连接测试": "Test connect" 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/assets/i18n/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "logTitle": "任务调度平台", 3 | "login":{ 4 | "任务调度平台":"任务调度平台", 5 | "请输入登录口令":"请输入登录口令", 6 | "提交":"提交" 7 | }, 8 | "task.list": { 9 | "table.th": { 10 | "任务名称": "任务名称", 11 | "状态": "状态", 12 | "请求方式": "请求方式", 13 | "Url": "触发地址", 14 | "异常信息": "异常信息", 15 | "开始时间": "开始时间", 16 | "上次执行时间": "上次执行时间", 17 | "下次执行时间": "下次执行时间", 18 | "执行计划": "执行计划", 19 | "描述": "描述", 20 | "请求次数":"触发次数", 21 | "任务类型":"任务类型", 22 | "button": { 23 | "新增任务": "新增任务", 24 | "恢复": "恢复", 25 | "复制": "复制", 26 | "删除": "删除", 27 | "编辑": "编辑", 28 | "暂停": "暂停", 29 | "执行": "执行", 30 | "日志": "日志", 31 | "更多": "更多" 32 | }, 33 | "tag": { 34 | "查看": "查看", 35 | "正常": "正常", 36 | "暂停": "暂停", 37 | "完成": "完成", 38 | "异常": "异常", 39 | "阻塞": "执行中", 40 | "不存在": "不存在", 41 | "未知": "未知" 42 | }, 43 | "jobType": { 44 | "1": "Url", 45 | "2": "邮件", 46 | "3": "Mqtt", 47 | "4": "RabbitMQ", 48 | "5": "热加载" 49 | } 50 | }, 51 | "modal.label": { 52 | "任务组名": "任务组名", 53 | "任务名称": "任务名称", 54 | "请求地址": "请求地址", 55 | "开始时间": "开始时间", 56 | "结束时间": "结束时间", 57 | "触发器类型": "触发器类型", 58 | "Cron表达式": "Cron表达式", 59 | "间隔时间": "间隔时间", 60 | "请求类型": "请求类型", 61 | "请求头": "请求头", 62 | "请求参数": "请求参数", 63 | "任务描述": "任务描述", 64 | "邮件通知": "邮件通知", 65 | "任务类型":"任务类型", 66 | "邮件":"邮件", 67 | "热加载":"热加载", 68 | "邮件内容": "邮件内容", 69 | "收件邮箱": "收件邮箱", 70 | "邮件标题": "邮件标题", 71 | "参考": "参考", 72 | "不通知": "不通知", 73 | "通知异常": "通知异常", 74 | "通知所有": "通知所有", 75 | "秒": "秒", 76 | "时": "时", 77 | "分": "分", 78 | "天": "天", 79 | "主题":"主题", 80 | "消息":"消息", 81 | "队列名称":"队列名称", 82 | "主体内容":"主体内容" 83 | }, 84 | "任务列表": "任务列表" 85 | }, 86 | "system.setup": { 87 | "注销":"注销", 88 | "breadcrumb": "系统设置", 89 | "tabset.tab": { 90 | "邮箱设置": "邮箱配置", 91 | "MQTT配置": "MQTT配置", 92 | "刷新设置": "刷新设置", 93 | "登录设置": "登录设置", 94 | "RabbitMQ配置":"RabbitMQ配置" 95 | }, 96 | "label": { 97 | "页面定时刷新时间": "页面定时刷新时间", 98 | "发件服务器": "发件服务器", 99 | "发件邮箱": "发件邮箱", 100 | "邮箱密码": "邮箱密码", 101 | "收件邮箱": "收件邮箱", 102 | "秒": "秒", 103 | "旧登录口令": "旧登录口令", 104 | "新登录口令": "新登录口令", 105 | "主机地址":"主机地址", 106 | "端口":"端口", 107 | "客户端ID":"客户端ID", 108 | "用户名":"用户名", 109 | "密码":"密码", 110 | "连接方式":"连接方式" 111 | }, 112 | "button": { 113 | "确定": "确定", 114 | "测试": "测试", 115 | "连接测试":"连接测试" 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/assets/images/yanjing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetAPI/Host/wwwroot/assets/images/yanjing1.png -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/assets/images/yanjing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetAPI/Host/wwwroot/assets/images/yanjing2.png -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetAPI/Host/wwwroot/favicon.ico -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 任务调度平台 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/main-es2015.d5ed1f222b0ffea87f16.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Alibaba.com All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE 7 | * @type {?} 8 | */ 9 | 10 | /** 11 | * @license 12 | * Copyright Alibaba.com All Rights Reserved. 13 | * 14 | * Use of this source code is governed by an MIT-style license that can be 15 | * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright Google Inc. All Rights Reserved. 21 | * 22 | * Use of this source code is governed by an MIT-style license that can be 23 | * found in the LICENSE file at https://angular.io/license 24 | * @param {?} cb 25 | * @return {?} 26 | */ 27 | 28 | /** 29 | * @license 30 | * Copyright Google Inc. All Rights Reserved. 31 | * 32 | * Use of this source code is governed by an MIT-style license that can be 33 | * found in the LICENSE file at https://angular.io/license 34 | * @type {?} 35 | */ 36 | 37 | /** 38 | * @license 39 | * Copyright Google Inc. All Rights Reserved. 40 | * 41 | * Use of this source code is governed by an MIT-style license that can be 42 | * found in the LICENSE file at https://angular.io/license 43 | */ 44 | 45 | /** 46 | * @license 47 | * Copyright Google LLC All Rights Reserved. 48 | * 49 | * Use of this source code is governed by an MIT-style license that can be 50 | * found in the LICENSE file at https://angular.io/license 51 | */ 52 | 53 | /** 54 | * @license Angular v8.2.8 55 | * (c) 2010-2019 Google LLC. https://angular.io/ 56 | * License: MIT 57 | */ 58 | 59 | /** 60 | * @license 61 | * Copyright Google Inc. All Rights Reserved. 62 | * 63 | * Use of this source code is governed by an MIT-style license that can be 64 | * found in the LICENSE file at https://angular.io/license 65 | */ 66 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/polyfills-es2015.6f19846b4ef18698dc55.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/polyfills-es5-es2015.06082d8ddd1aae402438.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | -------------------------------------------------------------------------------- /QuartzNetAPI/Host/wwwroot/runtime-es2015.d1d4fa10751b40a173bf.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,u,i=r[0],f=r[1],c=r[2],p=0,s=[];p 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /QuartzNetWeb/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('quartz App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /QuartzNetWeb/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /QuartzNetWeb/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /QuartzNetWeb/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /QuartzNetWeb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quartz", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build --prod", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular-devkit/schematics": "^0.7.5", 16 | "@angular/animations": "^8.2.8", 17 | "@angular/cli": "^8.3.6", 18 | "@angular/common": "^8.2.8", 19 | "@angular/compiler": "^8.2.8", 20 | "@angular/core": "^8.2.8", 21 | "@angular/forms": "^8.2.8", 22 | "@angular/platform-browser": "^8.2.8", 23 | "@angular/platform-browser-dynamic": "^8.2.8", 24 | "@angular/router": "^8.2.8", 25 | "@ngx-translate/core": "^11.0.1", 26 | "@ngx-translate/http-loader": "^4.0.0", 27 | "core-js": "^2.4.1", 28 | "handlebars": "^4.7.7", 29 | "ng-zorro-antd": "^8.3.1", 30 | "rxjs": "^6.5.3", 31 | "rxjs-compat": "^6.2.2", 32 | "tslib": "^1.9.0", 33 | "zone.js": "~0.9.1" 34 | }, 35 | "devDependencies": { 36 | "@angular-devkit/build-angular": "^0.803.29", 37 | "@angular/compiler-cli": "^8.2.8", 38 | "@angular/language-service": "^8.2.8", 39 | "@types/jasmine": "~2.8.3", 40 | "@types/jasminewd2": "~2.0.2", 41 | "@types/node": "~6.0.60", 42 | "codelyzer": "^5.0.1", 43 | "jasmine-core": "~2.8.0", 44 | "jasmine-spec-reporter": "~4.2.1", 45 | "karma": "^3.0.0", 46 | "karma-chrome-launcher": "~2.2.0", 47 | "karma-coverage-istanbul-reporter": "^1.2.1", 48 | "karma-jasmine": "~1.1.0", 49 | "karma-jasmine-html-reporter": "^0.2.2", 50 | "protractor": "^5.4.1", 51 | "ts-node": "~4.1.0", 52 | "tslint": "~5.9.1", 53 | "typescript": "^3.5.3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /QuartzNetWeb/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { LoginComponent } from './login/login.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | loadChildren: 'app/layout/layout.module#LayoutModule' 9 | }, 10 | { 11 | path: 'signin', 12 | component: LoginComponent 13 | } 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes)], 18 | exports: [RouterModule] 19 | }) 20 | export class AppRoutingModule { } -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/app/app.component.css -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component, Injectable, OnInit } from '@angular/core'; 3 | import { HttpClientModule, HttpClient, HttpHeaders } from '@angular/common/http'; 4 | import * as addDays from 'date-fns/add_days'; 5 | import * as getISOWeek from 'date-fns/get_iso_week'; 6 | import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; 7 | import { NgModule } from '@angular/core'; 8 | import { environment } from '../environments/environment'; 9 | import { NzNotificationService, NzTreeModule, NzModalService } from 'ng-zorro-antd'; 10 | 11 | @Component({ 12 | selector: 'app-root', 13 | templateUrl: './app.component.html', 14 | styleUrls: ['./app.component.css'] 15 | }) 16 | export class AppComponent { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | 5 | import { AppComponent } from './app.component'; 6 | import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd'; 7 | 8 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 9 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'; 10 | import { HttpClientModule, HttpClient } from '@angular/common/http'; 11 | import { AppRoutingModule } from './app-routing.module'; 12 | 13 | import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; 14 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 15 | import { LoginComponent } from './login/login.component'; 16 | import { MyHttpService } from '../shared/myhttp'; 17 | export function HttpLoaderFactory(http: HttpClient) { 18 | return new TranslateHttpLoader(http); 19 | } 20 | @NgModule({ 21 | declarations: [ 22 | AppComponent, 23 | LoginComponent 24 | ], 25 | imports: [ 26 | AppRoutingModule, 27 | BrowserModule, 28 | FormsModule, 29 | HttpClientModule, 30 | ReactiveFormsModule, 31 | BrowserAnimationsModule, 32 | NgZorroAntdModule, 33 | TranslateModule.forRoot({ 34 | loader: { 35 | provide: TranslateLoader, 36 | useFactory: HttpLoaderFactory, 37 | deps: [HttpClient] 38 | } 39 | }) 40 | ], 41 | providers: [ 42 | MyHttpService, 43 | { provide: NZ_I18N, useValue: zh_CN },// 这里设置当前全局使用的语言包 44 | ], 45 | bootstrap: [AppComponent] 46 | }) 47 | export class AppModule { } 48 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { ExplainComponent } from './explain/explain.component'; 4 | 5 | const routes: Routes = [{ 6 | path: '', 7 | component: ExplainComponent 8 | }]; 9 | 10 | @NgModule({ 11 | imports: [RouterModule.forChild(routes)], 12 | exports: [RouterModule] 13 | }) 14 | export class ExplainRoutingModule { } 15 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain.module.spec.ts: -------------------------------------------------------------------------------- 1 | import { ExplainModule } from './explain.module'; 2 | 3 | describe('ExplainModule', () => { 4 | let explainModule: ExplainModule; 5 | 6 | beforeEach(() => { 7 | explainModule = new ExplainModule(); 8 | }); 9 | 10 | it('should create an instance', () => { 11 | expect(explainModule).toBeTruthy(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { ExplainRoutingModule } from './explain-routing.module'; 5 | import { ExplainComponent } from './explain/explain.component'; 6 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'; 7 | import { NgZorroAntdModule } from 'ng-zorro-antd'; 8 | 9 | @NgModule({ 10 | imports: [ 11 | CommonModule, 12 | ExplainRoutingModule, 13 | NgZorroAntdModule, 14 | FormsModule, 15 | ReactiveFormsModule 16 | ], 17 | declarations: [ExplainComponent] 18 | }) 19 | export class ExplainModule { } 20 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain/explain.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/app/explain/explain/explain.component.css -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain/explain.component.html: -------------------------------------------------------------------------------- 1 | 2 | 使用说明 3 | 4 |
5 |
 6 |     方式1(docker使用)
 7 |     docker run -v /fileData/quartzuifile:/app/File --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui
 8 | 
 9 |     一行命令开箱即用,赶快体验下docker的便捷吧!
10 |     1、其中/fileData/quartzuifile为映射的文件地址,如SQLite数据库和log日志
11 |     2、5088为映射到主机的端口
12 |     3、直接在浏览器 ip:5088 即可访问。(注意防火墙是否打开了5088端口,或者在主机测试 curl 127.0.0.1:5088)
13 | 
14 |     方式2(可直接通过源码部署到windows或linux平台)
15 | 
16 |     源码地址:https://github.com/zhaopeiym/quartzui
17 | 
18 |     问题交流:https://github.com/zhaopeiym/quartzui/issues
19 |   
20 |
21 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain/explain.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ExplainComponent } from './explain.component'; 4 | 5 | describe('ExplainComponent', () => { 6 | let component: ExplainComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ExplainComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ExplainComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/explain/explain/explain.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-explain', 5 | templateUrl: './explain.component.html', 6 | styleUrls: ['./explain.component.css'] 7 | }) 8 | export class ExplainComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { LayoutComponent } from './layout/layout.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: LayoutComponent, 9 | children: [ 10 | { 11 | path: '', 12 | // loadChildren: "app/task-list/task-list.module#TaskListModule" 13 | loadChildren: () => import('../../app/task-list/task-list.module').then(m => m.TaskListModule) 14 | }, 15 | { 16 | path: 'seting', 17 | // loadChildren: "app/seting/seting.module#SetingModule" 18 | loadChildren: () => import('../../app/seting/seting.module').then(m => m.SetingModule) 19 | }, 20 | { 21 | path: 'explain', 22 | // loadChildren: "app/explain/explain.module#ExplainModule" 23 | loadChildren: () => import('../../app/explain/explain.module').then(m => m.ExplainModule) 24 | } 25 | ] 26 | }, 27 | 28 | ]; 29 | 30 | @NgModule({ 31 | imports: [RouterModule.forChild(routes)], 32 | exports: [RouterModule] 33 | }) 34 | export class LayoutRoutingModule { } 35 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { LayoutRoutingModule } from './layout-routing.module'; 5 | import { LayoutComponent } from './layout/layout.component'; 6 | import { NgZorroAntdModule } from 'ng-zorro-antd'; 7 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 8 | 9 | import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; 10 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 11 | import { HttpClient } from '@angular/common/http'; 12 | import { MyHttpService } from '../../shared/myhttp'; 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CommonModule, 20 | LayoutRoutingModule, 21 | NgZorroAntdModule, 22 | FormsModule, 23 | ReactiveFormsModule, 24 | TranslateModule.forRoot({ 25 | loader: { 26 | provide: TranslateLoader, 27 | useFactory: HttpLoaderFactory, 28 | deps: [HttpClient] 29 | } 30 | }) 31 | ], 32 | declarations: [LayoutComponent], 33 | providers: [ 34 | MyHttpService 35 | ], 36 | }) 37 | export class LayoutModule { } 38 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout/layout.component.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | min-width: 120px; 3 | padding: 0 8px; 4 | height: 31px; 5 | background: rgba(255, 255, 255, .2); 6 | margin: 16px 24px 16px 0; 7 | float: left; 8 | border-radius: 6px; 9 | margin: 16px; 10 | line-height: 31px; 11 | overflow: hidden; 12 | text-align: center; 13 | color: #fff; 14 | font-size: 16px; 15 | } 16 | 17 | .ant-layout-content { 18 | min-height: initial; 19 | } 20 | 21 | nz-layout { 22 | min-height: 100%; 23 | height: initial !important; 24 | } 25 | 26 | ::ng-deep .ant-modal { 27 | width: 615px !important; 28 | } 29 | 30 | ul li { 31 | display: inline-block; 32 | cursor: pointer; 33 | } 34 | 35 | ul li:hover { 36 | background: #05315D; 37 | } 38 | 39 | .nomenu a { 40 | color: rgba(255, 255, 255, 0.65); 41 | } 42 | 43 | .nomenu:hover a { 44 | color: #fff; 45 | } 46 | 47 | .nomenu:active { 48 | background: #0094ff; 49 | } 50 | 51 | .nomenu:active a { 52 | color: #fff; 53 | } 54 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout/layout.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | 25 | 26 | 27 | ©2018-2021 Implement By 28 | 农码一生 29 | 30 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout/layout.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LayoutComponent } from './layout.component'; 4 | 5 | describe('LayoutComponent', () => { 6 | let component: LayoutComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LayoutComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LayoutComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/layout/layout/layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Injectable, OnInit } from '@angular/core'; 2 | import { HttpClientModule, HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import * as addDays from 'date-fns/add_days'; 4 | import * as getISOWeek from 'date-fns/get_iso_week'; 5 | import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; 6 | import { NgModule } from '@angular/core'; 7 | import { NzNotificationService, NzTreeModule, NzModalService } from 'ng-zorro-antd'; 8 | import { environment } from '../../../environments/environment'; 9 | import { Router } from '@angular/router'; 10 | import { en_US, zh_CN, NzI18nService } from 'ng-zorro-antd/i18n'; 11 | import { debounceTime } from 'rxjs/operators'; 12 | 13 | import { TranslateService } from '@ngx-translate/core'; 14 | import { fromEvent } from 'rxjs'; 15 | import { Util } from '../../../shared/util'; 16 | 17 | @Component({ 18 | selector: 'app-layout', 19 | templateUrl: './layout.component.html', 20 | styleUrls: ['./layout.component.css'] 21 | }) 22 | export class LayoutComponent implements OnInit { 23 | validateJobForm: FormGroup; 24 | isJobVisible: boolean; 25 | isVisible: boolean; 26 | jobGroupName: any; 27 | jobGroupDescribe: any; 28 | isCron = true; 29 | modalTitle = "新增任务"; 30 | title = 'app'; 31 | // logTitle = "任务调度平台"; 32 | private baseUrl = environment.baseUrl;// "http://localhost:52725"; 开发的时候可以先设置本地接口地址 33 | public resultData: any = [{}]; 34 | dateFormat = 'yyyy/MM/dd'; 35 | jobInfoEntity: any = {}; 36 | Language: string = "English"; 37 | IsEnglish = false; 38 | TaskList: string; 39 | Seting: string; 40 | Explain: string; 41 | currentUrl: string; 42 | contentPaddingWidth: string = "0 40px"; 43 | constructor(private http: HttpClient, 44 | private fb2: FormBuilder, 45 | private notification: NzNotificationService, 46 | private modalService: NzModalService, 47 | private i18n: NzI18nService, 48 | //https://blog.csdn.net/qq_36822018/article/details/81504473 49 | //https://segmentfault.com/a/1190000019852382 50 | private translate: TranslateService, 51 | private router: Router) { 52 | this.translate.setDefaultLang("zh"); 53 | } 54 | 55 | ngOnInit(): void { 56 | if (this.IsEnglish) 57 | this.showEnglish(); 58 | else 59 | this.showChinese(); 60 | 61 | if (location.href.indexOf("/seting") >= 0) { 62 | this.currentUrl = "seting"; 63 | } else if (location.href.indexOf("/explain") >= 0) { 64 | this.currentUrl = "explain"; 65 | } 66 | else { 67 | this.currentUrl = "home"; 68 | } 69 | 70 | this.IsEnglish = JSON.parse(localStorage.getItem("IsEnglish")); 71 | this.setSwitchLanguage(); 72 | 73 | this.initWindowAdapt(); 74 | fromEvent(window, 'resize').pipe(debounceTime(50)).subscribe(() => { 75 | this.initWindowAdapt(); 76 | }); 77 | } 78 | initWindowAdapt() { 79 | var w = document.documentElement.offsetWidth || document.body.offsetWidth; 80 | if (w < 1500) 81 | this.contentPaddingWidth = "0 10px"; 82 | else 83 | this.contentPaddingWidth = "0 40px"; 84 | console.log(w); 85 | } 86 | 87 | msgError(str): void { 88 | this.notification.error(str, "") 89 | } 90 | msgInfo(str): void { 91 | this.notification.info(str, "") 92 | } 93 | msgSuccess(str): void { 94 | this.notification.success(str, "") 95 | } 96 | msgWarning(str): void { 97 | this.notification.warning(str, "") 98 | } 99 | 100 | //跳转到任务列表 101 | jumpTaskList() { 102 | this.router.navigate(['/']); 103 | } 104 | 105 | //跳转到设置页面 106 | jumpSeting() { 107 | this.router.navigate(['/seting']); 108 | } 109 | 110 | //跳转到说明 111 | jumpExplain() { 112 | this.router.navigate(['/explain']); 113 | } 114 | 115 | clickGitHub() { 116 | window.open("https://github.com/zhaopeiym/quartzui"); 117 | } 118 | 119 | // 切换语言 120 | switchLanguage() { 121 | this.IsEnglish = !this.IsEnglish; 122 | this.setSwitchLanguage(); 123 | } 124 | 125 | setSwitchLanguage() { 126 | if (this.IsEnglish) { 127 | this.i18n.setLocale(en_US); 128 | this.showEnglish(); 129 | this.Language = "中文"; 130 | } 131 | else { 132 | this.i18n.setLocale(zh_CN); 133 | this.showChinese(); 134 | this.Language = "English"; 135 | } 136 | 137 | localStorage.setItem("IsEnglish", JSON.stringify(this.IsEnglish)); 138 | } 139 | 140 | showEnglish() { 141 | //this.logTitle = "Task scheduling platform"; 142 | this.TaskList = "task list"; 143 | this.Seting = "system setup"; 144 | this.Explain = "direction for use"; 145 | 146 | this.translate.use("en"); 147 | } 148 | 149 | showChinese() { 150 | // this.logTitle = "任务调度平台"; 151 | this.TaskList = "任务列表"; 152 | this.Seting = "系统设置"; 153 | this.Explain = "使用说明"; 154 | this.translate.use("zh"); 155 | } 156 | 157 | logout() { 158 | Util.SetStorage("userInfo", {}); 159 | this.router.navigate(['/signin']); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/login/login.component.css: -------------------------------------------------------------------------------- 1 | .login-conent { 2 | height: 100%; 3 | } 4 | 5 | .login { 6 | top: 30%; 7 | position: absolute; 8 | margin: 0 auto; 9 | left: 0; 10 | width: 350px; 11 | right: 0; 12 | /* border: 1px solid #0094ff; */ 13 | } 14 | 15 | .title { 16 | font-size: 26px; 17 | font-weight: bold; 18 | color: #999; 19 | text-align: center; 20 | } 21 | 22 | .title span { 23 | font-size: 14px; 24 | font-weight: 400; 25 | color: #fff; 26 | background: #ff7600a6; 27 | border-radius: 6px; 28 | padding: 1px 8px; 29 | } 30 | 31 | .login>* { 32 | margin-bottom: 30px; 33 | } 34 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/login/login.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { environment } from '../../environments/environment'; 4 | import { HttpHeaders, HttpClient } from '@angular/common/http'; 5 | import { NzMessageService } from 'ng-zorro-antd'; 6 | import { Util } from '../../shared/util'; 7 | import { MyHttpService } from '../../shared/myhttp'; 8 | import { en_US, zh_CN, NzI18nService } from 'ng-zorro-antd/i18n'; 9 | import { TranslateService } from '@ngx-translate/core'; 10 | 11 | @Component({ 12 | selector: 'app-login', 13 | templateUrl: './login.component.html', 14 | styleUrls: ['./login.component.css'] 15 | }) 16 | export class LoginComponent implements OnInit { 17 | loginPassword: any = ""; 18 | private baseUrl = environment.baseUrl; 19 | IsEnglish: any; 20 | 21 | constructor(private router: Router, 22 | private i18n: NzI18nService, 23 | private translate: TranslateService, 24 | private message: NzMessageService, 25 | private http: MyHttpService, ) { 26 | 27 | if (JSON.parse(localStorage.getItem("IsEnglish"))) 28 | this.translate.setDefaultLang("en");//zh 29 | else 30 | this.translate.setDefaultLang("zh");//en 31 | } 32 | 33 | ngOnInit() { 34 | } 35 | 36 | login() { 37 | var url = this.baseUrl + "/api/Seting/VerifyLoginInfo"; 38 | this.http.post(url, { 39 | password: this.bash64(this.loginPassword) 40 | }, (result: any) => { 41 | if (result.token) { 42 | this.router.navigate(['/']); 43 | Util.SetStorage("userInfo", result); 44 | } 45 | else 46 | this.message.warning("登录失败"); 47 | }, (err) => { 48 | }); 49 | } 50 | 51 | bash64(str) { 52 | return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { 53 | return String.fromCharCode(parseInt('0x' + p1, 16)); 54 | })); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/seting/seting-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { SetingComponent } from './seting/seting.component'; 4 | 5 | const routes: Routes = [ { 6 | path: '', 7 | component: SetingComponent 8 | }]; 9 | 10 | @NgModule({ 11 | imports: [RouterModule.forChild(routes)], 12 | exports: [RouterModule] 13 | }) 14 | export class SetingRoutingModule { } 15 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/seting/seting.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { SetingRoutingModule } from './seting-routing.module'; 5 | import { SetingComponent } from './seting/seting.component'; 6 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'; 7 | import { NgZorroAntdModule } from 'ng-zorro-antd'; 8 | 9 | import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; 10 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 11 | import { HttpClient } from '@angular/common/http'; 12 | import { MyHttpService } from '../../shared/myhttp'; 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CommonModule, 20 | SetingRoutingModule, 21 | NgZorroAntdModule, 22 | FormsModule, 23 | ReactiveFormsModule, 24 | TranslateModule.forChild({ 25 | loader: { 26 | provide: TranslateLoader, 27 | useFactory: HttpLoaderFactory, 28 | deps: [HttpClient] 29 | } 30 | }) 31 | ], 32 | declarations: [SetingComponent], 33 | providers: [ 34 | MyHttpService 35 | ], 36 | }) 37 | export class SetingModule { } 38 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/seting/seting/seting.component.css: -------------------------------------------------------------------------------- 1 | nz-form-item { 2 | width: 60%; 3 | } 4 | 5 | .but-con { 6 | margin-top: 10px; 7 | text-align: right; 8 | margin-right: 53px; 9 | } 10 | 11 | .but-con-refresh { 12 | text-align: right; 13 | margin-right: 163px; 14 | } 15 | 16 | .but-con button { 17 | margin-right: 15px; 18 | } 19 | 20 | .but-con button:nth-child(2) { 21 | margin-right: 110px; 22 | } 23 | 24 | .but-con.mqtt-but button { 25 | margin-right: 110px; 26 | } 27 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/seting/seting/seting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SetingComponent } from './seting.component'; 4 | 5 | describe('SetingComponent', () => { 6 | let component: SetingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SetingComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SetingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/task-list/task-list-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { TaskListComponent } from './task-list/task-list.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: TaskListComponent 9 | } 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule] 15 | }) 16 | export class TaskListRoutingModule { } 17 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/task-list/task-list.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { TaskListRoutingModule } from './task-list-routing.module'; 5 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'; 6 | import { NgZorroAntdModule } from 'ng-zorro-antd'; 7 | import { TaskListComponent } from './task-list/task-list.component'; 8 | 9 | import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; 10 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 11 | import { HttpClient } from '@angular/common/http'; 12 | import { MyHttpService } from '../../shared/myhttp'; 13 | export function HttpLoaderFactory(http: HttpClient) { 14 | return new TranslateHttpLoader(http); 15 | } 16 | 17 | @NgModule({ 18 | imports: [ 19 | CommonModule, 20 | TaskListRoutingModule, 21 | NgZorroAntdModule, 22 | FormsModule, 23 | ReactiveFormsModule, 24 | TranslateModule.forChild({ 25 | loader: { 26 | provide: TranslateLoader, 27 | useFactory: HttpLoaderFactory, 28 | deps: [HttpClient] 29 | } 30 | }) 31 | ], 32 | providers: [ 33 | MyHttpService 34 | ], 35 | declarations: [TaskListComponent] 36 | }) 37 | export class TaskListModule { } 38 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/task-list/task-list/task-list.component.css: -------------------------------------------------------------------------------- 1 | ::ng-deep .ant-collapse-content>.ant-collapse-content-box { 2 | padding: 0px; 3 | } 4 | 5 | .jobTable { 6 | width: 100%; 7 | padding: 0; 8 | table-layout: fixed; 9 | } 10 | 11 | .jobTable tr { 12 | height: 50px; 13 | } 14 | 15 | .jobTable th, 16 | .jobTable td { 17 | border: 1px solid #f5f5f5; 18 | } 19 | 20 | .jobTable th:not(.tb-center), 21 | .jobTable td:not(.tb-center) { 22 | padding: 0 15px; 23 | } 24 | 25 | /*笔记本 (小于1400px时应用的样式)*/ 26 | @media screen and (max-width: 1400px) { 27 | 28 | .jobTable th:not(.tb-center), 29 | .jobTable td:not(.tb-center) { 30 | padding-left: 8px; 31 | } 32 | } 33 | 34 | .jobTable tr:hover { 35 | background: #E6F7FF; 36 | } 37 | 38 | .jobTable tr:first-child { 39 | background: #FBFBFB; 40 | } 41 | 42 | .jobTable tr:first-child:hover { 43 | background: #FBFBFB; 44 | } 45 | 46 | .jobTable tr th { 47 | border-top: 0; 48 | } 49 | 50 | .jobTable tr:last-child td { 51 | border-bottom: 0; 52 | } 53 | 54 | /* 最后一列,操作按钮 */ 55 | .jobTable tr th:last-child, 56 | .jobTable tr td:last-child { 57 | border-right: 0; 58 | padding-right: 0px; 59 | padding-left: 13px; 60 | } 61 | 62 | 63 | .jobTable tr th:first-child, 64 | .jobTable tr td:first-child { 65 | border-left: 0; 66 | } 67 | 68 | .jobTable .td-url { 69 | white-space: nowrap; 70 | overflow: hidden; 71 | text-overflow: ellipsis; 72 | } 73 | 74 | /* 75 | 超出部分显示省略号 76 | https://www.cnblogs.com/whb17bcdq/p/6549643.html */ 77 | 78 | div::-webkit-scrollbar { 79 | width: 10px; 80 | /*滚动条宽度*/ 81 | height: 10px; 82 | /*滚动条高度*/ 83 | } 84 | 85 | /*定义滚动条轨道 内阴影+圆角*/ 86 | 87 | div::-webkit-scrollbar-track { 88 | background-color: rgb(248, 246, 246); 89 | /*滚动条的背景颜色*/ 90 | } 91 | 92 | /*定义滑块 内阴影+圆角*/ 93 | 94 | div::-webkit-scrollbar-thumb { 95 | border-radius: 10px; 96 | /*滚动条的圆角*/ 97 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 98 | background-color: rgb(241, 241, 241); 99 | /*滚动条的背景颜色*/ 100 | } 101 | 102 | .rowJobCont:nth-child(n+2) { 103 | margin-top: 8px; 104 | } 105 | 106 | form nz-tag { 107 | /* line-height: 39px; 108 | margin-left: 5px; */ 109 | 110 | line-height: 20px; 111 | margin-left: 5px; 112 | margin-top: 8px; 113 | } 114 | 115 | ::ng-deep .ant-form-item { 116 | margin-bottom: 8px; 117 | } 118 | 119 | ::ng-deep.ant-form-item-with-help { 120 | margin-bottom: 3px; 121 | } 122 | 123 | ::ng-deep .ant-calendar-picker, 124 | ::ng-deep [nz-date-picker] { 125 | width: 100% !important; 126 | } 127 | 128 | ::ng-deep span.error { 129 | color: red; 130 | } 131 | 132 | ::ng-deep span.warning { 133 | color: #faad14; 134 | } 135 | 136 | ::ng-deep span.result { 137 | color: #0094ff; 138 | } 139 | 140 | 141 | ::ng-deep .ant-btn-danger { 142 | color: #f5222d; 143 | background-color: #f5f5f5; 144 | border-color: #d9d9d9; 145 | text-shadow: initial; 146 | box-shadow: initial; 147 | } 148 | 149 | ::ng-deep .ant-btn-danger:hover { 150 | background-color: #FF4D4F; 151 | } 152 | 153 | .yanjing { 154 | padding: 10px; 155 | width: 40px; 156 | height: 40px; 157 | } 158 | 159 | .tb-center { 160 | text-align: center; 161 | } 162 | 163 | .ant-tag { 164 | margin: 0px; 165 | } 166 | 167 | ::ng-deep p.msgList { 168 | border-left: 3px solid #b4daf5; 169 | padding-left: 20px; 170 | } 171 | 172 | ::ng-deep p.msgList.error { 173 | border-left: 3px solid #ff9f9f; 174 | } 175 | 176 | ::ng-deep p.msgList span.time { 177 | font-weight: 600; 178 | display: block; 179 | /* color: #fff; 180 | padding: 0 10px; 181 | border-radius: 4px; 182 | background: #40a9ffad; */ 183 | } 184 | 185 | ::ng-deep .ant-modal-body { 186 | max-height: 680px; 187 | overflow-y: auto; 188 | } 189 | 190 | /*笔记本 (小于1400px时应用的样式)*/ 191 | @media screen and (max-width: 1400px) { 192 | ::ng-deep .ant-modal-body { 193 | max-height: 480px; 194 | overflow-y: auto; 195 | } 196 | 197 | .jobTable tr th:last-child, 198 | .jobTable tr td:last-child { 199 | padding-left: 7px; 200 | } 201 | } 202 | 203 | ::ng-deep div::-webkit-scrollbar { 204 | width: 10px; 205 | /*滚动条宽度*/ 206 | height: 10px; 207 | /*滚动条高度*/ 208 | } 209 | 210 | /* 滚动条效果,鼠标悬浮才显示 211 | ::ng-deep div.ant-table-body.ng-star-inserted:hover::-webkit-scrollbar-thumb, 212 | ::ng-deep div.ant-modal-body:hover::-webkit-scrollbar-thum 213 | */ 214 | ::ng-deep div.ant-modal-body::-webkit-scrollbar-track { 215 | background-color: #fff; 216 | } 217 | 218 | ::ng-deep div.ant-modal-body::-webkit-scrollbar-thumb { 219 | border-radius: 10px; 220 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0); 221 | background-color: rgb(241, 241, 241, 0); 222 | } 223 | 224 | ::ng-deep div.ant-modal-body:hover::-webkit-scrollbar-thumb { 225 | border-radius: 10px; 226 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 227 | background-color: rgb(241, 241, 241); 228 | } 229 | 230 | .tag-jobtype { 231 | min-width: 42px; 232 | } 233 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/app/task-list/task-list/task-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TaskListComponent } from './task-list.component'; 4 | 5 | describe('TaskListComponent', () => { 6 | let component: TaskListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TaskListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TaskListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/assets/.gitkeep -------------------------------------------------------------------------------- /QuartzNetWeb/src/assets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "logTitle": "Task scheduling platform", 3 | "login": { 4 | "任务调度平台": "Task scheduling platform", 5 | "请输入登录口令": "Please enter your login password", 6 | "提交": "Submit" 7 | }, 8 | "task.list": { 9 | "table.th": { 10 | "任务名称": "Task Name", 11 | "状态": "State", 12 | "请求方式": "Request way", 13 | "Url": "Address", 14 | "异常信息": "Exception Info", 15 | "开始时间": "Start Time", 16 | "上次执行时间": "Last execution time", 17 | "下次执行时间": "Next execution time", 18 | "执行计划": "Execution", 19 | "描述": "Description", 20 | "请求次数": "Triggered", 21 | "任务类型": "Task type", 22 | "button": { 23 | "新增任务": "Add Task", 24 | "恢复": "Restore", 25 | "复制": "Copy", 26 | "删除": "Delete", 27 | "编辑": "Editor", 28 | "暂停": "Pause", 29 | "执行": "Execute", 30 | "日志": "Log", 31 | "更多": "More" 32 | }, 33 | "tag": { 34 | "查看": "View", 35 | "正常": "Normal", 36 | "暂停": "Paused", 37 | "完成": "Complete", 38 | "异常": "Error", 39 | "阻塞": "Blocked", 40 | "不存在": "None", 41 | "未知": "Unknown" 42 | }, 43 | "jobType": { 44 | "1": "Url", 45 | "2": "Emial", 46 | "3": "Mqtt", 47 | "4": "RabbitMQ", 48 | "5": "Hotreload" 49 | } 50 | }, 51 | "modal.label": { 52 | "任务组名": "Group name", 53 | "任务名称": "Task name", 54 | "请求地址": "Request URL", 55 | "开始时间": "Start time", 56 | "结束时间": "End time", 57 | "触发器类型": "Trigger type", 58 | "Cron表达式": "Cron", 59 | "间隔时间": "Interval time", 60 | "请求类型": "Request type", 61 | "请求头": "Request header", 62 | "请求参数": "Request parameter", 63 | "任务描述": "Task description", 64 | "邮件通知": "Email notification", 65 | "参考": "Consult", 66 | "不通知": "Not notify", 67 | "通知异常": "Notify exception", 68 | "通知所有": "Notify all", 69 | "任务类型": "Task type", 70 | "邮件内容": "Mail content", 71 | "收件邮箱": "MailTo", 72 | "邮件标题": "Mail title", 73 | "邮件": "Email", 74 | "热加载": "Hot reload", 75 | "秒": "second", 76 | "时": "hour", 77 | "分": "minute", 78 | "天": "day", 79 | "主题": "Topic", 80 | "消息": "Payload", 81 | "队列名称": "Queue", 82 | "主体内容": "Body" 83 | }, 84 | "任务列表": "Task list" 85 | }, 86 | "system.setup": { 87 | "注销": "logout", 88 | "breadcrumb": "system setup", 89 | "tabset.tab": { 90 | "邮箱设置": "Mailbox settings", 91 | "MQTT配置": "MQTT settings", 92 | "刷新设置": "Refresh settings", 93 | "登录设置": "Login settings", 94 | "RabbitMQ配置": "RabbitMQ settings" 95 | }, 96 | "label": { 97 | "页面定时刷新时间": "Page refresh time", 98 | "发件服务器": "MailHost", 99 | "发件邮箱": "MailFrom", 100 | "邮箱密码": "MailPassword", 101 | "收件邮箱": "MailTo", 102 | "秒": "second", 103 | "旧登录口令": "Old login password", 104 | "新登录口令": "New login password", 105 | "主机地址": "Host", 106 | "端口": "Port", 107 | "客户端ID": "Clinet ID", 108 | "用户名": "UserName", 109 | "密码": "Password", 110 | "连接方式": "Connection method" 111 | }, 112 | "button": { 113 | "确定": "Ok", 114 | "测试": "Test", 115 | "连接测试": "Test connect" 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /QuartzNetWeb/src/assets/i18n/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "logTitle": "任务调度平台", 3 | "login":{ 4 | "任务调度平台":"任务调度平台", 5 | "请输入登录口令":"请输入登录口令", 6 | "提交":"提交" 7 | }, 8 | "task.list": { 9 | "table.th": { 10 | "任务名称": "任务名称", 11 | "状态": "状态", 12 | "请求方式": "请求方式", 13 | "Url": "触发地址", 14 | "异常信息": "异常信息", 15 | "开始时间": "开始时间", 16 | "上次执行时间": "上次执行时间", 17 | "下次执行时间": "下次执行时间", 18 | "执行计划": "执行计划", 19 | "描述": "描述", 20 | "请求次数":"触发次数", 21 | "任务类型":"任务类型", 22 | "button": { 23 | "新增任务": "新增任务", 24 | "恢复": "恢复", 25 | "复制": "复制", 26 | "删除": "删除", 27 | "编辑": "编辑", 28 | "暂停": "暂停", 29 | "执行": "执行", 30 | "日志": "日志", 31 | "更多": "更多" 32 | }, 33 | "tag": { 34 | "查看": "查看", 35 | "正常": "正常", 36 | "暂停": "暂停", 37 | "完成": "完成", 38 | "异常": "异常", 39 | "阻塞": "执行中", 40 | "不存在": "不存在", 41 | "未知": "未知" 42 | }, 43 | "jobType": { 44 | "1": "Url", 45 | "2": "邮件", 46 | "3": "Mqtt", 47 | "4": "RabbitMQ", 48 | "5": "热加载" 49 | } 50 | }, 51 | "modal.label": { 52 | "任务组名": "任务组名", 53 | "任务名称": "任务名称", 54 | "请求地址": "请求地址", 55 | "开始时间": "开始时间", 56 | "结束时间": "结束时间", 57 | "触发器类型": "触发器类型", 58 | "Cron表达式": "Cron表达式", 59 | "间隔时间": "间隔时间", 60 | "请求类型": "请求类型", 61 | "请求头": "请求头", 62 | "请求参数": "请求参数", 63 | "任务描述": "任务描述", 64 | "邮件通知": "邮件通知", 65 | "任务类型":"任务类型", 66 | "邮件":"邮件", 67 | "热加载":"热加载", 68 | "邮件内容": "邮件内容", 69 | "收件邮箱": "收件邮箱", 70 | "邮件标题": "邮件标题", 71 | "参考": "参考", 72 | "不通知": "不通知", 73 | "通知异常": "通知异常", 74 | "通知所有": "通知所有", 75 | "秒": "秒", 76 | "时": "时", 77 | "分": "分", 78 | "天": "天", 79 | "主题":"主题", 80 | "消息":"消息", 81 | "队列名称":"队列名称", 82 | "主体内容":"主体内容" 83 | }, 84 | "任务列表": "任务列表" 85 | }, 86 | "system.setup": { 87 | "注销":"注销", 88 | "breadcrumb": "系统设置", 89 | "tabset.tab": { 90 | "邮箱设置": "邮箱配置", 91 | "MQTT配置": "MQTT配置", 92 | "刷新设置": "刷新设置", 93 | "登录设置": "登录设置", 94 | "RabbitMQ配置":"RabbitMQ配置" 95 | }, 96 | "label": { 97 | "页面定时刷新时间": "页面定时刷新时间", 98 | "发件服务器": "发件服务器", 99 | "发件邮箱": "发件邮箱", 100 | "邮箱密码": "邮箱密码", 101 | "收件邮箱": "收件邮箱", 102 | "秒": "秒", 103 | "旧登录口令": "旧登录口令", 104 | "新登录口令": "新登录口令", 105 | "主机地址":"主机地址", 106 | "端口":"端口", 107 | "客户端ID":"客户端ID", 108 | "用户名":"用户名", 109 | "密码":"密码", 110 | "连接方式":"连接方式" 111 | }, 112 | "button": { 113 | "确定": "确定", 114 | "测试": "测试", 115 | "连接测试":"连接测试" 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /QuartzNetWeb/src/assets/images/yanjing1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/assets/images/yanjing1.png -------------------------------------------------------------------------------- /QuartzNetWeb/src/assets/images/yanjing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/assets/images/yanjing2.png -------------------------------------------------------------------------------- /QuartzNetWeb/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | baseUrl: ""// 开发的时候可以先设置本地接口地址 4 | }; 5 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | baseUrl: "http://localhost:8100"// 开发的时候可以先设置本地接口地址 9 | }; 10 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhaopeiym/quartzui/609a9b49a4fea75bead351142a542afbfc0da194/QuartzNetWeb/src/favicon.ico -------------------------------------------------------------------------------- /QuartzNetWeb/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 任务调度平台 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | import { registerLocaleData } from '@angular/common'; 7 | import zh from '@angular/common/locales/zh'; 8 | registerLocaleData(zh); 9 | 10 | if (environment.production) { 11 | enableProdMode(); 12 | } 13 | 14 | platformBrowserDynamic().bootstrapModule(AppModule) 15 | .catch(err => console.log(err)); 16 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | /** 56 | * By default, zone.js will patch all possible macroTask and DomEvents 57 | * user can disable parts of macroTask/DomEvents patch by setting following flags 58 | */ 59 | 60 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 61 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 62 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 63 | 64 | /* 65 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 66 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 67 | */ 68 | // (window as any).__Zone_enable_cross_context_check = true; 69 | 70 | /*************************************************************************************************** 71 | * Zone JS is required by default for Angular itself. 72 | */ 73 | import 'zone.js/dist/zone'; // Included with Angular CLI. 74 | 75 | 76 | 77 | /*************************************************************************************************** 78 | * APPLICATION IMPORTS 79 | */ 80 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/shared/myhttp.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClientModule, HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import { Util } from './util'; 4 | import { Router } from '@angular/router'; 5 | 6 | @Injectable() 7 | export class MyHttpService { 8 | 9 | 10 | 11 | constructor(private http: HttpClient, 12 | private router: Router, ) { 13 | 14 | } 15 | 16 | post(url: string, body: any, succeed?: Function, error?: Function) { 17 | var headers = new HttpHeaders({ 18 | 'Content-Type': 'application/json', 19 | "token": Util.GetStorage("userInfo").token || "" 20 | }); 21 | return this.http.post(url, body, { headers: headers }) 22 | .subscribe((result: any) => { 23 | succeed && succeed(result); 24 | }, (err) => { 25 | error && error(err); 26 | if (err.status == 401 && err.error && err.error.resultUrl) 27 | this.router.navigate([err.error.resultUrl]); 28 | }, () => { }); 29 | } 30 | 31 | 32 | get(url: string, succeed?: Function, error?: Function) { 33 | var headers = new HttpHeaders({ 34 | 'Content-Type': 'application/json', 35 | "token": Util.GetStorage("userInfo").token || "" 36 | }); 37 | return this.http.get(url, { headers: headers }) 38 | .subscribe((result: any) => { 39 | succeed && succeed(result); 40 | }, (err) => { 41 | error && error(err); 42 | if (err.status == 401 && err.error && err.error.resultUrl) 43 | this.router.navigate([err.error.resultUrl]); 44 | }, () => { }); 45 | } 46 | } -------------------------------------------------------------------------------- /QuartzNetWeb/src/shared/util.ts: -------------------------------------------------------------------------------- 1 | export class Util { 2 | //保存 3 | static SetStorage(key, value) { 4 | localStorage.setItem(key, JSON.stringify(value)); 5 | } 6 | 7 | //获取 8 | static GetStorage(key) { 9 | var value = localStorage.getItem(key); 10 | if (value == null || value === undefined || value === "undefined") 11 | return {}; 12 | return JSON.parse(value); 13 | } 14 | } -------------------------------------------------------------------------------- /QuartzNetWeb/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "types": [] 7 | }, 8 | "exclude": [ 9 | "test.ts", 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /QuartzNetWeb/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /QuartzNetWeb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "downlevelIteration": true, 5 | "importHelpers": true, 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es2015", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2017", 18 | "dom" 19 | ], 20 | "module": "esnext", 21 | "baseUrl": "./" 22 | } 23 | } -------------------------------------------------------------------------------- /QuartzNetWeb/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-use-before-declare": true, 76 | "no-var-keyword": true, 77 | "object-literal-sort-keys": false, 78 | "one-line": [ 79 | true, 80 | "check-open-brace", 81 | "check-catch", 82 | "check-else", 83 | "check-whitespace" 84 | ], 85 | "prefer-const": true, 86 | "quotemark": [ 87 | true, 88 | "single" 89 | ], 90 | "radix": true, 91 | "semicolon": [ 92 | true, 93 | "always" 94 | ], 95 | "triple-equals": [ 96 | true, 97 | "allow-null-check" 98 | ], 99 | "typedef-whitespace": [ 100 | true, 101 | { 102 | "call-signature": "nospace", 103 | "index-signature": "nospace", 104 | "parameter": "nospace", 105 | "property-declaration": "nospace", 106 | "variable-declaration": "nospace" 107 | } 108 | ], 109 | "unified-signatures": true, 110 | "variable-name": false, 111 | "whitespace": [ 112 | true, 113 | "check-branch", 114 | "check-decl", 115 | "check-operator", 116 | "check-separator", 117 | "check-type" 118 | ], 119 | "directive-selector": [ 120 | true, 121 | "attribute", 122 | "app", 123 | "camelCase" 124 | ], 125 | "component-selector": [ 126 | true, 127 | "element", 128 | "app", 129 | "kebab-case" 130 | ], 131 | "no-output-on-prefix": true, 132 | "no-inputs-metadata-property": true, 133 | "no-outputs-metadata-property": true, 134 | "no-host-metadata-property": true, 135 | "no-input-rename": true, 136 | "no-output-rename": true, 137 | "use-lifecycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "component-class-suffix": true, 140 | "directive-class-suffix": true 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE) 2 | [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) 3 | [![GitHub license](https://img.shields.io/github/license/alienwow/SnowLeopard.svg)](https://github.com/zhaopeiym/quartzui/blob/master/LICENSE) 4 | 5 | ## 注意:请不要跑在IIS上,因为IIS会自动回收。建议使用docker运行,或者直接用命令dotnet Host.dll。 6 | 7 | ## 说明文档 8 | https://github.com/zhaopeiym/quartzui/wiki 9 | 10 | ## 演示地址 11 | https://scheduler.haojima.net 12 | 默认口令:admin 13 | 14 | ## quartzui 15 | - 基于.NET5.0和Quartz.NET3.2.4的任务调度Web界面管理。 16 | - docker方式开箱即用 17 | - 内置SQLite持久化 18 | - 支持 RESTful风格接口 19 | - 业务代码零污染 20 | - 语言无关 21 | - 傻瓜式配置 22 | - 异常请求邮件通知 23 | 24 | ## 使用 25 | - 方式1(docker使用) 26 | ``` 27 | docker run -v /fileData/quartzuifile:/app/File --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui 28 | 29 | 一行命令开箱即用,赶快体验下docker的便捷吧! 30 | 1、其中/fileData/quartzuifile为映射的文件地址,如SQLite数据库和log日志 31 | 2、5088为映射到主机的端口 32 | 3、直接在浏览器 ip:5088 即可访问。(注意防火墙是否打开了5088端口,或者在主机测试 curl 127.0.0.1:5088) 33 | ``` 34 | - 方式2(docker部署树莓派) 35 | ``` 36 | docker run -v /fileData/quartzuifile:/app/File --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui:RaspberryPi 37 | ``` 38 | - 方式3(可直接通过源码部署到windows或linux平台) 39 | 40 | ## 更换数据源 41 | 默认使用的是SQLite-Microsoft 42 | 如果需要使用其他数据源请自行在[appsettings.json](https://github.com/zhaopeiym/quartzui/blob/dev/QuartzNetAPI/Host/appsettings.json)进行正确配置。如: 43 | ``` 44 | "dbProviderName":"OracleODPManaged", 45 | "connectionString": "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=xe)));User Id=system;Password=oracle;"; 46 | 47 | "dbProviderName":"SqlServer", 48 | "connectionString": "Server=localhost;Database=quartznet;User Id={SqlServerUser};Password={SqlServerPassword};"; 49 | 50 | "dbProviderName":"SQLServerMOT", 51 | "connectionString": "Server=localhost,1444;Database=quartznet;User Id={SqlServerUser};Password={SqlServerPassword};" 52 | 53 | "dbProviderName":"MySql", // MySql 测试通过 54 | "connectionString": "Server = localhost; Database = quartznet; Uid = quartznet; Pwd = quartznet"; 55 | 56 | "dbProviderName":"Npgsql", // Npgsql 测试通过 57 | "connectionString": "Server=127.0.0.1;Port=5432;Userid=quartznet;Password=quartznet;Pooling=true;MinPoolSize=1;MaxPoolSize=20;Timeout=15;SslMode=Disable;Database=quartznet"; 58 | 59 | "dbProviderName":"SQLite", 60 | "connectionString": "Data Source=test.db;Version=3;"; 61 | 62 | "dbProviderName":"SQLite-Microsoft", // SQLite-Microsoft 测试通过 63 | "connectionString": "Data Source=test.db;"; 64 | 65 | "dbProviderName":"Firebird", 66 | "connectionString": "User=SYSDBA;Password=masterkey;Database=/firebird/data/quartz.fdb;DataSource=localhost;Port=3050;Dialect=3;Charset=NONE;Role=;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;"; 67 | ``` 68 | 69 | ## 效果图 70 | ![1](https://user-images.githubusercontent.com/5820324/105847993-574c5000-6019-11eb-8779-802fdd172a96.png) 71 | ![2](https://user-images.githubusercontent.com/5820324/56856559-1c267400-6990-11e9-8433-4705e0c4a984.png) 72 | ![3](https://user-images.githubusercontent.com/5820324/56856560-1cbf0a80-6990-11e9-835c-268efac70d50.png) 73 | ![4](https://user-images.githubusercontent.com/5820324/56856561-1cbf0a80-6990-11e9-8af6-a93ad0e09740.png) 74 | ![5](https://user-images.githubusercontent.com/5820324/56856562-1d57a100-6990-11e9-8433-5d6e1d78880a.png) 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /注意.md: -------------------------------------------------------------------------------- 1 | ## 说明(调试、发布) 2 | - 1、前端代码 private baseUrl = "";// "http://localhost:52725"; 开发的时候可以先设置本地接口地址 3 | - 2、发布的时候 ng build --prod ,然后把dist文件夹下的内容拷贝到.net core的wwwroot文件夹下 4 | --------------------------------------------------------------------------------