diff --git a/PEIS.Common b/PEIS.Common deleted file mode 160000 index d276266..0000000 --- a/PEIS.Common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d276266da5d8f4b9bb4b5dc9e88ddd2e21c62f94 diff --git a/PEIS.Common/Helper/Auth/AuthHelper.cs b/PEIS.Common/Helper/Auth/AuthHelper.cs new file mode 100644 index 0000000..d830fdd --- /dev/null +++ b/PEIS.Common/Helper/Auth/AuthHelper.cs @@ -0,0 +1,53 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Reflection; +using System.Security.Claims; +using System.Text; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; + +namespace PEIS.Common.Helper.Auth +{ + public class AuthHelper + { + + private readonly IConfiguration _configuration; + + + /// + public AuthHelper(IConfiguration configuration) + { + _configuration = configuration; + } + + /// + /// 生成jwt的token + /// + /// + /// + public string GetToken(dynamic userInfo) + { + var dynamicProperties =(PropertyInfo[]) userInfo.GetType().GetProperties(); + // token中的claims用于储存自定义信息,如登录之后的用户id等 + var claims = new Claim[dynamicProperties.Length]; + for (var i = 0; i < dynamicProperties.Length; i++) + { + claims[i] = new Claim(dynamicProperties[i].Name, userInfo.GetType().GetProperty(dynamicProperties[i].Name).GetValue(userInfo,null)?.ToString()); + } + // 获取SecurityKey + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.GetSection("Authentication")["SecurityKey"])); + var token = new JwtSecurityToken( + issuer: _configuration.GetSection("Authentication")["IsSure"], // 发布者 + audience: _configuration.GetSection("Authentication")["Audience"], // 接收者 + notBefore: DateTime.Now, // token签发时间 + expires: DateTime.Now.AddMinutes(30), // token过期时间 + claims: claims, // 该token内存储的自定义字段信息 + signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用于签发token的秘钥算法 + ); + // 返回成功信息,写出token + return new JwtSecurityTokenHandler().WriteToken(token); + } + + + } +} diff --git a/PEIS.Common/Helper/Auth/JwtHelper.cs b/PEIS.Common/Helper/Auth/JwtHelper.cs new file mode 100644 index 0000000..b9d95fe --- /dev/null +++ b/PEIS.Common/Helper/Auth/JwtHelper.cs @@ -0,0 +1,22 @@ +using System.Linq; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; + +namespace PEIS.Common.Helper.Auth +{ + public static class JwtHelper + { + /// + /// 获取当前jwt缓存里面的数值 直接本地this.CurValue即可 + /// + /// + /// + /// + public static string CurValue(this ControllerBase controller,string key) + { + var auth = controller.HttpContext.AuthenticateAsync().Result.Principal.Claims; + var value = auth.FirstOrDefault(t => t.Type.Equals(key))?.Value; + return value; + } + } +} diff --git a/PEIS.Common/Helper/Cache/CacheHelper.cs b/PEIS.Common/Helper/Cache/CacheHelper.cs new file mode 100644 index 0000000..ca33b21 --- /dev/null +++ b/PEIS.Common/Helper/Cache/CacheHelper.cs @@ -0,0 +1,58 @@ +using System; +using Microsoft.Extensions.Caching.Memory; + +namespace PEIS.Common.Helper.Cache +{ + /// + /// 缓存框架 + /// + public class CacheHelper + { + private readonly IMemoryCache _memoryCache; + + /// + /// 缓存框架 + /// + /// + public CacheHelper(IMemoryCache memoryCache) + { + _memoryCache = memoryCache; + } + + + /// + /// 存缓存 + /// + /// 关键词 + /// 值 + public void Set(string key, string value) + { + var cacheOptions = new MemoryCacheEntryOptions() + .SetSlidingExpiration(TimeSpan.FromMinutes(5)); + _memoryCache.Set(key, value,cacheOptions); + } + + /// + /// 存缓存 带时效 + /// + /// 关键词 + /// 值 + /// 时效 + public void SetAging(string key, string value,int aging) + { + var cacheOptions = new MemoryCacheEntryOptions() + .SetSlidingExpiration(TimeSpan.FromMinutes(aging)); + _memoryCache.Set(key, value, cacheOptions); + } + + /// + /// 获取缓存值 + /// + /// + /// + public string Get(string key) + { + return _memoryCache.TryGetValue(key, out string value) ? value:""; + } + } +} diff --git a/PEIS.Common/Helper/Code/CodeHelper.cs b/PEIS.Common/Helper/Code/CodeHelper.cs new file mode 100644 index 0000000..85f503c --- /dev/null +++ b/PEIS.Common/Helper/Code/CodeHelper.cs @@ -0,0 +1,71 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using QRCoder; + +namespace PEIS.Common.Helper.Code +{ + public class CodeHelper + { + + private static Bitmap QcCode(string text) + { + + var qrGenerator = new QRCodeGenerator(); + + var qrCodeData = qrGenerator.CreateQrCode(text, QRCodeGenerator.ECCLevel.Q); + + var qrCode = new QRCode(qrCodeData); + + return qrCode.GetGraphic(20, Color.Black, Color.White, new Bitmap(Path.Combine(Directory.GetCurrentDirectory(), "Image", "Logo.jpg"))); + } + + private static Bitmap QcCodeTitle(string text,string title) + { + var qrCodeImage = QcCode(text); + var bitmap = new Bitmap(500, 450); + var g = Graphics.FromImage(bitmap); + var font = new Font("SimSun", 24, FontStyle.Regular); + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + g.Clear(Color.White); + g.DrawImage(qrCodeImage, 50, 0, 400, 400); + var solidBrush = new SolidBrush(Color.Black); + g.DrawString(title, font, solidBrush, 190, 400); + g.Dispose(); + qrCodeImage.Dispose(); + return bitmap; + } + + + /// + /// 获取二维码 + /// + /// 文本 + /// + /// 生成文件地址 + public static void QcCodeForFilePath(string text, string title, string filePath) + { + + var map = QcCodeTitle(text,title); + map.Save(filePath + title, ImageFormat.Png); + map.Dispose(); + } + /// + /// 获取带标题的二维码 + /// + /// + /// + /// + + public static string QcCodeBase64(string text,string title) + { + using var ms = new MemoryStream(); + var map = QcCodeTitle(text,title); + map.Save(ms, ImageFormat.Png); + map.Dispose(); + return Convert.ToBase64String(ms.GetBuffer()); + } + + } +} diff --git a/PEIS.Common/Helper/Encryption/AppSettingJsonHelper.cs b/PEIS.Common/Helper/Encryption/AppSettingJsonHelper.cs new file mode 100644 index 0000000..e9cf8ef --- /dev/null +++ b/PEIS.Common/Helper/Encryption/AppSettingJsonHelper.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; + +namespace PEIS.Common.Helper.Encryption +{ + /// + /// 获取配置文件信息 + /// + public class AppSettingJsonHelper + { + + private static readonly IConfiguration Configuration = new ConfigurationBuilder() + .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }) + .Build(); + /// + /// 获取配置文件里面的参数 + /// + /// + /// + /// + public static string GetSection(string section,string key) + { + return Configuration.GetSection(section)[key]; + } + } + +} diff --git a/PEIS.Common/Helper/Encryption/ConnectionStringsHelper.cs b/PEIS.Common/Helper/Encryption/ConnectionStringsHelper.cs new file mode 100644 index 0000000..5d5c0ba --- /dev/null +++ b/PEIS.Common/Helper/Encryption/ConnectionStringsHelper.cs @@ -0,0 +1,17 @@ +namespace PEIS.Common.Helper.Encryption +{ + public class ConnectionStringsHelper + { + /// + /// 直接返回解密后的connectionString + /// + /// + /// + /// + public static string GetDesConfig(string configName,string configValue) + { + return DesHelper.DesDecrypt(AppSettingJsonHelper.GetSection(configName, configValue)); + } + + } +} diff --git a/PEIS.Common/Helper/Encryption/DesHelper.cs b/PEIS.Common/Helper/Encryption/DesHelper.cs new file mode 100644 index 0000000..88d59cc --- /dev/null +++ b/PEIS.Common/Helper/Encryption/DesHelper.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using System.Security.Cryptography; + +namespace PEIS.Common.Helper.Encryption +{ + public class DesHelper + { + private const string Key = "Blue2021"; + private const string Iv = "Flag2021"; + + /// + /// DES加密 + /// + /// 加密数据 + /// + public static string DesEncrypt(string data) + { + var byKey = System.Text.Encoding.ASCII.GetBytes(Key); + var byIv = System.Text.Encoding.ASCII.GetBytes(Iv); + + var cryptoProvider = new DESCryptoServiceProvider(); + var ms = new MemoryStream(); + var cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIv), CryptoStreamMode.Write); + + var sw = new StreamWriter(cst); + sw.Write(data); + sw.Flush(); + cst.FlushFinalBlock(); + sw.Flush(); + return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length); + } + + /// + /// DES解密 + /// + /// 解密数据 + /// + public static string DesDecrypt(string data) + { + var byKey = System.Text.Encoding.ASCII.GetBytes(Key); + var byIv = System.Text.Encoding.ASCII.GetBytes(Iv); + + byte[] byEnc; + try + { + byEnc = Convert.FromBase64String(data); + } + catch + { + return null; + } + + var cryptoProvider = new DESCryptoServiceProvider(); + var ms = new MemoryStream(byEnc); + var cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIv), CryptoStreamMode.Read); + var sr = new StreamReader(cst); + return sr.ReadToEnd(); + } + } +} diff --git a/PEIS.Common/Helper/Encryption/RsaHelper.cs b/PEIS.Common/Helper/Encryption/RsaHelper.cs new file mode 100644 index 0000000..d4c4f3f --- /dev/null +++ b/PEIS.Common/Helper/Encryption/RsaHelper.cs @@ -0,0 +1,102 @@ +using System; +using System.Security.Cryptography; + +namespace PEIS.Common.Helper.Encryption +{ + public class RsaHelper + { + private RSACryptoServiceProvider Csp { get; set; } + private RSAParameters PrivateKey { get; set; } + private RSAParameters PublicKey { get; set; } + + /// + /// 公钥字符串 + /// + public string PublicKeyString { get; set; } + + private RsaHelper() + { + Csp = new RSACryptoServiceProvider(2048); + + //how to get the private key + PrivateKey = Csp.ExportParameters(true); + + //and the public key ... + PublicKey = Csp.ExportParameters(false); + + //converting the public key into a string representation + { + //we need some buffer + var sw = new System.IO.StringWriter(); + //we need a serializer + var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters)); + //serialize the key into the stream + xs.Serialize(sw, PublicKey); + //get the string from the stream + PublicKeyString = sw.ToString(); + } + + //converting it back + { + //get a stream from the string + var sr = new System.IO.StringReader(PublicKeyString); + //we need a deserializer + var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters)); + //get the object back from the stream + PublicKey = (RSAParameters)xs.Deserialize(sr); + } + + } + static RsaHelper(){} + + public static RsaHelper Instance { get; } = new RsaHelper(); + /// + /// 加密数据 + /// + /// + /// + public string DesEncrypt(string keyWord) + { + //lets take a new CSP with a new 2048 bit rsa key pair + + //conversion for the private key is no black magic either ... omitted + + //we have a public key ... let's get a new csp and load that key + Csp = new RSACryptoServiceProvider(); + Csp.ImportParameters(PublicKey); + + + //for encryption, always handle bytes... + var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(keyWord); + + //apply pkcs#1.5 padding and encrypt our data + var bytesCypherText = Csp.Encrypt(bytesPlainTextData, false); + + //we might want a string representation of our cypher text... base64 will do + return Convert.ToBase64String(bytesCypherText); + + } + /// + /// 解密数据 + /// + /// + /// + + public string DesDecrypt(string keyWord) + { + + //first, get our bytes back from the base64 string ... + var bytesCypherText = Convert.FromBase64String(keyWord); + + //we want to decrypt, therefore we need a csp and load our private key + var csp = new RSACryptoServiceProvider(); + csp.ImportParameters(PrivateKey); + + //decrypt and strip pkcs#1.5 padding + var bytesPlainTextData = csp.Decrypt(bytesCypherText, false); + + //get our original plainText back... + return System.Text.Encoding.Unicode.GetString(bytesPlainTextData); + } + } +} diff --git a/PEIS.Common/Helper/Entity/ModelToEntity.cs b/PEIS.Common/Helper/Entity/ModelToEntity.cs new file mode 100644 index 0000000..e18b20a --- /dev/null +++ b/PEIS.Common/Helper/Entity/ModelToEntity.cs @@ -0,0 +1,45 @@ +using System; + +namespace PEIS.Common.Helper.Entity +{ + public class ModelToEntity + { + /// + /// 类型转换,有则赋值,没有则默认值 这个可以不传需要转换的值 + /// + /// + /// + public static TE Change(TM model) + { + var modelPropertyInfos = typeof(TM).GetProperties(); + var entityType = typeof(TE); + var entity =(TE)Activator.CreateInstance(typeof(TE)); + foreach (var modelPropertyInfo in modelPropertyInfos) + { + if(entityType.GetProperty(modelPropertyInfo.Name)!=null) + entityType.GetProperty(modelPropertyInfo.Name)?.SetValue(entity, modelPropertyInfo.GetValue(model), null); + } + + return entity; + } + /// + /// 类型转换,只是这个可以传入需要转换的值 + /// + /// + /// + /// + + public static TE Set(TM model,TE entity) + { + var modelPropertyInfos = typeof(TM).GetProperties(); + var entityType = typeof(TE); + foreach (var modelPropertyInfo in modelPropertyInfos) + { + if (entityType.GetProperty(modelPropertyInfo.Name) != null) + entityType.GetProperty(modelPropertyInfo.Name)?.SetValue(entity, modelPropertyInfo.GetValue(model), null); + } + + return entity; + } + } +} diff --git a/PEIS.Common/Helper/Excel/ExcelHelper.cs b/PEIS.Common/Helper/Excel/ExcelHelper.cs new file mode 100644 index 0000000..b66935f --- /dev/null +++ b/PEIS.Common/Helper/Excel/ExcelHelper.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using ExcelDataReader; + +namespace PEIS.Common.Helper.Excel +{ + public class ExcelHelper + { + static ExcelHelper() { } + + private ExcelHelper() { } + public static ExcelHelper Instance { get; } = new ExcelHelper(); + + /// + /// 读取excel的帮助类 必须传该excel有几列 + /// + /// + /// + /// + public List> Read(string filePath,int columnCount) + { + var excelContent = new List>(); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + using var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read); + using var reader = ExcelReaderFactory.CreateReader(stream); + do + { + while (reader.Read()) + { + + var cellContent = new List(); + for (var i = 0; i < columnCount; i++) + { + cellContent.Add(reader[i]==null?"": reader[i].ToString()); + } + if(!cellContent.All(string.IsNullOrEmpty)) + excelContent.Add(cellContent); + } + } while (reader.NextResult()); + return excelContent; + } + } +} diff --git a/PEIS.Common/Helper/File/FileHelper.cs b/PEIS.Common/Helper/File/FileHelper.cs new file mode 100644 index 0000000..fd832c8 --- /dev/null +++ b/PEIS.Common/Helper/File/FileHelper.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using PEIS.Common.Helper.Nlog; + +namespace PEIS.Common.Helper.File +{ + public class FileHelper + { + /// + /// 创建文件夹 + /// + /// + public static void CreateFile(string file) + { + if (Directory.Exists(file)) + //文件夹已经存在 + return; + + try + { + Directory.CreateDirectory(file); + //创建成功 + } + catch (Exception e) + { + LogHelper.Log.Error($"文件创建出错:{e.ToString()}"); + } + + } + + /// + /// 获取文件大小 + /// + /// 文件长度 + /// + public static string FileSize(long length) + { + var unit = new List() { "K", "M", "G" }; + var size = Math.Round(length / 1024.0, 2); + var index = 0; + while (size > 1024 && index < 2) + { + index++; + size = Math.Round(size / 1024, 2); + } + + return $"{size}{unit[index]}"; + + } + } +} diff --git a/PEIS.Common/Helper/Nlog/LogHelper.cs b/PEIS.Common/Helper/Nlog/LogHelper.cs new file mode 100644 index 0000000..2c160e6 --- /dev/null +++ b/PEIS.Common/Helper/Nlog/LogHelper.cs @@ -0,0 +1,18 @@ +using NLog; + +namespace PEIS.Common.Helper.Nlog +{ + /// + /// 日志静态类 + /// + public class LogHelper + { + + /// + /// 日志调用对象 + /// + public static readonly NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + } + +} \ No newline at end of file diff --git a/PEIS.Common/Helper/Page/PageHelper.cs b/PEIS.Common/Helper/Page/PageHelper.cs new file mode 100644 index 0000000..35496b1 --- /dev/null +++ b/PEIS.Common/Helper/Page/PageHelper.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; + +namespace PEIS.Common.Helper.Page +{ + /// + /// 分页帮助类 + /// + public class PageHelper + { + /* + * 1.分页 list.Skip(x).Take(y); + * 2.(x,y)超过(0,list.Count)范围时list为空[],在范围内(或单边超过范围)时显示范围内数据 + */ + /// + /// 分页 + /// + /// 数据类型 + /// 数据 + /// 页码 + /// 数据量/页 + /// + public static Data Pagination(List list, int page, int size) + { + if (list == null) + return new Data(0, page, null); + if (list.Count != 0 && list.Count >= size) + return new Data(list.Count, page <= 0 ? 0 : page, + list.Skip(Convert.ToInt32((page <= 0 ? 0 : page - 1) * size)).Take(size).ToList()); + return new Data(list.Count, page, list); + } + + /// + /// 该分页方法适用于sql server 2008 .net core 3.1不支持2008数据库 + /// + /// + /// + /// + /// + /// + /// + public static Data Pagination(DbContext db, DbSet dbTable, int page, int size) where T : class + { + var entityType = db.Model.FindEntityType(typeof(T)); + var tableName = entityType.GetTableName(); + var primaryKeyName = entityType.FindPrimaryKey().Properties.First().Name; + return new Data(dbTable.Count(), page, dbTable.FromSqlRaw($"select * from (select ROW_NUMBER() OVER(ORDER BY {primaryKeyName}) RowSerialNumber ,* from {tableName}) s where RowSerialNumber BETWEEN {(page - 1) * size + 1} and {page * size}").ToList()); + } + /// + /// 该方法适用于sql server 2008以上的数据库 sql server 2008会报错 + /// + /// + /// + /// + /// + /// + public static Data Pagination(IEnumerable list, int page, int size) + { + return list == null ? new Data(0, page, null) : new Data(list.Count(), page, list.Skip(Convert.ToInt32((page <= 0 ? 0 : page - 1) * size)).Take(size).ToList()); + } + } + + /// + /// 数据页数 + /// + public class Data + { + /// + /// 总数 + /// + public int? Total { get; set; } + /// + /// 当前页码 + /// + public int? Current { get; set; } + /// + /// 数据 + /// + public object List { get; set; } + + /// + /// 入参 + /// + /// + /// + /// + public Data(int? total, int? current, object list) + { + Total = total ?? 0; + Current = current; + List = list; + } + } +} + diff --git a/PEIS.Common/Helper/Redis/RedisHelper.cs b/PEIS.Common/Helper/Redis/RedisHelper.cs new file mode 100644 index 0000000..5e6babe --- /dev/null +++ b/PEIS.Common/Helper/Redis/RedisHelper.cs @@ -0,0 +1,127 @@ +using System; +using Newtonsoft.Json; +using PEIS.Common.Helper.Encryption; +using StackExchange.Redis; + +namespace PEIS.Common.Helper.Redis +{ + /// + /// Redis帮助类--- 项目的appsetting.json 文件里面必须包含 Redis ConnectionString 的配置 + /// + public class RedisHelper + { + private static readonly object Locker = new object(); + //连接多路复用器 + private ConnectionMultiplexer _redisMultiplexer; + + private IDatabase _db = null; + + private static RedisHelper _instance = null; + /// + /// 单例模式 + /// + public static RedisHelper Instance + { + get + { + if (_instance != null) return _instance; + lock (Locker) + { + _instance ??= new RedisHelper(); + } + return _instance; + } + } + + /// + /// 连接redis + /// + public void InitConnect() + { + try + { + //连接redis服务器 + var redisConnection = AppSettingJsonHelper.GetSection("Redis","ConnectionString"); + _redisMultiplexer = ConnectionMultiplexer.Connect(redisConnection); + _db = _redisMultiplexer.GetDatabase(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + _redisMultiplexer = null; + _db = null; + } + } + + /// + /// 实例化 + /// + public RedisHelper() + { + InitConnect(); + } + #region 通用key操作 + /// + /// 判断键是否存在 + /// + public bool ExistsKey(string key) + { + return _db.KeyExists(key); + } + + /// + /// 删除键 + /// + public bool DeleteKey(string key) + { + return _db.KeyDelete(key); + } + #endregion + + #region string操作 + /// + /// 保存单个key value + /// + /// 键 + /// 值 + /// 过期时间 + public bool SetStringKey(string key, string value, TimeSpan? expiry=null) + { + expiry ??= new TimeSpan(0, 5, 0); + return _db.StringSet(key, value, expiry); + } + + /// + /// 获取单个key的值 + /// + public RedisValue GetRedisValue(string key) + { + return _db.StringGet(key); + } + + + public string GetStringValue(string key) + { + return _db.StringGet(key); + } + /// + /// 保存一个对象 + /// + /// 对象的类型 + public bool SetObjectKey(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + { + var json = JsonConvert.SerializeObject(obj); + return _db.StringSet(key, json, expiry); + } + /// + /// 获取一个key的对象 + /// + /// 返回类型 + public T GetStringKey(string key) + { + var value = _db.StringGet(key); + return value.IsNullOrEmpty ? default : JsonConvert.DeserializeObject(value); + } + #endregion + } +} diff --git a/PEIS.Common/Helper/Request/RequestHelper.cs b/PEIS.Common/Helper/Request/RequestHelper.cs new file mode 100644 index 0000000..df35f0b --- /dev/null +++ b/PEIS.Common/Helper/Request/RequestHelper.cs @@ -0,0 +1,112 @@ +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace PEIS.Common.Helper.Request +{ + public class RequestHelper + { + /// + /// get方法获取文件流 + /// + /// + /// + public static async Task GetFileStream(string url) + { + using var client = new HttpClient(); + var msg = await client.GetAsync($"{url}"); + if (!msg.IsSuccessStatusCode) return null; + // create a new file to write to + var contentStream = await msg.Content.ReadAsStreamAsync(); + return contentStream; + } + /// + /// get方法返回实体对象 + /// + /// + /// + /// + + public static async Task GetEntity(string url) + { + using var client = new HttpClient(); + var msg = await client.GetAsync($"{url}"); + if (!msg.IsSuccessStatusCode) return default; + var content = await msg.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(content); + } + /// + /// get方法返回文本字符 + /// + /// + /// + + public static async Task GetString(string url) + { + using var client = new HttpClient(); + var msg = await client.GetAsync($"{url}"); + if (!msg.IsSuccessStatusCode) return default; + return await msg.Content.ReadAsStringAsync(); + } + /// + /// post方法返回文件流 + /// + /// + /// + /// + /// + public static async Task PostFileStream(string url,T entity) + { + using var client = new HttpClient(); + var msg = await client.PostAsync($"{url}", new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json")); + if (!msg.IsSuccessStatusCode) return null; + // create a new file to write to + var contentStream = await msg.Content.ReadAsStreamAsync(); // get the actual content stream + return contentStream; + } + /// + /// post方法返回实体对象 + /// + /// + /// + /// + /// + /// + + public static async Task PostEntity(string url,T entity) + { + using var client = new HttpClient(); + var msg = await client.PostAsync($"{url}", new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json")); + if (!msg.IsSuccessStatusCode) return default; + var content = await msg.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(content); + } + + + public static async Task PostFormDataEntity(string url, FormUrlEncodedContent formUrl) + { + using var client = new HttpClient(); + var msg = await client.PostAsync($"{url}", formUrl); + if (!msg.IsSuccessStatusCode) return default; + var content = await msg.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(content); + } + + /// + /// post方法返回文本字符 + /// + /// + /// + /// + /// + public static async Task PostString(string url,T entity) + { + using var client = new HttpClient(); + var msg = await client.PostAsync($"{url}", new StringContent(JsonConvert.SerializeObject(entity), Encoding.UTF8, "application/json")); + if (!msg.IsSuccessStatusCode) return default; + return await msg.Content.ReadAsStringAsync(); + } + } +} diff --git a/PEIS.Common/Helper/Response/ResponseHelper.cs b/PEIS.Common/Helper/Response/ResponseHelper.cs new file mode 100644 index 0000000..f8da9a7 --- /dev/null +++ b/PEIS.Common/Helper/Response/ResponseHelper.cs @@ -0,0 +1,365 @@ +using System; +using System.ComponentModel; +using Microsoft.AspNetCore.Mvc; + +namespace PEIS.Common.Helper.Response +{ + public static class ResponseHelper + { + /// + /// 首位: + /// 3:warning + /// 4:info(提示信息) + /// 5:error; + /// 6:后端校验,前端不报错 + /// 倒数第二位: + /// 0:代码校验出的错 + /// 1:业务流程里面的错误 + /// 4: notFind + /// 5: 权限 + /// + public enum ErrorEnum + { + + #region 3:warning + //倒数第二位 0 + + //倒数第二位 1 + + /// + /// 申请单已经发送到检验科,请联系检验科取消配血,并在his中删除医嘱及记账信息 + /// + [Description("申请单已经发送到检验科,请联系检验科取消配血,并在his中删除医嘱及记账信息")] + HasBeenSent = 30011, + /// + /// 申请已发送或已作废,请勿重复操作 + /// + [Description("申请已发送或已作废,请勿重复操作")] + RepeatSending = 30012, + /// + /// 条码作废- 改条码在检验科已经扫码上机,不能作废 + /// + [Description("该条码在检验科已经扫码上机,不能作废")] + NotCancelBarcode = 30013, + /// + /// 检验科未发血 + /// + [Description("检验科未发血")] + NotSend = 30014, + + /// + /// 血袋已接收 + /// + [Description("血袋已接收")] + BloodReceived = 30015, + /// + /// 操作时间不能超过当前时间 + /// + [Description("操作时间不能超过当前时间")] + NurseTimeOut = 30016, + /// + /// 输注记录已反馈 + /// + [Description("输注记录已反馈")] + InfusionFeedback = 3017, + /// + /// 输注记录已反馈 + /// + [Description("血袋配血科室不匹配")] + DeptMismatch = 3018, + + [Description("自助申请单名称重复")] + ApplicationNameRepeat = 30019, + + + [Description("该用户码不属于此次采集场所")] + UserCodeError = 300101, + + + [Description("该申请未审核")] + ApplicationNotAudit = 300102, + + + [Description("Excel有误")] + ExcelIsError = 300103, + + [Description("未付款")] + Unpaid = 300104, + + [Description("该用户信息已经注册过")] + UserInfoRepeat = 300105, + + + [Description("该用户信息已经注册过")] + UserBindRepeat = 300106, + + [Description("已超过最终上传时间")] + UploadFileTimeOut = 300107, + + [Description("请登录")] + NotLogin = 300108, + + [Description("团检申请不能停用")] + GroupInspectionNotDelete = 300109, + + [Description("该申请已经停用")] + ApplicationIsStop = 300120, + + //倒数第二位 4 + + /// + /// 未找到数据 + /// + [Description("未找到数据")] + NotFindData = 30041, + /// + /// 未找到输血申请单信息 + /// + [Description("未找到输血申请单信息")] + NotFindBloodRequest = 30042, + /// + /// 未找到患者信息 + /// + [Description("未找到患者信息")] + NotFindPatientInfo = 30043, + /// + /// 未找到样本信息 + /// + [Description("未找到样本信息")] + NotFindSampleInfo = 30044, + /// + /// 未找到知情同意书信息 + /// + [Description("未找到知情同意书信息")] + NotFindInformed = 30045, + /// + /// 未找到交叉配血信息 + /// + [Description("未找到交叉配血信息")] + NotFindBloodMatch = 30046, + + /// + /// 未找到血袋库存信息 + /// + [Description("未找到血袋库存信息")] + NotFindBlood = 30047, + /// + /// 未找到输注记录数据 + /// + [Description("未找到输注记录")] + NotFindInfusion = 30048, + /// + /// 未找到不良反应记录 + /// + [Description("未找到不良反应记录")] + NotFindReaction = 30049, + /// + /// 未找到输注前巡视记录 + /// + [Description("未找到输注前巡视记录")] + NotFindBeforeInspect = 30410, + /// + /// 未找到报告单 + /// + [Description("未找到报告单")] + NotFindReport = 30411, + //倒数第二位 5 权限 + + /// + /// 输血申请未审核 + /// + [Description("输血申请未审核")] + UnReviewBloodRequisition = 30051, + /// + /// 未进行医生审核 + /// + [Description("未进行医生审核")] + UnReviewDoctor = 30052, + /// + /// 权限不足,医生无相关证书信息,如果确有证书请到his添加 + /// + [Description("权限不足,医生无相关证书信息,如果确有证书请到his添加")] + InsufficientPermissions = 30053, + /// + /// 医生审核职称权限不足 + /// + [Description("权限不足,医生职称不符合审核要求")] + InsufficientDoctorTitle = 30054, + /// + /// 护士审核权限不足 + /// + [Description("护士审核权限不足")] + NurseInsufficient = 30055, + #endregion + + #region 4:info + /// + /// 正在配血,请等待 + /// + [Description("正在配血,请等待")] + Matching = 40011, + + + #endregion + + #region 5:error + + /// + /// Token错误 + /// + [Description("Token错误")] + TokenError = 50001, + + [Description("参数错误")] + ParamsError = 50002, + + [Description("登录失败,用户名或密码错误")] + UserAndPwError = 50011, + /// + /// 医嘱业务流程错误-输血申请单发送 + /// + [Description("业务逻辑错误")] + BusinessError = 50012, + /// + /// 血型未确认-创建知情同意书 + /// + [Description("患者血型未确认")] + BloodAboRhError = 50013, + /// + /// 科室不匹配-首页获取在院患者列表 + /// + [Description("科室不匹配")] + DeptMismatchError = 50014, + + #endregion + + #region 6:后端校验,前端不报错 + + [Description("登录失败,用户名或密码为空")] + UserAndPwIsNull = 60001, + + #endregion + + } + /// + /// 获取枚举对应的Description + /// + /// + /// + public static string GetDescription(this Enum val) + { + var field = val.GetType().GetField(val.ToString()); + if (field == null) + return null; + var customAttribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)); + return customAttribute == null ? val.ToString() : ((DescriptionAttribute)customAttribute).Description; + } + /// + /// 返回需单独处理错误的信息 + /// + /// + /// + public static ActionResult Fail(ErrorEnum enums) + { + var code = Convert.ToInt32(enums); + var message = enums.GetDescription(); + var result = new ResultModel(code, message, ""); + return new OkObjectResult(result); + } + /// + /// 返回需单独处理错误的信息,自定义message + /// + /// + /// + /// + public static ActionResult Fail(ErrorEnum enums, string message) + { + var code = Convert.ToInt32(enums); + var result = new ResultModel(code, message, ""); + return new OkObjectResult(result); + } + + /// + /// + /// + /// + /// + /// + public static ActionResult Fail(object data, ErrorEnum enums) + { + var result = new ResultModel(Convert.ToInt32(enums),enums.GetDescription(), data); + return new OkObjectResult(result); + } + /// + /// 成功(200,无返回) + /// + /// + public static ActionResult Success() + { + var result = new ResultModel(200, "Success", ""); + return new OkObjectResult(result); + } + /// + /// 成功(200,返回数据) + /// + /// + /// + public static ActionResult Success(object data)//File(ms.ToArray(), "application/pdf"); + { + var result = new ResultModel(200, "Success", data); + return new OkObjectResult(result); + } + /// + /// 返回自定义错误 + /// + /// + /// + /// + public static ActionResult CustomizeFail(string message, int code = 5) + { + code = code switch + { + 5 => 50001, + 6 => 60001, + 4 => 40001, + 3 => 30001, + _ => code + }; + return new OkObjectResult(new ResultModel(code, message, "")); + } + /// + /// 失败(500) + /// + /// + public static ActionResult ServerError() + { + var result = new ResultModel(500, "服务器内部错误,请联系系统管理员。", ""); + return new OkObjectResult(result); + } + /// + /// 失败(500) + /// + /// + public static ActionResult Fail(Exception ex) + { + var result = new ResultModel(500, ex.Message, ""); + return new OkObjectResult(result); + } + } + + public class ResultModel + { + public int Code { get; set; } + public string Message { get; set; } + public object Data { get; set; } + public ResultModel() + { + } + public ResultModel(int code, string message, object data) + { + Code = code; + Message = message; + Data = data; + } + } +} diff --git a/PEIS.Common/Helper/SqlServer/SqlHelper.cs b/PEIS.Common/Helper/SqlServer/SqlHelper.cs new file mode 100644 index 0000000..57c5e99 --- /dev/null +++ b/PEIS.Common/Helper/SqlServer/SqlHelper.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Dynamic; +using System.Linq; + +namespace PEIS.Common.Helper.SqlServer +{ + public class SqlHelper + { + public static readonly string ConnectString = ""; + private SqlConnection _con; + private SqlCommand _cmd; + + private SqlDataAdapter _sda; + private SqlDataReader _sdr; + private DataSet _ds; + private DataView _dv; + + public static SqlConnection GetConnection()//定义成静态的,很重要! + { + return new SqlConnection(ConnectString); + } + /// + /// 打开数据库连接 + /// + public void OpenDataBase() + { + _con = new SqlConnection(ConnectString); + _con.Open(); + } + /// + /// 关闭数据库连接 + /// + public void CloseDataBase() + { + + _con.Close(); + _con.Dispose(); + + } + + /// + /// 返回DataSet数据集 + /// + /// 数据库查询字符串 + /// + /// DataSet + public DataSet GetDs(string sqlStr, string tableName) + { + OpenDataBase(); + _sda = new SqlDataAdapter(sqlStr, _con); + _ds = new DataSet(); + _sda.Fill(_ds, tableName); + CloseDataBase(); + return _ds; + } + public DataView GetDv(string sqlStr) + { + OpenDataBase(); + _sda = new SqlDataAdapter(sqlStr, _con); + _ds = new DataSet(); + _sda.Fill(_ds); + _dv = _ds.Tables[0].DefaultView; + CloseDataBase(); + return _dv; + + } + /// + /// 返回DataReader对象 + /// + /// 查询字符串 + /// 返回值 + public SqlDataReader GetDataReader(string sqlString) + { + OpenDataBase(); + _cmd = new SqlCommand(sqlString, _con); + _sdr = _cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection); + + return _sdr; + + + } + public DataSet DataSet(string sql) + { + SqlConnection con = new SqlConnection(ConnectString); + SqlCommand cmd = new SqlCommand(sql, con); + SqlDataAdapter da = new SqlDataAdapter(cmd); + DataSet ds = null; + try + { + con.Open(); + ds = new DataSet(); + da.Fill(ds); + + } + catch (SqlException ex) + { + throw ex; + } + catch (Exception ex) + { + throw ex; + } + finally + { + con.Close(); + } + return ds; + } + + public static DataTable DataTable(string sql) + { + var con = new SqlConnection(ConnectString); + var cmd = new SqlCommand(sql, con); + var da = new SqlDataAdapter(cmd); + DataTable ds = null; + try + { + con.Open(); + ds = new DataTable(); + da.Fill(ds); + + } + catch (SqlException ex) + { + throw ex; + } + catch (Exception ex) + { + throw ex; + } + finally + { + con.Close(); + } + return ds; + } + + public static DataTable DataTable(string sql,string connectString) + { + var con = new SqlConnection(connectString); + var cmd = new SqlCommand(sql, con); + var da = new SqlDataAdapter(cmd); + DataTable ds = null; + try + { + con.Open(); + ds = new DataTable(); + da.Fill(ds); + + } + catch (SqlException ex) + { + throw ex; + } + catch (Exception ex) + { + throw ex; + } + finally + { + con.Close(); + } + return ds; + } + + /// + /// 可以传入连接字符串 返回T类型对象 + /// + /// + /// + /// + /// + public static List Entity(string sql,string connectString) + { + return ConvertDataTableToEntity(DataTable(sql,connectString)); + } + /// + /// 根据sql语句返回 T 类型对象 + /// + /// + /// + /// + + public static List Entity(string sql) + { + return ConvertDataTableToEntity(DataTable(sql)); + } + /// + /// 根据sql语句直接返回泛型对象 + /// + /// + /// + public static List Entity(string sql) + { + return ConvertDataTableToEntity(DataTable(sql)); + } + /// + /// 执行Sql语句方法没有返回值 + /// + /// 传入的查询参数 + public void RunSql(string sqlStr) + { + OpenDataBase(); + _cmd = new SqlCommand(sqlStr, _con); + _cmd.ExecuteNonQuery(); + CloseDataBase(); + } + /// + /// 返回查询结果的首行首列 + /// + /// 查询字符串 + /// 返回结果 + public string ReturnSql(string sqlStr) + { + OpenDataBase(); + string returnSql; + try + { + _cmd = new SqlCommand(sqlStr, _con); + returnSql = _cmd.ExecuteScalar().ToString(); + } + catch(Exception ex) + { + throw ex; + } + + CloseDataBase(); + return returnSql; + } + + /// + /// 将DataTable转成 T 实体对象 + /// + /// + /// + /// + public static List ConvertDataTableToEntity(DataTable dt) + { + return (from DataRow row in dt.Rows select GetItem(row)).ToList(); + } + /// + /// 组装实体的方法 + /// + /// + /// + /// + private static T GetItem(DataRow dr) + { + var temp = typeof(T); + var obj = Activator.CreateInstance(); + + foreach (DataColumn column in dr.Table.Columns) + { + foreach (var pro in temp.GetProperties()) + { + if (string.Equals(pro.Name, column.ColumnName.Replace("_", string.Empty), StringComparison.CurrentCultureIgnoreCase)) + { + if (dr[column.ColumnName] is DBNull) + { + pro.SetValue(obj, default, null); + continue; + } + pro.SetValue(obj, dr[column.ColumnName], null); + if (dr[column.ColumnName] is string) + pro.SetValue(obj, Convert.ToString(dr[column.ColumnName]).Trim(), null); + } + else + continue; + } + } + return obj; + } + + /// + /// 将DataTable转成 泛型实体对象 + /// + /// + /// + public static List ConvertDataTableToEntity(DataTable dt) + { + return (from DataRow row in dt.Rows select GetItem(row)).ToList(); + } + + /// + /// 不需要定义实体,直接返回泛型实体 + /// + /// + /// + + public static ExpandoObject GetItem(DataRow dr) + { + dynamic dynamicEntity = new ExpandoObject(); + foreach (DataColumn column in dr.Table.Columns) + { + (dynamicEntity as IDictionary).Add(column.ColumnName, (dr[column.ColumnName] is string)? dr[column.ColumnName].ToString().Trim(): dr[column.ColumnName]); + } + + return dynamicEntity; + } + } +} diff --git a/PEIS.Common/Helper/StringText/PinYinHelper.cs b/PEIS.Common/Helper/StringText/PinYinHelper.cs new file mode 100644 index 0000000..87dc80d --- /dev/null +++ b/PEIS.Common/Helper/StringText/PinYinHelper.cs @@ -0,0 +1,34 @@ +using Microsoft.International.Converters.PinYinConverter; + +namespace PEIS.Common.Helper.StringText +{ + /// + /// 拼音帮助类 + /// + public class PinYinHelper + { + /// + /// 获取首字母 + /// + /// + /// + public static string GetFirstPinyin(string str) + { + var r = string.Empty; + foreach (var obj in str) + { + try + { + var chineseChar = new ChineseChar(obj); + var t = chineseChar.Pinyins[0]; + r += t[..1]; + } + catch + { + r += obj.ToString(); + } + } + return r; + } + } +} diff --git a/PEIS.Common/Helper/StringText/StringHelper.cs b/PEIS.Common/Helper/StringText/StringHelper.cs new file mode 100644 index 0000000..fdcb52f --- /dev/null +++ b/PEIS.Common/Helper/StringText/StringHelper.cs @@ -0,0 +1,25 @@ +using System; + +namespace PEIS.Common.Helper.StringText +{ + /// + /// 相关码的生成 + /// + public class StringHelper + { + /// + ///获取文本数字码 + /// + /// 需要转换的文本 + /// 需要码长度 + /// + public string GetCode(string code, int length) + { + code = PinYinHelper.GetFirstPinyin(code); + var random = new Random(); + var numberLength = length - code.Length; + code += random.Next(Convert.ToInt32(Math.Pow(10, numberLength)),Convert.ToInt32(Math.Pow(10, numberLength + 1))); + return code; + } + } +} diff --git a/PEIS.Common/Helper/StringText/TypeChangeHelper.cs b/PEIS.Common/Helper/StringText/TypeChangeHelper.cs new file mode 100644 index 0000000..a242f66 --- /dev/null +++ b/PEIS.Common/Helper/StringText/TypeChangeHelper.cs @@ -0,0 +1,20 @@ +using System; +using System.IO; + +namespace PEIS.Common.Helper.StringText +{ + public class TypeChangeHelper + { + /// + /// 流转base64 适用于图片流 + /// + /// + /// + public static string StreamToBase64(Stream stream) + { + using var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + return Convert.ToBase64String(memoryStream.ToArray()); + } + } +} diff --git a/PEIS.Common/Helper/Verify/IdCardHelper.cs b/PEIS.Common/Helper/Verify/IdCardHelper.cs new file mode 100644 index 0000000..f74325a --- /dev/null +++ b/PEIS.Common/Helper/Verify/IdCardHelper.cs @@ -0,0 +1,45 @@ +using System; + +namespace PEIS.Common.Helper.Verify +{ + public class IdCardHelper + { + /// + /// 18位身份证验证 //校验码验证 符合GB11643-1999标准 + /// + /// 身份证号 + /// + public static bool CheckIdCard18(string id) + { + if (long.TryParse(id.Remove(17), out var n) == false || n < Math.Pow(10, 16) || + long.TryParse(id.Replace('x', '0').Replace('X', '0'), out n) == false) + { + return false; //数字验证 + } + + const string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91"; + if (address.IndexOf(id.Remove(2), StringComparison.Ordinal) == -1) + { + return false; //省份验证 + } + + var birth = id.Substring(6, 8).Insert(6, "-").Insert(4, "-"); + if (DateTime.TryParse(birth, out _) == false) + { + return false; //生日验证 + } + + var arrVerifyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(','); + var wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(','); + var ai = id.Remove(17).ToCharArray(); + var sum = 0; + for (var i = 0; i < 17; i++) + { + sum += int.Parse(wi[i]) * int.Parse(ai[i].ToString()); + } + + Math.DivRem(sum, 11, out var y); + return arrVerifyCode[y] == id.Substring(17, 1).ToLower(); + } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/AuditResult.cs b/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/AuditResult.cs new file mode 100644 index 0000000..76206ae --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/AuditResult.cs @@ -0,0 +1,24 @@ +namespace PEIS.Common.Helper.WeChat.Models.SubscribeMessage +{ + public class AuditResult + { + /// + /// 申请类型 + /// + public string phrase1 { get; set; } + /// + /// 审核结果 + /// + + public string phrase2 { get; set; } + /// + /// 审核时间 + /// + + public string date3 { get; set; } + /// + /// 备注 + /// + public string thing4 { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/PaymentSuccessful.cs b/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/PaymentSuccessful.cs new file mode 100644 index 0000000..21a9054 --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/SubscribeMessage/PaymentSuccessful.cs @@ -0,0 +1,26 @@ +namespace PEIS.Common.Helper.WeChat.Models.SubscribeMessage +{ + public class PaymentSuccessful + { + /// + /// 就诊人 + /// + public string thing6 { get; set; } + /// + /// 服务名称 + /// + public string phrase1 { get; set; } + /// + /// 订单总价 + /// + public string amount3 { get; set; } + /// + /// 下单时间 + /// + public string date4 { get; set; } + /// + /// 备注 + /// + public string thing5 { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/SubscribeMessageModel.cs b/PEIS.Common/Helper/WeChat/Models/SubscribeMessageModel.cs new file mode 100644 index 0000000..cecb956 --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/SubscribeMessageModel.cs @@ -0,0 +1,14 @@ +namespace PEIS.Common.Helper.WeChat.Models +{ + public class SubscribeMessageModel + { + public string touser { get; set; } + + public string template_id { get; set; } + + public string page { get; set; } + public object data { get; set; } + public string miniprogram_state { get; set; } + public string lang { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/TokenModel.cs b/PEIS.Common/Helper/WeChat/Models/TokenModel.cs new file mode 100644 index 0000000..982ad25 --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/TokenModel.cs @@ -0,0 +1,8 @@ +namespace PEIS.Common.Helper.WeChat.Models +{ + public class TokenModel + { + public string access_token { get; set; } + public int? expires_in { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/UnlimitedQrCodeModel.cs b/PEIS.Common/Helper/WeChat/Models/UnlimitedQrCodeModel.cs new file mode 100644 index 0000000..5441fee --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/UnlimitedQrCodeModel.cs @@ -0,0 +1,36 @@ +namespace PEIS.Common.Helper.WeChat.Models +{ + public class UnlimitedQrCodeModel + { + /// + /// 传参 + /// + public string scene { get; set; } + /// + /// 小程序页面 + /// + public string page { get; set; } + /// + /// 是否检查页面存在 + /// + public bool check_path { get; set; } + + /// + /// 打开版本 + /// + public string env_version { get; set; } + + /// + /// 宽度 + /// + public int width { get; set; } + /// + /// 自动配置线条颜色 + /// + public bool auto_color { get; set; } + /// + /// 是否需要透明底色 + /// + public bool is_hyaline { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Models/WeChatPayModel.cs b/PEIS.Common/Helper/WeChat/Models/WeChatPayModel.cs new file mode 100644 index 0000000..5d36e21 --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Models/WeChatPayModel.cs @@ -0,0 +1,15 @@ +namespace PEIS.Common.Helper.WeChat.Models +{ + public class WeChatPayModel + { + public string PayCode { get; set; } + public string Title { get; set; } + public string CallNo { get; set; } + public decimal TotalFee { get; set; } + public string Name { get; set; } + public string CardNo { get; set; } + public string PatientId { get; set; } + public string Mid { get; set; } + public string CollectId { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Response/OpenIdResponse.cs b/PEIS.Common/Helper/WeChat/Response/OpenIdResponse.cs new file mode 100644 index 0000000..8113fcd --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Response/OpenIdResponse.cs @@ -0,0 +1,8 @@ +namespace PEIS.Common.Helper.WeChat.Response +{ + public class OpenIdResponse : WeChatResponse + { + public string Session_Key { get; set; } + public string Openid { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Response/UnlimitedQrCodeResponse.cs b/PEIS.Common/Helper/WeChat/Response/UnlimitedQrCodeResponse.cs new file mode 100644 index 0000000..e61d4de --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Response/UnlimitedQrCodeResponse.cs @@ -0,0 +1,8 @@ +namespace PEIS.Common.Helper.WeChat.Response +{ + public class UnlimitedQrCodeResponse:WeChatResponse + { + public string ContentType { get; set; } + public byte Buffer { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/Response/WeChatResponse.cs b/PEIS.Common/Helper/WeChat/Response/WeChatResponse.cs new file mode 100644 index 0000000..602ee7a --- /dev/null +++ b/PEIS.Common/Helper/WeChat/Response/WeChatResponse.cs @@ -0,0 +1,8 @@ +namespace PEIS.Common.Helper.WeChat.Response +{ + public class WeChatResponse + { + public int ErrCode { get; set; } + public string ErrMsg { get; set; } + } +} diff --git a/PEIS.Common/Helper/WeChat/WeChat.cs b/PEIS.Common/Helper/WeChat/WeChat.cs new file mode 100644 index 0000000..26c6d94 --- /dev/null +++ b/PEIS.Common/Helper/WeChat/WeChat.cs @@ -0,0 +1,77 @@ +using System.IO; +using System.Net.Http; +using PEIS.Common.Helper.Request; +using PEIS.Common.Helper.Response; +using PEIS.Common.Helper.WeChat.Models; +using PEIS.Common.Helper.WeChat.Response; + +namespace PEIS.Common.Helper.WeChat +{ + public class WeChat + { + /// + /// 小程序通过code获取openId + /// + /// + /// + /// + /// + public static string GetOpenId(string appId, string secret, string code) + { + var url = $"https://api.weixin.qq.com/sns/jscode2session?appid={appId}&secret={secret}&js_code={code}&grant_type=authorization_code"; + return RequestHelper.GetString(url).Result; + // var client = new HttpClient(); + // var response = await client.GetAsync(uri); + // response.EnsureSuccessStatusCode(); + // return await response.Content.ReadAsStringAsync(); + } + /// + /// 获取token + /// + /// + /// + /// + public static TokenModel GetToken(string appId, string secret) + { + var url = $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}"; + return RequestHelper.GetEntity(url).Result; + } + + /// + /// 微信支付码 + /// + /// + /// + /// + public static string QrCodePay(string httpIp,FormUrlEncodedContent weChatPay) + { + return RequestHelper.PostFormDataEntity($"{httpIp}/wx/pay/qrCodePay.do",weChatPay).Result.Data.ToString(); + } + + /// + /// 小程序码 + /// + /// + /// + /// + public static Stream UnlimitedQrCode(string token,UnlimitedQrCodeModel unlimitedQrCode) + { + return RequestHelper + .PostFileStream( + $"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={token}", unlimitedQrCode).Result; + } + + /// + /// 一次性订阅消息 + /// + /// + /// + /// + public static WeChatResponse SubscribeMessage(string token,SubscribeMessageModel subscribeMessage) + { + return RequestHelper + .PostEntity( + $"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={token}", subscribeMessage).Result; + } + } +} diff --git a/PEIS.Common/Middleware/JwtMiddleware.cs b/PEIS.Common/Middleware/JwtMiddleware.cs new file mode 100644 index 0000000..15a5f94 --- /dev/null +++ b/PEIS.Common/Middleware/JwtMiddleware.cs @@ -0,0 +1,131 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; +using PEIS.Common.Helper.Response; + +namespace PEIS.Common.Middleware +{ + public class JwtMiddleware + { + private readonly RequestDelegate _next; + private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); + private static IConfiguration Configuration { get; set; } + public JwtMiddleware(RequestDelegate next, IConfiguration config) + { + _next = next; + Configuration = config; + } + + public async Task Invoke(HttpContext context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + var tokenStr = context.Request.Headers["Authorization"].ToString(); + //未携带token请求不需要授权页面,让其直接通过,用方法名上面的校验来判断 + if (!string.IsNullOrEmpty(tokenStr)) + { + //携带了token,判断token,回传失效,过期,或者续期 + var setting = new JsonSerializerSettings + { + ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() + }; + //token 是否合规 + if (!IsCanReadToken(ref tokenStr)) + { + var result = new ResultModel() { Message = "invalid token", Code = Convert.ToInt32(ResponseHelper.ErrorEnum.TokenError) }; + await context.Response.WriteAsync( JsonConvert.SerializeObject(result, setting), Encoding.UTF8); + return; + } + // token是否超过有效期 + if (IsExp(tokenStr)) + { + var result = new ResultModel() { Message = "token expired", Code = Convert.ToInt32(ResponseHelper.ErrorEnum.TokenError) }; + await context.Response.WriteAsync( JsonConvert.SerializeObject(result, setting), Encoding.UTF8); + return; + } + var oldClaims = GetJwtSecurityToken(tokenStr).Claims; + var claims = new Claim[oldClaims?.Count() ?? 0]; + for (var i = 0; i < (oldClaims?.Count() ?? 0); i++) + { + claims[i] = new Claim(oldClaims.ToList()[i].Type, oldClaims.ToList()[i].Value); + } + // 获取SecurityKey + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("Authentication")["SecurityKey"])); + var token = new JwtSecurityToken( + issuer: Configuration.GetSection("Authentication")["IsSure"], // 发布者 + audience: Configuration.GetSection("Authentication")["Audience"], // 接收者 + notBefore: DateTime.Now, // token签发时间 + expires: DateTime.Now.AddMinutes(30), // token过期时间 + claims: claims, // 该token内存储的自定义字段信息 + signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) // 用于签发token的秘钥算法 + ); + // 返回成功信息,写出token + var data = new JwtSecurityTokenHandler().WriteToken(token); + context.Response.Headers.Add("newToken", data); + } + await _next(context); + } + + /// + /// Token是否是符合要求的标准 Json Web 令牌 + /// + /// + /// + public bool IsCanReadToken(ref string tokenStr) + { + tokenStr = tokenStr.Replace("Bearer ", string.Empty); + var key = Encoding.UTF8.GetBytes(Configuration.GetSection("Authentication")["SecurityKey"]); + var tokenValidationParameters = new TokenValidationParameters + { + ValidIssuer = Configuration.GetSection("Authentication")["IsSure"], + ValidAudience = Configuration.GetSection("Authentication")["Audience"], + IssuerSigningKey = new SymmetricSecurityKey(key), + RequireExpirationTime = true, + ClockSkew = TimeSpan.Zero + }; + // 验证token是否有效,如果过期,报错SecurityTokenExpiredException + // 报错信息:IDX10223 : Lifetime validation failed + try + { + var principal = _jwtSecurityTokenHandler.ValidateToken(tokenStr, tokenValidationParameters, out var securityToken); + return principal != null; + } + catch (Exception) + { + return false; + } + } + + /// + /// 从Token解密出JwtSecurityToken,JwtSecurityToken : SecurityToken + /// + /// + /// + public JwtSecurityToken GetJwtSecurityToken(string tokenStr) + { + var jwt = _jwtSecurityTokenHandler.ReadJwtToken(tokenStr); + return jwt; + } + /// + /// 判断token是否过期 + /// + /// + /// + public bool IsExp(string token) + { + return GetDateTime(Convert.ToDouble(GetJwtSecurityToken(token)?.Claims.First(c => c.Type == JwtRegisteredClaimNames.Exp)?.Value)) < DateTime.Now; + } + private static DateTime GetDateTime(double timeStamp)// 时间戳Timestamp转换成日期 + { + var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + dateTime = dateTime.AddSeconds(timeStamp).ToLocalTime(); + return dateTime; + } + } +} diff --git a/PEIS.Common/Nlog.config b/PEIS.Common/Nlog.config new file mode 100644 index 0000000..0821688 --- /dev/null +++ b/PEIS.Common/Nlog.config @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PEIS.Common/README.md b/PEIS.Common/README.md new file mode 100644 index 0000000..0a84523 --- /dev/null +++ b/PEIS.Common/README.md @@ -0,0 +1,41 @@ +# .net core 3.1 web Api 帮助类合集 +1. Auth(Jwt相关的帮助类): +- AuthHelper +- JwtHelper +2. Cache(缓存) 适用于web Api的项目,需要传入IMemoryCache +- CacheHelper +3. Code(二维码) 生成二维码的帮助类,可以生成带标题,图标的二维码以及空二维码 +- CodeHelper +4. Encryption(加解密) +- AppSettingJsonHelper web Api的配置帮助类 +- ConnectionStringHelper 连接字符串解密(EF的) +- DesHelper Des加解密 +- RsaHelper 公私钥加解密 +5. Entity (实体类型的一些互相转换) => 反射来实现 +- ModelToEntity +6. Excel 读取excel的操作 +- ExcelHelper +7. File 对于文件的操作 (文件的删除创建判断存在之类的) +- FileHelper +8. Nlog 日志的帮助类 +- LogHelper +9. Page 分页的帮助类 +- PageHelper +10. Redis +- RedisHelper Redis的帮助类 +11. Request http get post 的各种请求以及返回回来不同类型的参数 +- RequestHelper +12. Response 返回的规范定义 所有接口返回值必须返回这个类型 +- ResponseHepler +13. SqlServer sqlserver的原生操作 (推荐观看) +- SqlHelper +14. StringText 字符的相关操作类 +- CodeHelper 获取文本数字码(不是文本里面的数字,数字码意义自己搜索) +- PinYinHelper 获取首字母之类的 +- TypeChange 流的转换 +15. Verify 验证 +- IdCardHelper 身份证验证 +16. WeChat 微信的帮助类,调用微信接口的(可以看,不要尝试,会影响我们正式业务,token会互冲) + + +