From 9701794cd18f70a980596bc03f393ea8c702630f Mon Sep 17 00:00:00 2001 From: Hao Date: Fri, 11 Mar 2022 10:51:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BcCenter/BcCenter.Common/App.config | 12 + .../BcCenter.Common/BcCenter.Common.csproj | 94 ++ .../BcCenter.Common/DB/BcCenterDataContext.cs | 142 +++ .../BcCenter.Common/DB/CommonDataContext.cs | 944 ++++++++++++++++++ BcCenter/BcCenter.Common/Helper/MailHelper.cs | 24 + .../Helper/WebRequestHelper.cs | 337 +++++++ BcCenter/BcCenter.Common/JobListener.cs | 126 +++ .../Properties/AssemblyInfo.cs | 36 + .../job_scheduling_data_2_0.xsd | 364 +++++++ BcCenter/BcCenter.Common/packages.config | 9 + BcCenter/BcCenter.Service/App.config | 37 + .../BcCenter.Service/BcCenter.Service.csproj | 123 +++ BcCenter/BcCenter.Service/MailJobService.cs | 52 + BcCenter/BcCenter.Service/Program.cs | 15 + .../Properties/AssemblyInfo.cs | 36 + BcCenter/BcCenter.Service/ReceiveJob.cs | 424 ++++++++ BcCenter/BcCenter.Service/SchedulerJob.cs | 130 +++ .../job_scheduling_data_2_0.xsd | 364 +++++++ BcCenter/BcCenter.Service/packages.config | 14 + BcCenter/BcCenter.Service/quartz_jobs.xml | 159 +++ BcCenter/BcCenter.sln | 31 + 21 files changed, 3473 insertions(+) create mode 100644 BcCenter/BcCenter.Common/App.config create mode 100644 BcCenter/BcCenter.Common/BcCenter.Common.csproj create mode 100644 BcCenter/BcCenter.Common/DB/BcCenterDataContext.cs create mode 100644 BcCenter/BcCenter.Common/DB/CommonDataContext.cs create mode 100644 BcCenter/BcCenter.Common/Helper/MailHelper.cs create mode 100644 BcCenter/BcCenter.Common/Helper/WebRequestHelper.cs create mode 100644 BcCenter/BcCenter.Common/JobListener.cs create mode 100644 BcCenter/BcCenter.Common/Properties/AssemblyInfo.cs create mode 100644 BcCenter/BcCenter.Common/job_scheduling_data_2_0.xsd create mode 100644 BcCenter/BcCenter.Common/packages.config create mode 100644 BcCenter/BcCenter.Service/App.config create mode 100644 BcCenter/BcCenter.Service/BcCenter.Service.csproj create mode 100644 BcCenter/BcCenter.Service/MailJobService.cs create mode 100644 BcCenter/BcCenter.Service/Program.cs create mode 100644 BcCenter/BcCenter.Service/Properties/AssemblyInfo.cs create mode 100644 BcCenter/BcCenter.Service/ReceiveJob.cs create mode 100644 BcCenter/BcCenter.Service/SchedulerJob.cs create mode 100644 BcCenter/BcCenter.Service/job_scheduling_data_2_0.xsd create mode 100644 BcCenter/BcCenter.Service/packages.config create mode 100644 BcCenter/BcCenter.Service/quartz_jobs.xml create mode 100644 BcCenter/BcCenter.sln diff --git a/BcCenter/BcCenter.Common/App.config b/BcCenter/BcCenter.Common/App.config new file mode 100644 index 0000000..2af6916 --- /dev/null +++ b/BcCenter/BcCenter.Common/App.config @@ -0,0 +1,12 @@ + + + + +
+ + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Common/BcCenter.Common.csproj b/BcCenter/BcCenter.Common/BcCenter.Common.csproj new file mode 100644 index 0000000..8ff761a --- /dev/null +++ b/BcCenter/BcCenter.Common/BcCenter.Common.csproj @@ -0,0 +1,94 @@ + + + + + + Debug + AnyCPU + {D26A3DF4-4F5B-4B40-8723-2B9477E754A1} + Library + Properties + BcCenter.Common + BcCenter.Common + v4.6.1 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Common.Logging.3.3.1\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Core.3.3.1\lib\net40\Common.Logging.Core.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\log4net.2.0.14\lib\net45\log4net.dll + + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Quartz.2.6.2\lib\net40\Quartz.dll + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Common/DB/BcCenterDataContext.cs b/BcCenter/BcCenter.Common/DB/BcCenterDataContext.cs new file mode 100644 index 0000000..7f77614 --- /dev/null +++ b/BcCenter/BcCenter.Common/DB/BcCenterDataContext.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BcCenter.Common.DB +{ + public class BcCenterDataContext : DbContext + { + public BcCenterDataContext(string conn) : base(conn) + { + + } + + public BcCenterDataContext() : base("BcCenterDB") + { + + } + + //邮件 + public DbSet Mails { get; set; } + + //附件 + public DbSet Attachments { get; set; } + + //收件邮箱 + public DbSet UserAccounts { get; set; } + + //api账户 + public DbSet ApiAccount { get; set; } + + + } + + //邮件 + [Table("Mails")] + public class Mails + { + public const string SourceTypeMail = "Mail"; + public const string SourceTypeApi = "Api"; + public const string SourceTypeApiDirect = "ApiDirect"; + + public Mails() + { + this.ReceiveTime = DateTime.Now; + this.SourceType = SourceTypeMail; + } + + [Key] + public string GID { get; set; } + public string MailId { get; set; } + public string MailPath { get; set; } + public string SendUserMail { get; set; } + public string MailSubject { get; set; } + public string Status { get; set; } + public DateTime? EmailDate { get; set; } + public DateTime ReceiveTime { get; set; } + public DateTime? UpdateTime { get; set; } + public string CompId { get; set; } + public string CompName { get; set; } + public string UserName { get; set; } + public string MailAccount { get; set; } + public int ImapId { get; set; } + public string MailUrl { get; set; } + public string UserId { get; set; } + public DateTime? MailDate { get; set; } + public string SourceType { get; set; } + } + + //附件 + [Table("Attachments")] + public class Attachments + { + [Key] + public string GID { get; set; } + public string MailGID { get; set; } + public string MailID { get; set; } + public string AttachMD5 { get; set; } + public string AttachPath { get; set; } + public string AttachUrl { get; set; } + public string AttachName { get; set; } + public DateTime CreateTime { get; set; } + public DateTime? UpdateTime { get; set; } + public string Status { get; set; } + public string FileType { get; set; } + public string Tips { get; set; } + public string SendStatus { get; set; } + } + + + [Table("MailUserAccount")] + public class MailUserAccount + { + [Key] + public string GID { get; set; } + public string MailAccount { get; set; } + public string Password { get; set; } + public string ReceiveServer { get; set; } + public bool UseImap { get; set; } + public int ReceivePort { get; set; } + public bool ReceiveSSL { get; set; } + public string SmtpServer { get; set; } + public int SmtpPort { get; set; } + public bool SmtpSSL { get; set; } + public bool IsChanged { get; set; } + public string RelativeId { get; set; } + public int ProcessorCount { get; set; } + public int SenderCount { get; set; } + public string ManagerMailAddress { get; set; } + public int ParserCount { get; set; } + public string UserId { get; set; } + public string CompId { get; set; } + public string UserName { get; set; } + public string CompName { get; set; } + public string CREATEUSER { get; set; } + public DateTime CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + } + + //api账号 + [Table("ApiAccount")] + public class ApiAccount + { + [Key] + public string GID { get; set; } + public string CompanyId { get; set; } + public string CompanyName { get; set; } + public string LoginAccount { get; set; } + public string LoginPassword { get; set; } + public DateTime CreateTime { get; set; } + public DateTime? UpdateTime { get; set; } + public bool IsDisable { get; set; } + public string CreateUser { get; set; } + public string UpdateUser { get; set; } + } + +} diff --git a/BcCenter/BcCenter.Common/DB/CommonDataContext.cs b/BcCenter/BcCenter.Common/DB/CommonDataContext.cs new file mode 100644 index 0000000..e372ef4 --- /dev/null +++ b/BcCenter/BcCenter.Common/DB/CommonDataContext.cs @@ -0,0 +1,944 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; +using System.Web; + +namespace BcCenter.Common.DB +{ + public class CommonDataContext : DbContext + { + public CommonDataContext() : base("DongShengDB") + { + Database.SetInitializer(null); + } + + public CommonDataContext(string conn) : base(conn) + { + Database.SetInitializer(null); + } + + public DbSet ParamSets { get; set; } + + public DbSet SysOpRecords { get; set; } + + public DbSet Users { get; set; } + public DbSet UserBases { get; set; } + public DbSet CompanyNew { get; set; } + + + public DbSet Vessels { get; set; } + public DbSet Voynos { get; set; } + public DbSet Ctns { get; set; } + + public DbSet Issutypes { get; set; } + public DbSet Frts { get; set; } + public DbSet Packages { get; set; } + public DbSet Services { get; set; } + + public DbSet SysPrintInfos { get; set; } + + public DbSet OpSeaeMbT { get; set; } + + + public DbSet FtpSet { get; set; } + public DbSet YardDataSet { get; set; } + + /// + /// 子系统网关配置 + /// + public DbSet SysGateway { get; set; } + + #region edi相关 + public DbSet CodeCtnEdi { get; set; } + public DbSet CodeCustEdi { get; set; } + public DbSet CodePkgsEdi { get; set; } + public DbSet CodeServiceEdi { get; set; } + public DbSet CodeVesselEdi { get; set; } + public DbSet CodeDisportEdi { get; set; } + + #endregion + + //航线 + public DbSet CodeLanes { get; set; } + + #region 权限相关 + + public DbSet UserAuthorityInfo { get; set; } + public DbSet UserAuthorityRanges { get; set; } + + #endregion + + public DbSet BackgroundTaskFtp { get; set; } + + public DbSet BackgroundTaskCommon { get; set; } + + //公司参数 + public DbSet ParamValues { get; set; } + + public void SetValue(Object newObj, Object srcObj, bool dosave = false) + { + var t1s = srcObj.GetType().GetProperties(); + var t2s = newObj.GetType().GetProperties(); + foreach (var p in t1s) + { + foreach (var q in t2s) + { + if (q.Name == p.Name) + {// 这里有可能需要对属性的类型和值做一些判断和转换,大家自己根据自己的业务添加处理,估计不会很多 + q.SetValue(newObj, p.GetValue(srcObj), null); + } + } + } + if (dosave) + SaveChanges(); + } + + + + public DbSet CUST_AUTH { get; set; } + } + + [Table("tb_sys_Dictionary")] + public class Tb_SysDictionary + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long ID { get; set; } + + public string Gid { get; set; } + /// + /// 排序 + /// + public int IndexInt { get; set; } + /// + /// 分组 系统的sys + /// + public string GroupName { get; set; } + /// + /// 分组中的子键值 + /// + public string Key { get; set; } + /// + /// 名称名字 + /// + public string Title { get; set; } + /// + /// 备注 + /// + public string Memo { get; set; } + /// + /// 创建时间戳 + /// + public long AddTime { get; set; } + /// + /// 状态 1 -100 + /// + + public short Status { get; set; } + } + + [Table("tb_SysGateway")] + public class SysGateway + { + + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long ID { get; set; } + + public string Gid { get; set; } + /// + ///子系统Key + /// + public string SysKey { get; set; } + /// + /// 子系统URl格式化模版 + /// + public string Url { get; set; } + /// + /// 备注 + /// + public string Memo { get; set; } + + public DateTime CreateTime { get; set; } + + public short Status { get; set; } + } + + [Table("Sys_OpRecord")] + public class SysOpRecord + { + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int ID { get; set; } + public string ModuleId { get; set; } + public string CateId { get; set; } + public DateTime OpTime { get; set; } + public string UserId { get; set; } + public string UserName { get; set; } + public string CompId { get; set; } + public string CompName { get; set; } + public string ReqAddr { get; set; } + public string ReqParam { get; set; } + public string RespData { get; set; } + public string IpAddr { get; set; } + public string WebBrowser { get; set; } + public string RelativeId { get; set; } + + } + + [Table("Sys_PrintInfo")] + public class SysPrintInfo + { + [Key] + public string GID { get; set; } + public string MODNAME { get; set; } + public string PRINTNAME { get; set; } + public string URL { get; set; } + public DateTime MODIFIEDTIME { get; set; } + public string CRC { get; set; } + } + + + #region code_开头系列 + [Table("code_ctn")] + public class CodeCtn + { + [Key] + public string CTNID { get; set; } + public string CTNSIZE { get; set; } + public string CTNTYPE { get; set; } + public string CTN { get; set; } + public string EDICODE { get; set; } + public decimal? CTNWEIGHT { get; set; } + public string EEXPLAIN { get; set; } + public string CEXPLAIN { get; set; } + public string AFRCODE { get; set; } + public decimal? TEU { get; set; } + public decimal? DLIKGS { get; set; } + public string COSCO { get; set; } + public string EDICODE2 { get; set; } + public string EDICODE3 { get; set; } + public string EDICODE4 { get; set; } + + public string CMACTN { get; set; } + public string CARGOSMARTCTN { get; set; } + } + + /// + /// 付费方式 + /// + [Table("code_frt")] + public class CodeFrt + { + [Key] + public string FEID { get; set; } + public string FRT { get; set; } + public string FRTCNAME { get; set; } + public string EDICODE { get; set; } + public string EDICODE_INTTRA_WEB { get; set; } + } + + [Table("code_goods_inv")] + public class CodeGoodsInv + { + [Key] + public string GID { get; set; } + public string GOODCODE { get; set; } + public string GOODNAME { get; set; } + public string SPEC { get; set; } + public string UNIT { get; set; } + public string DESCRIP { get; set; } + public decimal? TAXRATE { get; set; } + public string TAXNO { get; set; } + public string TAXCLASS { get; set; } + public string TAXCLASSNAME { get; set; } + public string ISTAXPRICE { get; set; } + public string ISUSEPREF { get; set; } + public string ISDEF { get; set; } + public string ZTAXTYPE { get; set; } + public string DEFREMARK { get; set; } + public bool? ISSTOP { get; set; } + public string GoodsTypeGID { get; set; } + public string DEFCURR { get; set; } + + public string CompId { get; set; } + public string CompName { get; set; } + public string CreateUser { get; set; } + public DateTime CreateTime { get; set; } + } + + /// + /// 签单方式 + /// + [Table("code_issutype")] + public class CodeIssutype + { + [Key] + public string GID { get; set; } + public string BLTYPE { get; set; } + } + + /// + /// 包装 + /// + [Table("code_package")] + public class CodePackage + { + [Key] + public string GID { get; set; } + public string PKGS { get; set; } + public string CEXPLAIN { get; set; } + public string EDICODE { get; set; } + public string AFRCODE { get; set; } + public string cosco { get; set; } + } + + /// + /// 运输条款 + /// + [Table("code_service")] + public class CodeService + { + [Key] + public string GID { get; set; } + public string SERVICE { get; set; } + } + + [Table("code_vessel")] + public class CodeVessel + { + [Key] + public string VSID { get; set; } + public string VESSEL { get; set; } + public string CNAME { get; set; } + public string CARRIER { get; set; } + public string EDICODE { get; set; } + } + + [Table("code_voyno")] + public class CodeVoyno + { + [Key] + public string VOID { get; set; } + public string VSID { get; set; } + public string VOYNO { get; set; } + public string PORTLOAD { get; set; } + public string PORTDISCHARGE { get; set; } + public DateTime? ETD { get; set; } + public DateTime? CLOSINGDATE { get; set; } + public DateTime? ETA { get; set; } + public string CORPID { get; set; } + public string YARDID { get; set; } + public string ENTREPORT { get; set; } + public string VESSEL { get; set; } + public DateTime? ATD { get; set; } + + public string VOYNO_FORWARDER { get; set; } + public string FORWARDER { get; set; } + public string CARRIER { get; set; } + public DateTime? CLOSEDOCDATE { get; set; } + public DateTime? CLOSEVGMDATE { get; set; } + + } + + + + [Table("code_currency")] + public class CodeCurrency + { + [Key] + public string GID { get; set; } + public string CODENAME { get; set; } + public string NAME { get; set; } + public string DESCRIPTION { get; set; } + public decimal? DEFAULTRATE { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + public string FINANCESOFTCODE { get; set; } + } + + [Table("code_goods_inv_template")] + public class CodeGoodsInvTemplate + { + [Key] + public string GID { get; set; } + public string GOODCODE { get; set; } + public string GOODNAME { get; set; } + public string SPEC { get; set; } + public string UNIT { get; set; } + public string DESCRIP { get; set; } + public decimal? TAXRATE { get; set; } + public string TAXNO { get; set; } + public string TAXCLASS { get; set; } + public string TAXCLASSNAME { get; set; } + public string ISTAXPRICE { get; set; } + public string ISUSEPREF { get; set; } + public string ISDEF { get; set; } + public string ZTAXTYPE { get; set; } + public string DEFREMARK { get; set; } + public string TradeType { get; set; } + } + + + #region edi相关 + //集装箱 + [Table("code_ctn_edi")] + public class CodeCtnEdi + { + [Key] + public string GID { get; set; } + public string CTN { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + } + + //往来单位 + [Table("code_cust_edi")] + public class CodeCustEdi + { + [Key] + public string GID { get; set; } + public string CUST { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string PORTSIDE { get; set; } + public string SENDINFO { get; set; } + } + + //包装 + [Table("code_pkgs_edi")] + public class CodePkgsEdi + { + [Key] + public string GID { get; set; } + public string PKGS { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + } + + //运输条款 + [Table("code_service_edi")] + public class CodeServiceEdi + { + [Key] + public string GID { get; set; } + public string SERVICE { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + } + + //船名 + [Table("code_vessel_edi")] + public class CodeVesselEdi + { + [Key] + public string GID { get; set; } + public string VESSEL { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + } + + //港口 + [Table("code_disport_edi")] + public class CodeDisportEdi + { + [Key] + public string GID { get; set; } + public string PORTDISCHARGE { get; set; } + public string EDICODE { get; set; } + public string EDINAME { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string PORTID { get; set; } + } + + + + + #endregion + + + //ftp设置 + [Table("code_ftpset")] + public class CodeFtpset + { + [Key] + public string GID { get; set; } + public string EDINAME { get; set; } + public string SERVERIP { get; set; } + public string FOLDERNAME { get; set; } + public string USERNAME { get; set; } + public string PASSWORD { get; set; } + public string CORPID { get; set; } + public string SENDCODE { get; set; } + public string RECEIVECODE { get; set; } + public string SENDNAME { get; set; } + public string SENDATTN { get; set; } + public string SENDTEL { get; set; } + public string SENDEMAIL { get; set; } + public string SENDCOMPANYCODE { get; set; } + public string SENDSUBCOMPANYCODE { get; set; } + public string CARRIERID { get; set; } + public string RECEIVEEMAIL { get; set; } + public string RECEIVESIEMAIL { get; set; } + public string RECEIVEOP { get; set; } + public string RECEIVESALE { get; set; } + public string RECEIVEDEPT { get; set; } + public string SHIPPERTEL { get; set; } + public string CONSIGNEETEL { get; set; } + public string NOTIFYPARTYTEL { get; set; } + public string ISUSETEL { get; set; } + public string CompId { get; set; } + public string CompName { get; set; } + } + + //场站对应 + [Table("code_yarddata_set")] + public class CodeYardDataSet + { + [Key] + public string GID { get; set; } + public string YARDCODE { get; set; } + public string YARD { get; set; } + public string LOGINNAME { get; set; } + public string PASSWORD { get; set; } + public string REMARK { get; set; } + public string COMPANYID { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + + public string YitongCode { get; set; } + public string YitongName { get; set; } + } + + [Table("code_lanes")] + public class CodeLanes + { + [Key] + public string GID { get; set; } + public string LANEID { get; set; } + public string LANE { get; set; } + public string LANEEN { get; set; } + public string EDICODE { get; set; } + public string OP { get; set; } + public string DOC { get; set; } + } + + #endregion + + /// + /// 托单收发通模板 + /// + [Table("op_seae_t_mb")] + public class OpSeaeMbT + { + [Key] + public string gid { get; set; } + public string mbname { get; set; } + public string mbtype { get; set; } + public string mbtext { get; set; } + public DateTime? createtime { get; set; } + public string userid { get; set; } + public string CompId { get; set; } + } + + #region 权限相关 + + [Table("user_action")] + public class UserAction + { + [Key] + public string GID { get; set; } + public string ACTIONID { get; set; } + public string USERID { get; set; } + public string CREATEUSER { get; set; } + public DateTime CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + } + + [Table("user_authority_range")] + public class UserAuthorityRange + { + [Key] + public string GID { get; set; } + public string USERID { get; set; } + public string AUTHORITYID { get; set; } + public int? VISIBLERANGE { get; set; } + public int? OPERATERANGE { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + } + + [Table("VW_User_Authority")] + public class VUserAuthority + { + [Key] + public string GID { get; set; } + public string USERID { get; set; } + public int VISIBLERANGE { get; set; } + public int OPERATERANGE { get; set; } + public bool? ISDELETE { get; set; } + public string DESCRIPTION { get; set; } + public string NAME { get; set; } + public string MODULEURL { get; set; } + public string AUTHORITYID { get; set; } + public bool? ISALL { get; set; } + public bool? ISCOMPANY { get; set; } + public bool? ISDEPT { get; set; } + public bool? ISPERSON { get; set; } + } + + [Table("AuthUserVirtualModule")] + public class AuthUserVirtualModule + { + public const string RangePersonal = "Personal"; + public const string RangeAll = "All"; + + [Key] + public string GId { get; set; } + public string ModuleId { get; set; } + public string UserId { get; set; } + public bool HasAuth { get; set; } + public string RangeViewValue { get; set; } + public string RangeOperateValue { get; set; } + } + + [Table("AuthVirtualModule")] + public class AuthVirtualModule + { + [Key] + public string GId { get; set; } + public string ModuleName { get; set; } + public string ParentId { get; set; } + public string ModuleMap { get; set; } + public string RangeMap { get; set; } + public int Sort { get; set; } + } + + [Table("user_authority_info")] + public class UserAuthorityInfo + { + [Key] + public string GID { get; set; } + public string NAME { get; set; } + public string DESCRIPTION { get; set; } + public string MODULEURL { get; set; } + public bool? ISALL { get; set; } + public bool? ISCOMPANY { get; set; } + public bool? ISDEPT { get; set; } + public bool? ISPERSON { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + public bool? ISDELETE { get; set; } + } + #endregion + + //后台ftp任务 + [Table("BackgroundTaskFtp")] + public class BackgroundTaskFtp + { + public BackgroundTaskFtp() + { + Status = StatusCreate; + CreateTime = DateTime.Now; + } + + /// + /// 上传ftp + /// + public const string TypeFtpUpload = "FtpUpload"; + + + /// + /// 新建 + /// + public const string StatusCreate = "Create"; + + /// + /// 正在执行 + /// + public const string StatusDoing = "Doing"; + + /// + /// 执行成功 + /// + public const string StatusSuccess = "Success"; + + /// + /// 执行失败 + /// + public const string StatusFail = "Fail"; + + [Key] + public string GID { get; set; } + public string Type { get; set; } + public string FtpHost { get; set; } + public string FtpUser { get; set; } + public string FtpPassword { get; set; } + public string FtpData { get; set; } + public DateTime CreateTime { get; set; } + public int TryCount { get; set; } + public DateTime? LastDo { get; set; } + public string Status { get; set; } + public string Remark { get; set; } + } + + + //后台任务(通用) + [Table("BackgroundTaskCommon")] + public class BackgroundTaskCommon + { + /// + /// 订舱自动放舱 + /// + public const string TypeBookingFangCang = "BookingFangCang"; + + /// + /// 订舱BC + /// + public const string TypeBookingBC = "BookingBC"; + + /// + /// 回写SI状态 + /// + public const string TypeBookingPostSiStatus = "PostSiStatus"; + + /// + /// HTTP Feedback + /// + public const string TypeHttpFeedback = "HttpFeedback"; + + /// + /// 下货纸 + /// + public const string TypeBookingXiahuozhi = "Xiahuozhi"; + + /// + /// VGM核查 + /// + public const string TypeVgmCheck = "VgmCheck"; + + /// + /// 重新比较BC、发送下货纸任务 + /// + public const string TypeCompareBcRedo = "CompareBcRedo"; + + public const string StatusCreate = "Create"; + public const string StatusDoing = "Doing"; + public const string StatusSuccess = "Success"; + public const string StatusFail = "Fail"; + + public BackgroundTaskCommon() + { + CreateTime = DateTime.Now; + Status = StatusCreate; + } + + [Key] + public string GID { get; set; } + public string Type { get; set; } + public string ParamData { get; set; } + public string Status { get; set; } + public DateTime CreateTime { get; set; } + public int ExecuteCount { get; set; } + public DateTime? ExecuteTime { get; set; } + public string ResultData { get; set; } + } + + [Table("CUST_AUTH")] + public class CUST_AUTH + { + [Key] + public string GID { get; set; } + public string USERID { get; set; } + public string SKEY { get; set; } + public int? BSTYPE { get; set; } + public DateTime CREATETIME { get; set; } + public string username { get; set; } + public string comname { get; set; } + public string Module { get; set; } + public string ModuleJson { get; set; } + public string IpBlackList { get; set; } + public string IpWhiteList { get; set; } + public int Status { get; set; } + } + + [Table("company_new")] + public class CompanyNew + { + public const string AuditStatusNotSubmit = "NotSubmit"; + public const string AuditStatusAuditing = "Auditing"; + public const string AuditStatusSuccess = "Success"; + public const string AuditStatusReject = "Reject"; + + [Key] + public string CompId { get; set; } + public string CompName { get; set; } + public string SourceName { get; set; } + public int AlertMinValue { get; set; } + public string AuditStatus { get; set; } + public string AuditText { get; set; } + public string AdminUser { get; set; } + public string AdminShowName { get; set; } + public string Address { get; set; } + public string Tel { get; set; } + public string TaxCode { get; set; } + /// + /// 海关登记号 + /// + public string CustomsCode { get; set; } + public string BankName { get; set; } + public string BankAccount { get; set; } + public string LicenceImage { get; set; } + public string InvoiceSystem { get; set; } + public string InvoiceApi { get; set; } + + public string EmailShowName { get; set; } + + public bool MinValueSMS { get; set; } + public bool MinValueEmail { get; set; } + public string MinValueEmailAddr { get; set; } + } + + [Table("user")] + public class User + { + [Key] + public string GID { get; set; } + public string USERNAME { get; set; } + public string CODENAME { get; set; } + public string PASSWORD { get; set; } + public string SHOWNAME { get; set; } + public DateTime? ENROLLTIME { get; set; } + public string CREATEUSER { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + public bool? ISDELETED { get; set; } + public bool? ISDISABLE { get; set; } + public string DELETEUSER { get; set; } + public DateTime? DELETETIME { get; set; } + public string NOCODE { get; set; } + public string OPENID { get; set; } + public string WeChatAccount { get; set; } + public string FaSongFangDaiMa { get; set; } + public string ptPhone { get; set; } + public string ptEmail { get; set; } + public string comid { get; set; } + public bool isAllowGenerate { get; set; } + public bool isAllowSend { get; set; } + public string COMNAME { get; set; } + public string YAOQINGMA { get; set; } + public string cscode { get; set; } + public string COMTYPE { get; set; } + + //用户绑定公司的ID,认证后或加入公司后,置值所属公司的ID + public string CompId { get; set; } + } + + [Table("user_baseinfo")] + public class UserBaseinfo + { + [Key] + public string GID { get; set; } + public string USERID { get; set; } + public string COMPANYNAME { get; set; } + public string DEPTNAME { get; set; } + public string OFFICEPHONE { get; set; } + public string HOMEPHONE { get; set; } + public string MOBILE { get; set; } + public string FAX { get; set; } + public string EMAIL1 { get; set; } + public string EMAIL2 { get; set; } + public string HOMEADDRESS { get; set; } + public string REMARK { get; set; } + public string CREATEUSER { get; set; } + public DateTime? CREATETIME { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + public string EMERGUSER { get; set; } + public string EMERGPHONE { get; set; } + public string EMERGEMAIL { get; set; } + public string POSTCODE { get; set; } + public string QQ { get; set; } + public string MSN { get; set; } + public string FINANCESOFTCODE { get; set; } + public string IMAGEURL { get; set; } + public string SIGNATUREURL { get; set; } + public string FaSongFangDaiMa { get; set; } + public string JieShouFangDaiMa { get; set; } + public string QdPortUserName { get; set; } + public string QdPortPassword { get; set; } + } + + [Table("sys_param_set")] + public class ParamSet + { + [Key] + public string GID { get; set; } + public string PARAMNAME { get; set; } + public string PARAMDESCRIPTION { get; set; } + public string PARAMVALUE { get; set; } + public string MODIFIEDUSER { get; set; } + public DateTime? MODIFIEDTIME { get; set; } + public string PARAMTYPE { get; set; } + public string FIELDTYPE { get; set; } + } + + + //公司参数 + [Table("company_new_param")] + public class CompanyNewParam + { + [Key] + public string ParaCode { get; set; } + public string ParaName { get; set; } + public string Remark { get; set; } + } + + //公司参数项 + [Table("company_new_param_item")] + public class CompanyNewParamItem + { + [Key, Column(Order = 0)] + public string ParaCode { get; set; } + [Key, Column(Order = 1)] + public string ItemCode { get; set; } + public string ItemName { get; set; } + public string Remark { get; set; } + } + + //公司参数值 + [Table("company_new_param_value")] + public class CompanyNewParamValue + { + [Key, Column(Order = 0)] + public string ParaCode { get; set; } + [Key, Column(Order = 1)] + public string CompId { get; set; } + public string ItemCode { get; set; } + public string Remark { get; set; } + } +} \ No newline at end of file diff --git a/BcCenter/BcCenter.Common/Helper/MailHelper.cs b/BcCenter/BcCenter.Common/Helper/MailHelper.cs new file mode 100644 index 0000000..307515b --- /dev/null +++ b/BcCenter/BcCenter.Common/Helper/MailHelper.cs @@ -0,0 +1,24 @@ +using log4net; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BcCenter.Common.Helper +{ + public static class MailHelper + { + private static ILog logger = LogManager.GetLogger("MailHelper"); + public static void SendMailService(string title, string body, string recUser) + { + var url = ConfigurationManager.AppSettings["MailSendServiceUrl"]; + logger.Debug($"发送邮件【{title}】到【{recUser}】:{url}"); + var rtn = WebRequestHelper.DoPost(url, JsonConvert.SerializeObject(new { })); + logger.Debug($"发送邮件返回:{rtn}"); + } + + } +} diff --git a/BcCenter/BcCenter.Common/Helper/WebRequestHelper.cs b/BcCenter/BcCenter.Common/Helper/WebRequestHelper.cs new file mode 100644 index 0000000..618576a --- /dev/null +++ b/BcCenter/BcCenter.Common/Helper/WebRequestHelper.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using System.Text; +using System.Web; + +namespace BcCenter.Common.Helper +{ + public static class WebRequestHelper + { + public static string DoGet(string url, int timeout = 3000, Dictionary dicHead = null) + { + string responseString = "";//post返回的结果 + ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, err) => { return true; }; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); + req.Method = "GET"; + req.ContentLength = 0; + req.Timeout = timeout; + req.KeepAlive = false; + + if (dicHead != null && dicHead.Count > 0) + { + foreach (var key in dicHead.Keys) + { + req.Headers.Add(key, dicHead[key]); + } + } + + var response = req.GetResponse(); + Stream streamResponse = response.GetResponseStream(); + StreamReader streamRead = new StreamReader(streamResponse); + responseString = streamRead.ReadToEnd(); + response.Close(); + streamRead.Close(); + + return responseString; + } + /// + /// Post Json提交 + /// + /// + /// + /// + /// + public static string DoPostJson(string url, object PostData, int timeout = 10000) => DoPost(url, Newtonsoft.Json.JsonConvert.SerializeObject(PostData), timeout); + public static string DoPost(string url, string json, int timeout = 10000, Dictionary dicHead = null) + { + string responseString = "";//post返回的结果 + ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, err) => { return true; }; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); + req.Method = "POST"; + req.Timeout = timeout; + + if (dicHead != null && dicHead.Count > 0) + { + foreach (var key in dicHead.Keys) + { + req.Headers.Add(key, dicHead[key]); + } + } + + if (!string.IsNullOrWhiteSpace(json)) + { + byte[] postBytes = Encoding.UTF8.GetBytes(json); + req.ContentType = "application/json; charset=utf-8"; + req.ContentLength = Encoding.UTF8.GetByteCount(json); + Stream stream = req.GetRequestStream(); + stream.Write(postBytes, 0, postBytes.Length); + stream.Close(); + } + else + { + req.ContentLength = 0; + } + var response = req.GetResponse(); + Stream streamResponse = response.GetResponseStream(); + StreamReader streamRead = new StreamReader(streamResponse); + responseString = streamRead.ReadToEnd(); + response.Close(); + streamRead.Close(); + + return responseString; + } + + public static string DoPost(string url, Dictionary dic, int timeout = 10000) + { + string responseString = "";//post返回的结果 + ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, err) => { return true; }; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); + req.Method = "POST"; + req.Timeout = timeout; + req.Headers.Add("Accept-Encoding", "gzip, deflate"); + + if (dic.Count > 0) + { + string strContent = string.Empty; + foreach (var item in dic) + { + if (strContent.Length > 0) + { + strContent += "&"; + } + strContent += $"{item.Key}={item.Value}"; + } + + byte[] postBytes = Encoding.UTF8.GetBytes(strContent); + req.ContentType = "application/x-www-form-urlencoded"; + req.ContentLength = postBytes.Length; + Stream stream = req.GetRequestStream(); + stream.Write(postBytes, 0, postBytes.Length); + stream.Close(); + } + else + { + req.ContentLength = 0; + } + var response = req.GetResponse(); + responseString = GetResponseBody((HttpWebResponse)response); + return responseString; + } + + + private static string GetResponseBody(HttpWebResponse response) + { + string responseBody = string.Empty; + if (response.ContentEncoding.ToLower().Contains("gzip")) + { + using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress)) + { + using (StreamReader reader = new StreamReader(stream)) + { + responseBody = reader.ReadToEnd(); + } + } + } + else if (response.ContentEncoding.ToLower().Contains("deflate")) + { + using (DeflateStream stream = new DeflateStream( + response.GetResponseStream(), CompressionMode.Decompress)) + { + using (StreamReader reader = + new StreamReader(stream, Encoding.UTF8)) + { + responseBody = reader.ReadToEnd(); + } + } + } + else + { + using (Stream stream = response.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + responseBody = reader.ReadToEnd(); + } + } + } + return responseBody; + } + + + + /// + /// 使用Post方法获取字符串结果 + /// + /// + /// Post表单内容 + /// 默认20秒 + /// + public static string PostForm(string url, List formItems, int timeOut = 20000) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + #region 初始化请求对象 + request.Method = "POST"; + request.Timeout = timeOut; + request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; + request.KeepAlive = true; + request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"; + #endregion + + string boundary = "----" + DateTime.Now.Ticks.ToString("x");//分隔符 + request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); + //请求流 + var postStream = new MemoryStream(); + #region 处理Form表单请求内容 + //是否用Form上传文件 + var formUploadFile = formItems != null && formItems.Count > 0; + if (formUploadFile) + { + //文件数据模板 + string fileFormdataTemplate = + "\r\n--" + boundary + + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + + "\r\nContent-Type: application/octet-stream" + + "\r\n\r\n"; + //文本数据模板 + string dataFormdataTemplate = + "\r\n--" + boundary + + "\r\nContent-Disposition: form-data; name=\"{0}\"" + + "\r\n\r\n{1}"; + foreach (var item in formItems) + { + string formdata = null; + if (item.IsFile) + { + //上传文件 + formdata = string.Format( + fileFormdataTemplate, + item.Key, //表单键 + item.FileName); + } + else + { + //上传文本 + formdata = string.Format( + dataFormdataTemplate, + item.Key, + item.Value); + } + + //统一处理 + byte[] formdataBytes = null; + //第一行不需要换行 + if (postStream.Length == 0) + formdataBytes = Encoding.UTF8.GetBytes(formdata.Substring(2, formdata.Length - 2)); + else + formdataBytes = Encoding.UTF8.GetBytes(formdata); + postStream.Write(formdataBytes, 0, formdataBytes.Length); + + //写入文件内容 + if (item.FileContent != null && item.FileContent.Length > 0) + { + using (var stream = item.FileContent) + { + byte[] buffer = new byte[1024]; + int bytesRead = 0; + while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) + { + postStream.Write(buffer, 0, bytesRead); + } + } + } + } + //结尾 + var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n"); + postStream.Write(footer, 0, footer.Length); + + } + else + { + request.ContentType = "application/x-www-form-urlencoded"; + } + #endregion + + request.ContentLength = postStream.Length; + + #region 输入二进制流 + if (postStream != null) + { + postStream.Position = 0; + //直接写入流 + Stream requestStream = request.GetRequestStream(); + + byte[] buffer = new byte[1024]; + int bytesRead = 0; + while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0) + { + requestStream.Write(buffer, 0, bytesRead); + } + + //postStream.Seek(0, SeekOrigin.Begin); + //StreamReader sr = new StreamReader(postStream); + //var postStr = sr.ReadToEnd(); + postStream.Close();//关闭文件访问 + } + #endregion + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + + using (Stream responseStream = response.GetResponseStream()) + { + using (StreamReader myStreamReader = new StreamReader(responseStream, Encoding.UTF8)) + { + string retString = myStreamReader.ReadToEnd(); + return retString; + } + } + } + } + + + + /// + /// 表单数据项 + /// + public class FormItemModel + { + /// + /// 表单键,request["key"] + /// + public string Key { set; get; } + /// + /// 表单值,上传文件时忽略,request["key"].value + /// + public string Value { set; get; } + /// + /// 是否是文件 + /// + public bool IsFile + { + get + { + if (FileContent == null || FileContent.Length == 0) + return false; + + if (FileContent != null && FileContent.Length > 0 && string.IsNullOrWhiteSpace(FileName)) + throw new Exception("上传文件时 FileName 属性值不能为空"); + return true; + } + } + /// + /// 上传的文件名 + /// + public string FileName { set; get; } + /// + /// 上传的文件内容 + /// + public Stream FileContent { set; get; } + } + +} \ No newline at end of file diff --git a/BcCenter/BcCenter.Common/JobListener.cs b/BcCenter/BcCenter.Common/JobListener.cs new file mode 100644 index 0000000..b44a9ed --- /dev/null +++ b/BcCenter/BcCenter.Common/JobListener.cs @@ -0,0 +1,126 @@ +using log4net; +using Quartz; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BcCenter.Common +{ + public class JobListener : ISchedulerListener + { + private ILog logger = LogManager.GetLogger("JobListener"); + + public void JobAdded(IJobDetail jobDetail) + { + logger.Debug($"Job被添加:{jobDetail.JobType}"); + } + + public void JobDeleted(JobKey jobKey) + { + + } + + public void JobPaused(JobKey jobKey) + { + + } + + public void JobResumed(JobKey jobKey) + { + + } + + public void JobScheduled(ITrigger trigger) + { + + } + + public void JobsPaused(string jobGroup) + { + + } + + public void JobsResumed(string jobGroup) + { + + } + + public void JobUnscheduled(TriggerKey triggerKey) + { + + } + + public void SchedulerError(string msg, SchedulerException cause) + { + logger.Error(msg); + + var excep = cause as Exception; + while (true) + { + logger.Error(excep.Message); + logger.Error(excep.StackTrace); + + excep = excep.InnerException; + } + + } + + public void SchedulerInStandbyMode() + { + + } + + public void SchedulerShutdown() + { + logger.Debug($"SchedulerShutdown"); + } + + public void SchedulerShuttingdown() + { + + } + + public void SchedulerStarted() + { + logger.Debug($"SchedulerStarted"); + + } + + public void SchedulerStarting() + { + + } + + public void SchedulingDataCleared() + { + + } + + public void TriggerFinalized(ITrigger trigger) + { + + } + + public void TriggerPaused(TriggerKey triggerKey) + { + + } + + public void TriggerResumed(TriggerKey triggerKey) + { + + } + + public void TriggersPaused(string triggerGroup) + { + + } + + public void TriggersResumed(string triggerGroup) + { + + } + } +} diff --git a/BcCenter/BcCenter.Common/Properties/AssemblyInfo.cs b/BcCenter/BcCenter.Common/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f5efde3 --- /dev/null +++ b/BcCenter/BcCenter.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("BcCenter.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BcCenter.Common")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("d26a3df4-4f5b-4b40-8723-2b9477e754a1")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BcCenter/BcCenter.Common/job_scheduling_data_2_0.xsd b/BcCenter/BcCenter.Common/job_scheduling_data_2_0.xsd new file mode 100644 index 0000000..7bff0f0 --- /dev/null +++ b/BcCenter/BcCenter.Common/job_scheduling_data_2_0.xsd @@ -0,0 +1,364 @@ + + + + + + + Root level node + + + + + + Commands to be executed before scheduling the jobs and triggers in this file. + + + + + Directives to be followed while scheduling the jobs and triggers in this file. + + + + + + + + + + + + + + Version of the XML Schema instance + + + + + + + + + + Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. + + + + + Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. + + + + + Delete the identified job if it exists (will also result in deleting all triggers related to it). + + + + + + + + + + + Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). + + + + + + + + + + + + + + + + Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. + + + + + If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. + + + + + If true trigger's start time is calculated based on earlier run time instead of fixed value. Trigger's start time must be undefined for this to work. + + + + + + + + Define a JobDetail + + + + + + + + + + + + + + + + + Define a JobDataMap + + + + + + + + + Define a JobDataMap entry + + + + + + + + + + Define a Trigger + + + + + + + + + + + Common Trigger definitions + + + + + + + + + + + + + + + + + + + + + + + Define a SimpleTrigger + + + + + + + + + + + + + + + + + Define a CronTrigger + + + + + + + + + + + + + + + Define a DateIntervalTrigger + + + + + + + + + + + + + + + + Cron expression (see JavaDoc for examples) + + Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! + + Regular expressions are not my strong point but I believe this is complete, + with the caveat that order for expressions like 3-0 is not legal but will pass, + and month and day names must be capitalized. + If you want to examine the correctness look for the [\s] to denote the + seperation of individual regular expressions. This is how I break them up visually + to examine them: + + SECONDS: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + MINUTES: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + HOURS: + ( + ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) + | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) + | ([\?]) + | ([\*]) + ) [\s] + DAY OF MONTH: + ( + ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) + | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) + | (L(-[0-9])?) + | (L(-[1-2][0-9])?) + | (L(-[3][0-1])?) + | (LW) + | ([1-9]W) + | ([1-3][0-9]W) + | ([\?]) + | ([\*]) + )[\s] + MONTH: + ( + ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) + | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) + | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) + | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) + | ([\?]) + | ([\*]) + )[\s] + DAY OF WEEK: + ( + (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) + | ([1-7]/([1-7])) + | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) + | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) + | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) + | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) + | ([\?]) + | ([\*]) + ) + YEAR (OPTIONAL): + ( + [\s]? + ([\*])? + | ((19[7-9][0-9])|(20[0-9][0-9]))? + | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? + | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? + ) + + + + + + + + + + Number of times to repeat the Trigger (-1 for indefinite) + + + + + + + + + + Simple Trigger Misfire Instructions + + + + + + + + + + + + + + + Cron Trigger Misfire Instructions + + + + + + + + + + + + Date Interval Trigger Misfire Instructions + + + + + + + + + + + + Interval Units + + + + + + + + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Common/packages.config b/BcCenter/BcCenter.Common/packages.config new file mode 100644 index 0000000..1cfaca1 --- /dev/null +++ b/BcCenter/BcCenter.Common/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Service/App.config b/BcCenter/BcCenter.Service/App.config new file mode 100644 index 0000000..8138751 --- /dev/null +++ b/BcCenter/BcCenter.Service/App.config @@ -0,0 +1,37 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Service/BcCenter.Service.csproj b/BcCenter/BcCenter.Service/BcCenter.Service.csproj new file mode 100644 index 0000000..3048fd1 --- /dev/null +++ b/BcCenter/BcCenter.Service/BcCenter.Service.csproj @@ -0,0 +1,123 @@ + + + + + + Debug + AnyCPU + {3A539117-F2B7-4B78-8849-48DE29370F09} + Exe + BcCenter.Service + BcCenter.Service + v4.6.1 + 512 + true + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll + + + ..\packages\Common.Logging.3.3.1\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Core.3.3.1\lib\net40\Common.Logging.Core.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\log4net.2.0.14\lib\net45\log4net.dll + + + ..\packages\MailKit.3.1.1\lib\net46\MailKit.dll + + + ..\packages\MimeKit.3.1.1\lib\net46\MimeKit.dll + + + ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Quartz.2.6.2\lib\net40\Quartz.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + + + + + + + + + + + + + + ..\packages\Topshelf.4.2.1\lib\net452\Topshelf.dll + + + + + + + + + + + + + Designer + + + + + + + + + {d26a3df4-4f5b-4b40-8723-2b9477e754a1} + BcCenter.Common + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Service/MailJobService.cs b/BcCenter/BcCenter.Service/MailJobService.cs new file mode 100644 index 0000000..09b6c7b --- /dev/null +++ b/BcCenter/BcCenter.Service/MailJobService.cs @@ -0,0 +1,52 @@ +using BcCenter.Common; +using log4net; +using Quartz; +using Quartz.Impl; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Topshelf; + +namespace BcCenter.Service +{ + public class MailJobService : ServiceControl + { + private static ILog logger = LogManager.GetLogger("MailJobService"); + + private IScheduler scheduler; + + public bool Start(HostControl hostControl) + { + // 开始具体的业务逻辑 + logger.Debug("开始运行"); + + try + { + scheduler = StdSchedulerFactory.GetDefaultScheduler(); + scheduler.ListenerManager.AddSchedulerListener(new JobListener()); + scheduler.Start(); + + } + catch (Exception ex) + { + logger.Error("启动出错:"); + logger.Error(ex.Message); + logger.Error(ex.StackTrace); + } + + return true; + } + + public bool Stop(HostControl hostControl) + { + // 结束 + logger.Debug("停止运行"); + + scheduler.Shutdown(); + + return true; + } + } +} diff --git a/BcCenter/BcCenter.Service/Program.cs b/BcCenter/BcCenter.Service/Program.cs new file mode 100644 index 0000000..dbbdfc1 --- /dev/null +++ b/BcCenter/BcCenter.Service/Program.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BcCenter.Service +{ + class Program + { + static void Main(string[] args) + { + } + } +} diff --git a/BcCenter/BcCenter.Service/Properties/AssemblyInfo.cs b/BcCenter/BcCenter.Service/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..97f2f79 --- /dev/null +++ b/BcCenter/BcCenter.Service/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("BcCenter.Service")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BcCenter.Service")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("3a539117-f2b7-4b78-8849-48de29370f09")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BcCenter/BcCenter.Service/ReceiveJob.cs b/BcCenter/BcCenter.Service/ReceiveJob.cs new file mode 100644 index 0000000..aeeb48b --- /dev/null +++ b/BcCenter/BcCenter.Service/ReceiveJob.cs @@ -0,0 +1,424 @@ + +using log4net; +using MailKit; +using MailKit.Net.Imap; +using MailKit.Search; +using MimeKit; +using Quartz; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Runtime.Caching; +using System.Text.RegularExpressions; +using MimeKit.Utils; +using MailKit.Security; +using System.Configuration; +using System.Security.Cryptography; +using MimeKit.Encodings; +using BcCenter.Common.DB; +using BcCenter.Common.Helper; + +namespace BcCenter.Service +{ + public class ReceiveJob : IJob + { + ILog log = LogManager.GetLogger(typeof(ReceiveJob)); + + private const string KeyRecMail = "RecMail_"; + private static string EmlSavePath = ConfigurationManager.AppSettings["EmlSavePath"]; + private static string fileDownloadUrl = ConfigurationManager.AppSettings["FileDownloadUrl"]; + + public void Execute(IJobExecutionContext context) + { + try + { + string account = context.JobDetail.JobDataMap.GetString("Account"); + string password = context.JobDetail.JobDataMap.GetString("Password"); + + string imapServer = context.JobDetail.JobDataMap.GetString("ImapServer"); + int imapPort = context.JobDetail.JobDataMap.GetInt("ImapPort"); + bool imapSSL = context.JobDetail.JobDataMap.GetBoolean("ImapSSL"); + + string smtpServer = context.JobDetail.JobDataMap.GetString("SmtpServer"); + int stmpPort = context.JobDetail.JobDataMap.GetInt("SmtpPort"); + bool smtpSSL = context.JobDetail.JobDataMap.GetBoolean("SmtpSSL"); + + if (!fileDownloadUrl.EndsWith("/")) + { + fileDownloadUrl += "/"; + } + + string keyMem = KeyRecMail + account; + if (MemoryCache.Default.Contains(keyMem)) + { + log.Debug($"其他线程正收取邮件:{account}"); + return; + } + + MemoryCache.Default.Add(new CacheItem(keyMem, true), new CacheItemPolicy() { AbsoluteExpiration = DateTime.Now.AddMinutes(2) }); + + log.Debug($"正在收取邮箱{account}的邮件……"); + + DateTime mailDate = DateTime.Today; + //DateTime mailDate = DateTime.Parse("2019-06-10"); + using (var imapClient = new ImapClient()) + { + imapClient.ServerCertificateValidationCallback = (s, c, h, e) => true; + log.Debug($"正在连接邮件服务器:{imapServer}:{imapPort},SSL:{imapSSL}"); + imapClient.Connect(imapServer, imapPort, imapSSL ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.None); + log.Debug($"正在登录邮件服务器,账号:{account}"); + imapClient.Authenticate(account, password); + + var inbox = imapClient.Inbox; + inbox.Open(FolderAccess.ReadOnly); + + var uids = inbox.Search(SearchQuery.DeliveredAfter(mailDate.AddDays(-1))); + log.Debug($"{account}邮件数量:{uids.Count}"); + + string savePath = string.Empty; + if (!string.IsNullOrEmpty(EmlSavePath)) + { + savePath = Path.Combine(EmlSavePath, $"BillCenter\\{mailDate.ToString("yyyyMMdd")}\\{account}"); + } + else + { + savePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"BillCenter\\{mailDate.ToString("yyyyMMdd")}\\{account}"); + } + + if (!Directory.Exists(savePath)) + { + Directory.CreateDirectory(savePath); + } + + //找最大ID + long maxId = 0; + CommonDataContext commonData = new CommonDataContext(); + BcCenterDataContext billCenterData = new BcCenterDataContext(); + var mc = billCenterData.Mails.Count(r => r.MailAccount == account); + if (mc > 0) + { + maxId = billCenterData.Mails.Where(r => r.MailAccount == account).Max(r => r.ImapId); + uids = uids.Where(u => u.Id > maxId).ToList(); + } + + log.Debug($"{account}开始下载邮件"); + + int recCount = 0; + foreach (var uid in uids) + { + var c = billCenterData.Mails.Count(r => r.MailAccount == account && r.ImapId == uid.Id); + if (c > 0) + { + continue; //忽略 + } + + var headers = inbox.GetHeaders(uid); + var messageId = headers[HeaderId.MessageId]; + var sendUser = headers[HeaderId.From]; + var suject = headers[HeaderId.Subject]; + var idxStart = sendUser.IndexOf("<"); + var idxEnd = sendUser.IndexOf(">"); + if (idxStart > -1 && idxEnd > -1) + { + sendUser = sendUser.Substring(idxStart + 1, idxEnd - idxStart - 1); + } + + + //判断发件人是否合法 + var qUser = from ub in commonData.UserBases.AsNoTracking() + join u in commonData.Users.AsNoTracking() on ub.USERID equals u.GID + join comp in commonData.CompanyNew.AsNoTracking() on u.CompId equals comp.CompId + where ub.EMAIL1 == sendUser + select new { u.GID, u.SHOWNAME, comp.CompId, comp.CompName }; + var usrObj = qUser.FirstOrDefault(); + if (usrObj == null) + { + //发回复邮件,提醒注册大简云 + log.Debug($"发送人邮箱{sendUser}未注册大简云"); + MailHelper.SendMailService("账单未处理提醒", "当前邮箱未注册大简云,请联系客服注册后再试。", sendUser); + } + + try + { + var recInfo = new Mails(); + recInfo.GID = Guid.NewGuid().ToString(); + recInfo.MailAccount = account; + recInfo.ImapId = (int)uid.Id; + recInfo.MailId = messageId; + recInfo.EmailDate = mailDate; + recInfo.SourceType = Mails.SourceTypeMail; + if (usrObj != null) + { + recInfo.UserId = usrObj.GID; + recInfo.UserName = usrObj.SHOWNAME; + recInfo.CompId = usrObj.CompId; + recInfo.CompName = usrObj.CompName; + recInfo.Status = "Ready"; + } + else + { + recInfo.UserId = string.Empty; + recInfo.UserName = string.Empty; + recInfo.CompId = string.Empty; + recInfo.CompName = string.Empty; + recInfo.Status = "Fail"; + } + recInfo.SendUserMail = sendUser; + recInfo.ReceiveTime = DateTime.Now; + recInfo.MailSubject = suject; + + var listAtt = new List(); + if (usrObj != null) //没有注册的不拉取邮件和附件 + { + var mailGuid = Guid.NewGuid().ToString(); + string emlSavePath = Path.Combine(savePath, $"{mailGuid}.eml"); + var message = inbox.GetMessage(uid); + message.WriteTo(emlSavePath); + recInfo.MailPath = emlSavePath; + recInfo.MailUrl = $"{fileDownloadUrl}bill/GetMailFile?id={recInfo.GID}"; + recInfo.MailDate = message.Date.ToLocalTime().DateTime; + + //附件存放路径 + var attPath = Path.Combine(savePath, $"{recInfo.ImapId}"); + if (!Directory.Exists(attPath)) + { + Directory.CreateDirectory(attPath); + } + + //解析附件 + ParseAttach(message, attPath, recInfo, listAtt); + + var listErr = new List(); + //校验文件MD5存在 + foreach (var att in listAtt) + { + if (att.Status != "Ready") //已处理过,不重复处理 + { + continue; + } + + var attInfo = billCenterData.Attachments.AsNoTracking().FirstOrDefault(aa => aa.AttachMD5 == att.AttachMD5); + if (attInfo != null) + { + var mail = billCenterData.Mails.AsNoTracking().First(mm => mm.GID == attInfo.MailGID); + + var errMsg = " " + + $" {att.AttachName}" + + $" {mail.SendUserMail}" + + $" {mail.ReceiveTime}" + + $" {mail.MailSubject}" + + " "; + listErr.Add(errMsg); + att.Status = "Repeat"; + att.Tips = $"文件重复发送:{mail.SendUserMail} 在 {mail.ReceiveTime} 发送过此文件"; + } + else + { + //2022-1-21,解决同一封邮件中同个附件重复问题的处理 + var tmpList = listAtt.Where(x => x.AttachMD5 == att.AttachMD5).ToList(); + if (tmpList.Count > 1) + { + for (var idx = 1; idx < tmpList.Count; idx++) + { + tmpList[idx].Status = "Repeat"; + tmpList[idx].Tips = $"文件重复发送:在同一封邮件中"; + } + } + } + } + + if (listErr.Count > 0) + { + var str = string.Join("", listErr); + var strTable = " " + +" " + +" " + +" " + +" " + +" " + +" " + +" " + +" " + +" "; + + var strTableEnd = " " + +"
文件名称上次发送人上次发送时间上次发件标题
"; + str = $@"{strTable}{str}{strTableEnd}"; + log.Debug($"附件重复发送:\r\n{str}"); + MailHelper.SendMailService("账单未处理提醒:文件重复发送", str.Replace("\r\n", "
"), sendUser); + + } + } + else + { + recInfo.MailPath = string.Empty; + } + + billCenterData.Mails.Add(recInfo); + billCenterData.Attachments.AddRange(listAtt); + + billCenterData.SaveChanges(); //立即保存 + + log.Debug($"{account}已下载邮件,ID:{uid} 标题:{suject} 发送者:{sendUser}"); + recCount++; + } + catch (Exception ex) + { + log.Error($"{account}收取邮件时,发生严重错误({uid}):"); + var exp = ex; + while (exp != null) + { + log.Error(exp.Message); + log.Error(exp.StackTrace); + + exp = exp.InnerException; + } + + + } + + //2021-9-14,每封邮件置标志状态,防止单次设置10分钟收件未完成,第二个线程重复收取 + if (MemoryCache.Default.Contains(keyMem)) + { + MemoryCache.Default.Remove(keyMem); + } + + MemoryCache.Default.Add(new CacheItem(keyMem, true), new CacheItemPolicy() { AbsoluteExpiration = DateTime.Now.AddMinutes(2) }); + } + + log.Debug($"{account}下载邮件完成,共{recCount}封"); + + inbox.Close(); + imapClient.Disconnect(true); + } + + MemoryCache.Default.Remove(keyMem); + } + catch (Exception ex) + { + log.Error($"收取邮件出错:{ex.Message}"); + log.Error($"{ex.StackTrace}"); + + } + } + + private void ParseAttach(MimeMessage message, string attPath, Mails parent, List listAtt) + { + //解析附件 + foreach (var att in message.Attachments) + { + MimePart attPart = att as MimePart; + if (attPart != null && attPart.IsAttachment) + { + var attName = att.ContentType.Name; + var attExt = Path.GetExtension(attName); + + //eml文件继续解析处理 + if (attExt.ToLower() == ".eml") + { + //todo: + MemoryStream msMail = new MemoryStream(); + att.WriteTo(msMail, true); + msMail.Position = 0; + StreamReader readerMail = new StreamReader(msMail); + var strB64Mail = readerMail.ReadToEnd(); + var bsArrAtt = Convert.FromBase64String(strB64Mail); + msMail.Close(); + msMail = new MemoryStream(bsArrAtt); + var attMail = MimeMessage.Load(msMail); + ParseAttach(attMail, attPath, parent, listAtt); + + continue; + } + + var attSaveName = Guid.NewGuid().ToString() + attExt; + + Attachments attach = new Attachments(); + attach.GID = Guid.NewGuid().ToString(); + attach.MailGID = parent.GID; + attach.MailID = parent.MailId; + attach.CreateTime = DateTime.Now; + attach.AttachName = attName; + attach.FileType = attExt; + attach.Status = "Ready"; + + + string attSavePath = Path.Combine(attPath, attSaveName); + MemoryStream ms = new MemoryStream(); + att.WriteTo(ms, true); + ms.Position = 0; + StreamReader reader = new StreamReader(ms); + var strB64 = reader.ReadToEnd(); + if (att.ContentType.MediaType == "application" || att.ContentType.MediaType == "binary") + { + var bsArrAtt = Convert.FromBase64String(strB64); + File.WriteAllBytes(attSavePath, bsArrAtt); + } + else if (att.ContentType.MediaType == "text") + { + File.WriteAllText(attSavePath, strB64); + } + else + { + log.Error($"未知附件类型:{att.ContentType.MediaType} {att.ContentType.MediaSubtype}"); + attach.Status = "Fail"; + attach.Tips = "未知附件类型"; + } + + attach.AttachMD5 = GetMD5HashFromFile(attSavePath); + attach.AttachPath = attSavePath; + attach.AttachUrl = $"{fileDownloadUrl}bill/GetAttFile?id={attach.GID}"; + + listAtt.Add(attach); + } + } + } + + + public string GetMD5HashFromBytes(byte[] arr) + { + try + { + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash(arr); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + return sb.ToString(); + } + catch (Exception ex) + { + log.Error("计算文件MD5错误"); + log.Error(ex.Message); + log.Error(ex.StackTrace); + throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message); + } + } + + public string GetMD5HashFromFile(string fileName) + { + try + { + FileStream file = new FileStream(fileName, System.IO.FileMode.Open); + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash(file); + file.Close(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + return sb.ToString(); + } + catch (Exception ex) + { + throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message); + } + } + } +} diff --git a/BcCenter/BcCenter.Service/SchedulerJob.cs b/BcCenter/BcCenter.Service/SchedulerJob.cs new file mode 100644 index 0000000..ead1832 --- /dev/null +++ b/BcCenter/BcCenter.Service/SchedulerJob.cs @@ -0,0 +1,130 @@ +using BcCenter.Common.DB; +using log4net; +using Quartz; +using Quartz.Impl.Matchers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Caching; +using System.Text; + +namespace BcCenter.Service +{ + public class SchedulerJob : IJob + { + private static readonly string MailGroup = "Mail"; + ILog log = LogManager.GetLogger(typeof(SchedulerJob)); + + public void Execute(IJobExecutionContext context) + { + try + { + int getMailInterval = context.JobDetail.JobDataMap.GetInt("GetMailIntervalMinutes"); + + BcCenterDataContext mailData = new BcCenterDataContext(); + List listAccounts = null; + + if (MemoryCache.Default.Contains("FirstRun")) + { + listAccounts = mailData.UserAccounts.Where(u => u.IsChanged).ToList(); + log.Debug($"******发现修改的邮箱{listAccounts.Count}个"); + } + else + { + MemoryCache.Default.Add(new CacheItem("FirstRun", true), new CacheItemPolicy() { Priority = CacheItemPriority.NotRemovable }); + + listAccounts = mailData.UserAccounts.ToList(); + log.Debug($"******启动调度,待处理邮箱{listAccounts.Count}个"); + } + + int delay = 0; + foreach (var ua in listAccounts) + { + #region 先删除已存在的调度 + JobKey jobFind = new JobKey($"JobGetMail_{ua.MailAccount}", MailGroup); + var job = context.Scheduler.GetJobDetail(jobFind); + if (job != null) + { + bool success = context.Scheduler.DeleteJob(jobFind); + log.Debug($">>>>>删除邮箱{ua.MailAccount}的获取邮件任务 {(success ? "成功" : "失败")}"); + } + + #endregion + + Dictionary> dicJob = new Dictionary>(); + + #region 收取邮件调度 + if (ua.UseImap) + { + log.Debug($"******新增邮箱{ua.MailAccount}的获取邮件任务调度"); + IJobDetail jobGetMail = JobBuilder.Create() + .WithIdentity($"JobGetMail_{ua.MailAccount}", MailGroup) + .UsingJobData("Account", ua.MailAccount) + .UsingJobData("Password", ua.Password) + .UsingJobData("ImapServer", ua.ReceiveServer) + .UsingJobData("ImapPort", ua.ReceivePort) + .UsingJobData("ImapSSL", ua.ReceiveSSL) + .UsingJobData("SmtpServer", ua.SmtpServer) + .UsingJobData("SmtpPort", ua.SmtpPort) + .UsingJobData("SmtpSSL", ua.SmtpSSL) + .Build(); + + + ISimpleTrigger triGetMail = (ISimpleTrigger)TriggerBuilder.Create() + .WithIdentity($"TrigGetMail_{ua.MailAccount}", MailGroup) + .StartAt(DateTime.UtcNow.AddSeconds(delay++)) + .WithSimpleSchedule(x => x.WithIntervalInMinutes(getMailInterval).RepeatForever()) + .Build(); + + Quartz.Collection.HashSet hsTriger = new Quartz.Collection.HashSet(); + hsTriger.Add(triGetMail); + dicJob.Add(jobGetMail, hsTriger); + } + //else + //{ + // log.Debug($"******新增邮箱{ua.MailAccount}的获取邮件任务调度"); + // IJobDetail jobGetMail = JobBuilder.Create() + // .WithIdentity($"JobGetMail_{ua.MailAccount}", MailGroup) + // .UsingJobData("Account", ua.MailAccount) + // .UsingJobData("Password", ua.Password) + // .UsingJobData("PopServer", ua.ReceiveServer) + // .UsingJobData("PopPort", ua.ReceivePort) + // .UsingJobData("PopSSL", ua.ReceiveSSL) + // .Build(); + + + // ISimpleTrigger triGetMail = (ISimpleTrigger)TriggerBuilder.Create() + // .WithIdentity($"TrigGetMail_{ua.MailAccount}", MailGroup) + // .StartAt(DateTime.UtcNow.AddSeconds(delay++)) + // .WithSimpleSchedule(x => x.WithIntervalInMinutes(getMailInterval).RepeatForever()) + // .Build(); + + // Quartz.Collection.HashSet hsTriger = new Quartz.Collection.HashSet(); + // hsTriger.Add(triGetMail); + // dicJob.Add(jobGetMail, hsTriger); + //} + #endregion + + context.Scheduler.ScheduleJobs(dicJob, true); + + ua.IsChanged = false; + mailData.SaveChanges(); + } + } + catch (Exception ex) + { + log.Error($"处理调度任务出错:{ex.Message}"); + log.Error($"{ex.StackTrace}"); + + Exception exTmp = ex.InnerException; + while (exTmp != null) + { + log.Error($"{exTmp.Message}"); + log.Error($"{exTmp.StackTrace}"); + + exTmp = exTmp.InnerException; + } + } + } + } +} diff --git a/BcCenter/BcCenter.Service/job_scheduling_data_2_0.xsd b/BcCenter/BcCenter.Service/job_scheduling_data_2_0.xsd new file mode 100644 index 0000000..7bff0f0 --- /dev/null +++ b/BcCenter/BcCenter.Service/job_scheduling_data_2_0.xsd @@ -0,0 +1,364 @@ + + + + + + + Root level node + + + + + + Commands to be executed before scheduling the jobs and triggers in this file. + + + + + Directives to be followed while scheduling the jobs and triggers in this file. + + + + + + + + + + + + + + Version of the XML Schema instance + + + + + + + + + + Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. + + + + + Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. + + + + + Delete the identified job if it exists (will also result in deleting all triggers related to it). + + + + + + + + + + + Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). + + + + + + + + + + + + + + + + Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. + + + + + If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. + + + + + If true trigger's start time is calculated based on earlier run time instead of fixed value. Trigger's start time must be undefined for this to work. + + + + + + + + Define a JobDetail + + + + + + + + + + + + + + + + + Define a JobDataMap + + + + + + + + + Define a JobDataMap entry + + + + + + + + + + Define a Trigger + + + + + + + + + + + Common Trigger definitions + + + + + + + + + + + + + + + + + + + + + + + Define a SimpleTrigger + + + + + + + + + + + + + + + + + Define a CronTrigger + + + + + + + + + + + + + + + Define a DateIntervalTrigger + + + + + + + + + + + + + + + + Cron expression (see JavaDoc for examples) + + Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! + + Regular expressions are not my strong point but I believe this is complete, + with the caveat that order for expressions like 3-0 is not legal but will pass, + and month and day names must be capitalized. + If you want to examine the correctness look for the [\s] to denote the + seperation of individual regular expressions. This is how I break them up visually + to examine them: + + SECONDS: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + MINUTES: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + HOURS: + ( + ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) + | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) + | ([\?]) + | ([\*]) + ) [\s] + DAY OF MONTH: + ( + ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) + | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) + | (L(-[0-9])?) + | (L(-[1-2][0-9])?) + | (L(-[3][0-1])?) + | (LW) + | ([1-9]W) + | ([1-3][0-9]W) + | ([\?]) + | ([\*]) + )[\s] + MONTH: + ( + ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) + | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) + | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) + | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) + | ([\?]) + | ([\*]) + )[\s] + DAY OF WEEK: + ( + (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) + | ([1-7]/([1-7])) + | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) + | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) + | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) + | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) + | ([\?]) + | ([\*]) + ) + YEAR (OPTIONAL): + ( + [\s]? + ([\*])? + | ((19[7-9][0-9])|(20[0-9][0-9]))? + | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? + | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? + ) + + + + + + + + + + Number of times to repeat the Trigger (-1 for indefinite) + + + + + + + + + + Simple Trigger Misfire Instructions + + + + + + + + + + + + + + + Cron Trigger Misfire Instructions + + + + + + + + + + + + Date Interval Trigger Misfire Instructions + + + + + + + + + + + + Interval Units + + + + + + + + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Service/packages.config b/BcCenter/BcCenter.Service/packages.config new file mode 100644 index 0000000..f7ab5ea --- /dev/null +++ b/BcCenter/BcCenter.Service/packages.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.Service/quartz_jobs.xml b/BcCenter/BcCenter.Service/quartz_jobs.xml new file mode 100644 index 0000000..c538ec4 --- /dev/null +++ b/BcCenter/BcCenter.Service/quartz_jobs.xml @@ -0,0 +1,159 @@ + + + + true + + + + + JobScheduler + System + 动态调度作业 + DSWeb.BillCenter.Service.SchedulerJob,DSWeb.BillCenter.Service + true + false + + + GetMailIntervalMinutes + 1 + + + ParseMailIntervalSeconds + 10 + + + ProcessMailIntervalSeconds + 10 + + + RetransmissionIntervalSeconds + 10 + + + + + + + TriggerScheduler + System + 动态调度作业触发器 + JobScheduler + System + -1 + 60000 + + + + + + JobCheckProgress + System + 检查附件处理进度作业 + DSWeb.BillCenter.Service.JobCheckAttachProgress,DSWeb.BillCenter.Service + true + false + + + + + TriggerCheckProgress + System + 检查附件处理进度作业触发器 + JobCheckProgress + System + -1 + 60000 + + + + + + JobBillDataToDS7 + System + 账单推送DS7消息队列 + DSWeb.BillCenter.Service.JobBillDataToDS7,DSWeb.BillCenter.Service + true + false + + + + + TriggerBillDataToDS7 + System + 账单推送消息队列触发器 + JobBillDataToDS7 + System + -1 + 10000 + + + + + + JobBillDataToDS7Task + System + 账单推送DS7消息队列 + DSWeb.BillCenter.Service.JobBillDataToDS7Task,DSWeb.BillCenter.Service + true + false + + + + + TriggerBillDataToDS7Task + System + 账单推送消息队列触发器 + JobBillDataToDS7Task + System + -1 + 10000 + + + + + + JobBillDataToDS7New + System + 账单推送DS7消息队列 + DSWeb.BillCenter.Service.JobBillDataToDS7New,DSWeb.BillCenter.Service + true + false + + + + + TriggerBillDataToDS7New + System + 账单推送消息队列触发器 + JobBillDataToDS7New + System + -1 + 10000 + + + + + + JobBillDataToDS7TaskDirect + System + 账单推送DS7消息队列 + DSWeb.BillCenter.Service.JobBillDataToDS7TaskDirect,DSWeb.BillCenter.Service + true + false + + + + + TriggerBillDataToDS7TaskDirect + System + 账单推送消息队列触发器 + JobBillDataToDS7TaskDirect + System + -1 + 10000 + + + + + + \ No newline at end of file diff --git a/BcCenter/BcCenter.sln b/BcCenter/BcCenter.sln new file mode 100644 index 0000000..346a206 --- /dev/null +++ b/BcCenter/BcCenter.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BcCenter.Service", "BcCenter.Service\BcCenter.Service.csproj", "{3A539117-F2B7-4B78-8849-48DE29370F09}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BcCenter.Common", "BcCenter.Common\BcCenter.Common.csproj", "{D26A3DF4-4F5B-4B40-8723-2B9477E754A1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3A539117-F2B7-4B78-8849-48DE29370F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A539117-F2B7-4B78-8849-48DE29370F09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A539117-F2B7-4B78-8849-48DE29370F09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A539117-F2B7-4B78-8849-48DE29370F09}.Release|Any CPU.Build.0 = Release|Any CPU + {D26A3DF4-4F5B-4B40-8723-2B9477E754A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D26A3DF4-4F5B-4B40-8723-2B9477E754A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D26A3DF4-4F5B-4B40-8723-2B9477E754A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D26A3DF4-4F5B-4B40-8723-2B9477E754A1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {31DE9E18-ED5A-41FA-850C-9C68B7E46272} + EndGlobalSection +EndGlobal