Browse Source

一体机模块迁入WingCloudServer

warr.qian 1 year ago
parent
commit
4801ca9035
100 changed files with 7273 additions and 0 deletions
  1. 49 0
      src/VitalMixtureService/Common/AnalyzeJsonData.cs
  2. 167 0
      src/VitalMixtureService/Common/AnalyzeStrategy.cs
  3. 46 0
      src/VitalMixtureService/Common/AnalyzeXmlData.cs
  4. 27 0
      src/VitalMixtureService/Common/AssemblyLoader.cs
  5. 17 0
      src/VitalMixtureService/Common/CacheCreator.cs
  6. 572 0
      src/VitalMixtureService/Common/CronHelper.cs
  7. 27 0
      src/VitalMixtureService/Common/DBRepositoryFactory.cs
  8. 203 0
      src/VitalMixtureService/Common/Encrypt/Base64EncryptHelper.cs
  9. 74 0
      src/VitalMixtureService/Common/Encrypt/DBEncryptHelper.cs
  10. 171 0
      src/VitalMixtureService/Common/Encrypt/DESHelper.cs
  11. 49 0
      src/VitalMixtureService/Common/Encrypt/EmptyEncrypt.cs
  12. 78 0
      src/VitalMixtureService/Common/Encrypt/EncryptStrategy.cs
  13. 165 0
      src/VitalMixtureService/Common/Encrypt/RSAHelper.cs
  14. 206 0
      src/VitalMixtureService/Common/Encrypt/SM2Helper.cs
  15. 147 0
      src/VitalMixtureService/Common/Encrypt/SM4Helper.cs
  16. 181 0
      src/VitalMixtureService/Common/EnvironmentConfigManager.cs
  17. 17 0
      src/VitalMixtureService/Common/Extensions.cs
  18. 77 0
      src/VitalMixtureService/Common/FileCache.cs
  19. 11 0
      src/VitalMixtureService/Common/ICache.cs
  20. 45 0
      src/VitalMixtureService/Common/MemoryCache.cs
  21. 28 0
      src/VitalMixtureService/Common/MemoryIds.cs
  22. 29 0
      src/VitalMixtureService/Common/NumberGenerator.cs
  23. 137 0
      src/VitalMixtureService/Common/ProcessStarter.cs
  24. 31 0
      src/VitalMixtureService/Common/RequestConvertHelper.cs
  25. 26 0
      src/VitalMixtureService/Common/ResultConvertHelper.cs
  26. 53 0
      src/VitalMixtureService/Common/RpcClient.cs
  27. 22 0
      src/VitalMixtureService/Common/SequentialNumberGenerator.cs
  28. 81 0
      src/VitalMixtureService/Common/ServerLoggerEngine.cs
  29. 100 0
      src/VitalMixtureService/Common/UserHeartRateManager.cs
  30. 334 0
      src/VitalMixtureService/DBService/DBAutoMapperProfile.cs
  31. 62 0
      src/VitalMixtureService/DBService/Driver/Other/SpinThread.cs
  32. 85 0
      src/VitalMixtureService/DBService/Driver/Query/MongoRepertoryCenter.cs
  33. 63 0
      src/VitalMixtureService/DBService/Driver/Server/BackupDBJob.cs
  34. 35 0
      src/VitalMixtureService/DBService/Entities/AnalyzeConfigEntity.cs
  35. 56 0
      src/VitalMixtureService/DBService/Entities/BaseEntity.cs
  36. 65 0
      src/VitalMixtureService/DBService/Entities/CompletionRecordEntity.cs
  37. 90 0
      src/VitalMixtureService/DBService/Entities/ContractRecordEntity.cs
  38. 21 0
      src/VitalMixtureService/DBService/Entities/ContractTemplateEntity.cs
  39. 105 0
      src/VitalMixtureService/DBService/Entities/DeviceEntity.cs
  40. 53 0
      src/VitalMixtureService/DBService/Entities/DiagnosisEntity.cs
  41. 28 0
      src/VitalMixtureService/DBService/Entities/DictionaryEntity.cs
  42. 16 0
      src/VitalMixtureService/DBService/Entities/DynamicTypeEntity.cs
  43. 59 0
      src/VitalMixtureService/DBService/Entities/ExamEntity.cs
  44. 78 0
      src/VitalMixtureService/DBService/Entities/FollowUpEntity.cs
  45. 28 0
      src/VitalMixtureService/DBService/Entities/IBaseEntity.cs
  46. 21 0
      src/VitalMixtureService/DBService/Entities/LabelEntity.cs
  47. 39 0
      src/VitalMixtureService/DBService/Entities/NotificationEntity.cs
  48. 25 0
      src/VitalMixtureService/DBService/Entities/OperationLogEntity.cs
  49. 98 0
      src/VitalMixtureService/DBService/Entities/OrganizationEntity.cs
  50. 100 0
      src/VitalMixtureService/DBService/Entities/PatientEntity.cs
  51. 23 0
      src/VitalMixtureService/DBService/Entities/PatientExtensionEntity.cs
  52. 79 0
      src/VitalMixtureService/DBService/Entities/ReportEntity.cs
  53. 17 0
      src/VitalMixtureService/DBService/Entities/ResidenceEntity.cs
  54. 22 0
      src/VitalMixtureService/DBService/Entities/RoleEntity.cs
  55. 54 0
      src/VitalMixtureService/DBService/Entities/ScheduleEntity.cs
  56. 58 0
      src/VitalMixtureService/DBService/Entities/ServiceItemEntity.cs
  57. 36 0
      src/VitalMixtureService/DBService/Entities/ServicePackEntity.cs
  58. 32 0
      src/VitalMixtureService/DBService/Entities/StatisticEntity.cs
  59. 16 0
      src/VitalMixtureService/DBService/Entities/SystemSetting.cs
  60. 34 0
      src/VitalMixtureService/DBService/Entities/TeamEntity.cs
  61. 20 0
      src/VitalMixtureService/DBService/Entities/TeamRegionEntity.cs
  62. 28 0
      src/VitalMixtureService/DBService/Entities/TemplateEntity.cs
  63. 65 0
      src/VitalMixtureService/DBService/Entities/TokenEntity.cs
  64. 28 0
      src/VitalMixtureService/DBService/Entities/TownEntity.cs
  65. 38 0
      src/VitalMixtureService/DBService/Entities/UpgradeEntity.cs
  66. 66 0
      src/VitalMixtureService/DBService/Entities/UserEntity.cs
  67. 48 0
      src/VitalMixtureService/DBService/Entities/UserFeatureEntity.cs
  68. 18 0
      src/VitalMixtureService/DBService/Entities/UserPasswordEntity.cs
  69. 25 0
      src/VitalMixtureService/DBService/Entity/BaseDataEntity.cs
  70. 88 0
      src/VitalMixtureService/DBService/Entity/CodeCreator.cs
  71. 28 0
      src/VitalMixtureService/DBService/Entity/LogEntryDO.cs
  72. 15 0
      src/VitalMixtureService/DBService/Entity/MongoDataItem.cs
  73. 12 0
      src/VitalMixtureService/DBService/Entity/MongoPlatform.cs
  74. 12 0
      src/VitalMixtureService/DBService/Entity/MongoQuery.cs
  75. 55 0
      src/VitalMixtureService/DBService/Entity/MongoTable.cs
  76. 27 0
      src/VitalMixtureService/DBService/Job/DataPullingJobs/DataPullingJobBase.cs
  77. 369 0
      src/VitalMixtureService/DBService/Job/DataPullingJobs/VNoteDiagnosisDataPullingJob.cs
  78. 258 0
      src/VitalMixtureService/DBService/Job/DataPullingJobs/VNotePatientDataPullingJob.cs
  79. 14 0
      src/VitalMixtureService/DBService/Job/IJob.cs
  80. 110 0
      src/VitalMixtureService/DBService/Job/JobQueue.cs
  81. 484 0
      src/VitalMixtureService/DBService/Job/ReportSendJobs/ReportDiagnosisDataJob.cs
  82. 27 0
      src/VitalMixtureService/DBService/Job/ReportSendJobs/ReportSendJobBase.cs
  83. 58 0
      src/VitalMixtureService/DBService/Job/StatisticJobs/CompletionRecordStatisticJob.cs
  84. 131 0
      src/VitalMixtureService/DBService/Job/StatisticJobs/HomeStatisticJob.cs
  85. 67 0
      src/VitalMixtureService/DBService/Job/StatisticJobs/KeyPopulationStatisticJob.cs
  86. 47 0
      src/VitalMixtureService/DBService/Job/StatisticJobs/ServiceRateAged65Job.cs
  87. 54 0
      src/VitalMixtureService/DBService/Job/StatisticJobs/StatisticJobBase.cs
  88. 41 0
      src/VitalMixtureService/DBService/Job/ThirdLevelSoftwareJobs/PasswordExpiredJob.cs
  89. 24 0
      src/VitalMixtureService/DBService/Job/ThirdLevelSoftwareJobs/ThirdLevelSoftwareJobBase.cs
  90. 35 0
      src/VitalMixtureService/DBService/QueryAction/CompletionRecordQueryAction.cs
  91. 47 0
      src/VitalMixtureService/DBService/QueryAction/ContractRecordQueryAction.cs
  92. 27 0
      src/VitalMixtureService/DBService/QueryAction/ContractTemplateQueryAction.cs
  93. 31 0
      src/VitalMixtureService/DBService/QueryAction/DeviceQueryAction.cs
  94. 33 0
      src/VitalMixtureService/DBService/QueryAction/DiagnosisQueryAction.cs
  95. 30 0
      src/VitalMixtureService/DBService/QueryAction/DictionaryQueryAction.cs
  96. 30 0
      src/VitalMixtureService/DBService/QueryAction/DynamicTypeQueryAction.cs
  97. 39 0
      src/VitalMixtureService/DBService/QueryAction/ExamQueryAction.cs
  98. 39 0
      src/VitalMixtureService/DBService/QueryAction/FollowUpQueryAction.cs
  99. 10 0
      src/VitalMixtureService/DBService/QueryAction/IQueryAction.cs
  100. 27 0
      src/VitalMixtureService/DBService/QueryAction/OrganizationQueryAction.cs

+ 49 - 0
src/VitalMixtureService/Common/AnalyzeJsonData.cs

@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using Newtonsoft.Json.Linq;
+
+namespace VitalService.Common
+{
+    public class AnalyzeJsonData : IAnalyzeData
+    {
+        private JObject _jObject;
+        public AnalyzeJsonData(string jsonData)
+        {
+            _jObject = JObject.Parse(jsonData);
+        }
+
+        /// <summary>
+        /// 获取值
+        /// </summary>
+        /// <param name="key">字典key</param>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <returns></returns>
+        public T GetValue<T>(string key)
+        {
+            if(_jObject.ContainsKey(key))
+            {
+                _jObject.TryGetValue(key, out JToken jToken);
+                return jToken.Value<T>();
+            }
+            return default;
+        }
+
+        /// <summary>
+        /// 获取数组值
+        /// </summary>
+        /// <param name="key">字典key</param>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <returns></returns>
+        public IEnumerable<T> GetArrayValue<T>(string key)
+        {
+            if(_jObject.ContainsKey(key))
+            {
+                _jObject.TryGetValue(key, out JToken jToken);
+                if(jToken.HasValues)
+                {
+                    return jToken.Values<T>();
+                }
+            }
+            return new T[0];
+        }
+    }
+}

+ 167 - 0
src/VitalMixtureService/Common/AnalyzeStrategy.cs

@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace VitalService.Common
+{
+    public class AnalyzeStrategy
+    {
+        private AnalyzeStrategy() { }
+        public static Func<byte[], Task<string>>? StorageHandler { get; set; }
+        public static async Task<string> GetAnalyzeResult(string data, AnalyzeConfig analyzeConfig)
+        {
+            IAnalyzeData analyze = null;
+            if (!string.IsNullOrWhiteSpace(data) && analyzeConfig != null && analyzeConfig.Mode.ToUpper() == "XML")
+            {
+                analyze = new AnalyzeXmlData(data);
+            }
+            else
+            {
+                analyze = new AnalyzeJsonData(data);
+            }
+            if (analyze != null)
+            {
+                var paramsBuilder = new StringBuilder();
+                var resultJsonBuilder = new StringBuilder(analyzeConfig.Template);
+                foreach (var item in analyzeConfig.AnalyzeConfigItems)
+                {
+                    string name = item["Name"];
+                    string path = item["Path"];
+                    string type = item["Type"];
+                    string value = string.Empty;
+                    string jsonStr = string.Empty;
+                    switch (type)
+                    {
+                        case "string":
+                            value = analyze.GetValue<string>(path);
+                            jsonStr = $"\"{name}\":\"{value}\"";
+                            break;
+                        case "image":
+                            value = analyze.GetValue<string>(path);
+                            if(!string.IsNullOrWhiteSpace(value))
+                            {
+                                var imageBytes = await GetImageBytes(value);
+                                string base64String = Convert.ToBase64String(imageBytes);
+                                jsonStr = $"\"{name}\":\"{base64String}\"";
+                            }
+                            break;
+                        case "txt":
+                            value = analyze.GetValue<string>(path);
+                            if(!string.IsNullOrWhiteSpace(value))
+                            {
+                                var txtContent = await GetTxtContent(value);
+                                jsonStr = $"\"{name}\":\"{txtContent}\"";
+                            }
+                            break;
+                        case "int":
+                            value = analyze.GetValue<int>(path).ToString();
+                            jsonStr = $"\"{name}\":{value}";
+                            break;
+                        case "double":
+                            value = analyze.GetValue<double>(path).ToString("0.00");
+                            jsonStr = $"\"{name}\":\"{value}\"";
+                            break;
+                        case "base64Image":
+                            if(StorageHandler!=null)
+                            {
+                                value = analyze.GetValue<string>(path);
+                                if(!string.IsNullOrWhiteSpace(value))
+                                {
+                                    var base64Bytes = Convert.FromBase64String(value);
+                                    var url = await StorageHandler(base64Bytes);
+                                    jsonStr = $"\"{name}\":\"{url}\"";
+                                }
+                            }
+                            break;
+                        case "txtData":
+                            if(StorageHandler!=null)
+                            {
+                                value = analyze.GetValue<string>(path);
+                                if(!string.IsNullOrWhiteSpace(value))
+                                {
+                                    var bytes = Encoding.UTF8.GetBytes(value);
+                                    var url = await StorageHandler(bytes);
+                                    jsonStr = $"\"{name}\":\"{url}\"";
+                                }
+                            }
+                            break;
+                        default:
+                            break;
+                    }
+                    paramsBuilder.Append(jsonStr+",");
+                    foreach(var key in item.Keys)
+                    {
+                        resultJsonBuilder.Replace("{{" + key + "}}", item[key].ToString());
+                    }
+                }
+                return resultJsonBuilder.ToString().Replace("{{data}}", paramsBuilder.ToString().TrimEnd(','));
+            }
+            return string.Empty;
+        }
+
+        private static async Task<byte[]> GetImageBytes(string imageUrl)
+        {
+            if(!imageUrl.StartsWith("http") && !imageUrl.StartsWith("https"))
+            {
+                return Array.Empty<byte>();
+            }
+            using var httpClient = new HttpClient();
+            return await httpClient.GetByteArrayAsync(imageUrl);
+        }
+
+        private static async Task<string> GetTxtContent(string txtUrl)
+        {
+            if(!txtUrl.StartsWith("http") && !txtUrl.StartsWith("https"))
+            {
+                return string.Empty;
+            }
+            using var httpClient = new HttpClient();
+            return await httpClient.GetStringAsync(txtUrl);
+        }
+    }
+
+    public class AnalyzeConfig
+    {
+        /// <summary>
+        /// 输入的字段
+        /// </summary>
+        /// <value></value>
+        public string InField { get; set; }
+
+        /// <summary>
+        /// 输出的字段
+        /// </summary>
+        /// <value></value>
+        public string OutField  { get; set; }
+
+        /// <summary>
+        /// 解析方式
+        /// </summary>
+        /// <value></value>
+        public string Mode { get; set; }
+
+        /// <summary>
+        /// 模版
+        /// </summary>
+        /// <value></value>
+        public string Template { get; set; }
+
+        /// <summary>
+        /// 解析配置
+        /// </summary>
+        /// <value></value>
+        public List<AnalyzeConfigItem> AnalyzeConfigItems { get; set; }
+    }
+
+    public class AnalyzeConfigItem : Dictionary<string, string>
+    {
+    }
+
+    public interface IAnalyzeData
+    {
+        T GetValue<T>(string key);
+        IEnumerable<T> GetArrayValue<T>(string key);
+    }
+}

+ 46 - 0
src/VitalMixtureService/Common/AnalyzeXmlData.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+namespace VitalService.Common
+{
+    public class AnalyzeXmlData : IAnalyzeData
+    {
+        private XmlDocument _xmlDocument;
+
+        public AnalyzeXmlData(string xmlData)
+        {
+            _xmlDocument = new XmlDocument();
+            _xmlDocument.LoadXml(xmlData);
+        }
+
+        /// <summary>
+        /// 获取值
+        /// </summary>
+        /// <param name="xpath">XPath表达式</param>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <returns></returns>
+        public T GetValue<T>(string xpath)
+        {
+            XmlNode node = _xmlDocument.SelectSingleNode(xpath);
+            if (node != null)
+            {
+                return (T)Convert.ChangeType(node.InnerText, typeof(T));
+            }
+            return default(T);
+        }
+
+        /// <summary>
+        /// 获取节点列表
+        /// </summary>
+        /// <param name="xpath">XPath表达式</param>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <returns></returns>
+        public IEnumerable<T> GetArrayValue<T>(string xpath)
+        {
+            XmlNodeList nodeList = _xmlDocument.SelectNodes(xpath);
+            return nodeList.Cast<XmlNode>().Select(node => (T)Convert.ChangeType(node.InnerText, typeof(T)));
+        }
+    }
+}

+ 27 - 0
src/VitalMixtureService/Common/AssemblyLoader.cs

@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace VitalService.Common
+{
+    public class AssemblyLoader
+    {        
+        /// <summary>
+        /// 加载依赖项
+        /// </summary>
+        /// <param name="assemblyPath">程序集</param>
+        /// <returns></returns>
+        public static Assembly LoadAssemblyDependencies(string assemblyPath, string assemblySymbolsPath=null)
+        {                
+            var file = File.OpenRead(assemblyPath);
+            if(!string.IsNullOrWhiteSpace(assemblySymbolsPath))
+            {
+                var symbolsFile = File.OpenRead(assemblySymbolsPath);
+                return AssemblyLoadContext.Default.LoadFromStream(file, symbolsFile);
+            }
+            else
+            {
+                return AssemblyLoadContext.Default.LoadFromStream(file);
+            }
+        }                       
+    }
+}

+ 17 - 0
src/VitalMixtureService/Common/CacheCreator.cs

@@ -0,0 +1,17 @@
+using System.Collections.Concurrent;
+
+namespace VitalService.Common
+{
+    public class CacheCreator
+    {
+        private CacheCreator() { }
+        private static ConcurrentDictionary<string, ICache> _cacheDictionary = new();
+        public static ICache GetCache<T>() where T:ICache
+        {
+            return _cacheDictionary.GetOrAdd(typeof(T).Name, (key) =>
+            {
+                return (ICache)Activator.CreateInstance(typeof(T));
+            });
+        }
+    }
+}

+ 572 - 0
src/VitalMixtureService/Common/CronHelper.cs

@@ -0,0 +1,572 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace VitalService.Common
+{
+    public class CronHelper
+    {
+        /// <summary>
+        /// Cron表达式转换(自定义开始时间)
+        /// </summary>
+        /// <param name="cron">表达式</param>
+        /// <param name="now">开始时间</param>
+        /// <returns>下次执行的时间</returns>
+        public static DateTime CronToNextDateTime(string cron, DateTime now)
+        {
+            var times = CronToDateTime(cron, now);
+            if (times != null && times.Any())
+            {
+                return times.FirstOrDefault();
+            }
+            return default;
+        }
+
+        /// <summary>
+        /// Cron表达式转换(自定义开始时间)
+        /// </summary>
+        /// <param name="cron">表达式</param>
+        /// <param name="now">开始时间</param>
+        /// <returns>最近5次要执行的时间</returns>
+        public static List<DateTime> CronToDateTime(string cron, DateTime now)
+        {
+            try
+            {
+                List<DateTime> lits = new List<DateTime>();
+                Cron c = new Cron();
+                string[] arr = cron.Split(' ');
+                Seconds(c, arr[0]);
+                Minutes(c, arr[1]);
+                Hours(c, arr[2]);
+                Month(c, arr[4]);
+                if (arr.Length < 7)
+                {
+                    Year(c, null);
+                }
+                else
+                {
+                    Year(c, arr[6]);
+                }
+                int addtime = 1;
+                while (true)
+                {
+                    if (c.Seconds[now.Second] == 1 && c.Minutes[now.Minute] == 1 && c.Hours[now.Hour] == 1 && c.Month[now.Month - 1] == 1 && c.Year[now.Year - 2019] == 1)
+                    {
+                        if (arr[3] != "?")
+                        {
+                            Days(c, arr[3], DateTime.DaysInMonth(now.Year, now.Month), now);
+                            int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
+                            if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
+                            {
+                                lits.Add(now);
+                            }
+                        }
+                        else
+                        {
+                            Weeks(c, arr[5], DateTime.DaysInMonth(now.Year, now.Month), now);
+                            int DayOfWeek = (((int)now.DayOfWeek) + 6) % 7;
+                            if (c.Days[now.Day - 1] == 1 && c.Weeks[DayOfWeek] == 1)
+                            {
+                                lits.Add(now);
+                            }
+                        }
+                    }
+                    if (lits.Count >= 5)
+                    {
+                        break;
+                    }
+                    c.Init();
+                    if (!arr[1].Contains('-') && !arr[1].Contains(',') && !arr[1].Contains('*') && !arr[1].Contains('/'))
+                    {
+                        if (now.Minute == int.Parse(arr[1]))
+                        {
+                            addtime = 3600;
+                        }
+                    }
+                    else if (arr[0] == "0" && now.Second == 0)
+                    {
+                        addtime = 60;
+                    }
+                    now = now.AddSeconds(addtime);
+                }
+                return lits;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+
+        #region 初始化Cron对象
+        /// <summary>
+        /// 指定秒位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">秒位</param>
+        private static void Seconds(Cron c, string str)
+        {
+            if (str == "*")
+            {
+                for (int i = 0; i < 60; i++)
+                {
+                    c.Seconds[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Seconds[i] = 1;
+                }
+            }
+            else if (str.Contains('/'))
+            {
+                int begin = int.Parse(str.Split('/')[0]);
+                int interval = int.Parse(str.Split('/')[1]);
+                while (true)
+                {
+                    c.Seconds[begin] = 1;
+                    if ((begin + interval) >= 60)
+                        break;
+                    begin += interval;
+                }
+            }
+            else if (str.Contains(','))
+            {
+
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Seconds[int.Parse(str.Split(',')[i])] = 1;
+                }
+            }
+            else
+            {
+                c.Seconds[int.Parse(str)] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定分位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">分位</param>
+        private static void Minutes(Cron c, string str)
+        {
+            if (str == "*")
+            {
+                for (int i = 0; i < 60; i++)
+                {
+                    c.Minutes[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Minutes[i] = 1;
+                }
+            }
+            else if (str.Contains('/'))
+            {
+                int begin = int.Parse(str.Split('/')[0]);
+                int interval = int.Parse(str.Split('/')[1]);
+                while (true)
+                {
+                    c.Minutes[begin] = 1;
+                    if ((begin + interval) >= 60)
+                        break;
+                    begin += interval;
+                }
+            }
+            else if (str.Contains(','))
+            {
+
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Minutes[int.Parse(str.Split(',')[i])] = 1;
+                }
+            }
+            else
+            {
+                c.Minutes[int.Parse(str)] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定小时位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">小时位</param>
+        private static void Hours(Cron c, string str)
+        {
+            if (str == "*")
+            {
+                for (int i = 0; i < 24; i++)
+                {
+                    c.Hours[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Hours[i] = 1;
+                }
+            }
+            else if (str.Contains('/'))
+            {
+                int begin = int.Parse(str.Split('/')[0]);
+                int interval = int.Parse(str.Split('/')[1]);
+                while (true)
+                {
+                    c.Hours[begin] = 1;
+                    if ((begin + interval) >= 24)
+                        break;
+                    begin += interval;
+                }
+            }
+            else if (str.Contains(','))
+            {
+
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Hours[int.Parse(str.Split(',')[i])] = 1;
+                }
+            }
+            else
+            {
+                c.Hours[int.Parse(str)] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定月位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">月位</param>
+        private static void Month(Cron c, string str)
+        {
+            if (str == "*")
+            {
+                for (int i = 0; i < 12; i++)
+                {
+                    c.Month[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Month[i - 1] = 1;
+                }
+            }
+            else if (str.Contains('/'))
+            {
+                int begin = int.Parse(str.Split('/')[0]);
+                int interval = int.Parse(str.Split('/')[1]);
+                while (true)
+                {
+                    c.Month[begin - 1] = 1;
+                    if ((begin + interval) >= 12)
+                        break;
+                    begin += interval;
+                }
+            }
+            else if (str.Contains(','))
+            {
+
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Month[int.Parse(str.Split(',')[i]) - 1] = 1;
+                }
+            }
+            else
+            {
+                c.Month[int.Parse(str) - 1] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定年位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">年位</param>
+        private static void Year(Cron c, string str)
+        {
+            if (str == null || str == "*")
+            {
+                for (int i = 0; i < 80; i++)
+                {
+                    c.Year[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin - 2019; i <= end - 2019; i++)
+                {
+                    c.Year[i] = 1;
+                }
+            }
+            else
+            {
+                c.Year[int.Parse(str) - 2019] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定天位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">天位</param>
+        private static void Days(Cron c, string str, int len, DateTime now)
+        {
+            for (int i = 0; i < 7; i++)
+            {
+                c.Weeks[i] = 1;
+            }
+            if (str == "*" || str == "?")
+            {
+                for (int i = 0; i < len; i++)
+                {
+                    c.Days[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Days[i - 1] = 1;
+                }
+            }
+            else if (str.Contains('/'))
+            {
+                int begin = int.Parse(str.Split('/')[0]);
+                int interval = int.Parse(str.Split('/')[1]);
+                while (true)
+                {
+                    c.Days[begin - 1] = 1;
+                    if ((begin + interval) >= len)
+                        break;
+                    begin += interval;
+                }
+            }
+            else if (str.Contains(','))
+            {
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Days[int.Parse(str.Split(',')[i]) - 1] = 1;
+                }
+            }
+            else if (str.Contains('L'))
+            {
+                int i = str.Replace("L", "") == "" ? 0 : int.Parse(str.Replace("L", ""));
+                c.Days[len - 1 - i] = 1;
+            }
+            else if (str.Contains('W'))
+            {
+                c.Days[len - 1] = 1;
+            }
+            else
+            {
+                c.Days[int.Parse(str) - 1] = 1;
+            }
+        }
+
+        /// <summary>
+        /// 指定星期位
+        /// </summary>
+        /// <param name="c">cron表达式</param>
+        /// <param name="str">星期位</param>
+        private static void Weeks(Cron c, string str, int len, DateTime now)
+        {
+            if (str == "*" || str == "?")
+            {
+                for (int i = 0; i < 7; i++)
+                {
+                    c.Weeks[i] = 1;
+                }
+            }
+            else if (str.Contains('-'))
+            {
+                int begin = int.Parse(str.Split('-')[0]);
+                int end = int.Parse(str.Split('-')[1]);
+                for (int i = begin; i <= end; i++)
+                {
+                    c.Weeks[i - 1] = 1;
+                }
+            }
+            else if (str.Contains(','))
+            {
+                for (int i = 0; i < str.Split(',').Length; i++)
+                {
+                    c.Weeks[int.Parse(str.Split(',')[i]) - 1] = 1;
+                }
+            }
+            else if (str.Contains('L'))
+            {
+                int i = str.Replace("L", "") == "" ? 0 : int.Parse(str.Replace("L", ""));
+                if (i == 0)
+                {
+                    c.Weeks[6] = 1;
+                }
+                else
+                {
+                    c.Weeks[i - 1] = 1;
+                    c.Days[GetLastWeek(i, now) - 1] = 1;
+                    return;
+                }
+            }
+            else if (str.Contains('#'))
+            {
+                int i = int.Parse(str.Split('#')[0]);
+                int j = int.Parse(str.Split('#')[1]);
+                c.Weeks[i - 1] = 1;
+                c.Days[GetWeek(i - 1, j, now)] = 1;
+                return;
+            }
+            else
+            {
+                c.Weeks[int.Parse(str) - 1] = 1;
+            }
+            //week中初始化day,则说明day没要求
+            for (int i = 0; i < len; i++)
+            {
+                c.Days[i] = 1;
+            }
+        }
+        #endregion
+
+        /// <summary>
+        /// 获取最后一个星期几的day
+        /// </summary>
+        /// <param name="i">星期几</param>
+        /// <param name="now">现在时间</param>
+        /// <returns></returns>
+        private static int GetLastWeek(int i, DateTime now)
+        {
+            DateTime d = now.AddDays(1 - now.Day).Date.AddMonths(1).AddSeconds(-1);
+            int DayOfWeek = ((((int)d.DayOfWeek) + 6) % 7) + 1;
+            int a = DayOfWeek >= i ? DayOfWeek - i : 7 + DayOfWeek - i;
+            return DateTime.DaysInMonth(now.Year, now.Month) - a;
+        }
+
+        /// <summary>
+        /// 获取当月第几个星期几的day
+        /// </summary>
+        /// <param name="i">星期几</param>
+        /// <param name="j">第几周</param>
+        /// <param name="now">现在时间</param>
+        /// <returns></returns>
+        private static int GetWeek(int i, int j, DateTime now)
+        {
+            int day = 0;
+            DateTime d = new DateTime(now.Year, now.Month, 1);
+            int DayOfWeek = ((((int)d.DayOfWeek) + 6) % 7) + 1;
+            if (i >= DayOfWeek)
+            {
+                day = (7 - DayOfWeek + 1) + 7 * (j - 2) + i;
+            }
+            else
+            {
+                day = (7 - DayOfWeek + 1) + 7 * (j - 1) + i;
+            }
+            return day;
+        }
+    }
+
+    public class Cron
+    {
+        /// <summary>
+        /// 秒位,表示1-60秒
+        /// </summary>
+        private int[] seconds = new int[60];
+        /// <summary>
+        /// 分位,表示1-60分
+        /// </summary>
+        private int[] minutes = new int[60];
+        /// <summary>
+        /// 小时位,表示1-12小时
+        /// </summary>
+        private int[] hours = new int[24];
+        /// <summary>
+        /// 天位,表示1-31天
+        /// </summary>
+        private int[] days = new int[31];
+        /// <summary>
+        /// 月位,表示1-12月
+        /// </summary>
+        private int[] month = new int[12];
+        /// <summary>
+        /// 星期位,表示星期1-星期天
+        /// </summary>
+        private int[] weeks = new int[7];
+        //年位,表示2019-2099年
+        private int[] year = new int[80];
+
+        public int[] Seconds { get => seconds; set => seconds = value; }
+        public int[] Minutes { get => minutes; set => minutes = value; }
+        public int[] Hours { get => hours; set => hours = value; }
+        public int[] Days { get => days; set => days = value; }
+        public int[] Month { get => month; set => month = value; }
+        public int[] Weeks { get => weeks; set => weeks = value; }
+        public int[] Year { get => year; set => year = value; }
+
+        public Cron()
+        {
+            for (int i = 0; i < 60; i++)
+            {
+                seconds[i] = 0;
+                minutes[i] = 0;
+            }
+            for (int i = 0; i < 24; i++)
+            {
+                hours[i] = 0;
+            }
+            for (int i = 0; i < 31; i++)
+            {
+                days[i] = 0;
+            }
+            for (int i = 0; i < 12; i++)
+            {
+                month[i] = 0;
+            }
+            for (int i = 0; i < 7; i++)
+            {
+                weeks[i] = 0;
+            }
+            for (int i = 0; i < 80; i++)
+            {
+                year[i] = 0;
+            }
+        }
+
+        /// <summary>
+        /// 初始化星期和天
+        /// </summary>
+        public void Init()
+        {
+            for (int i = 0; i < 7; i++)
+            {
+                weeks[i] = 0;
+            }
+            for (int i = 0; i < 31; i++)
+            {
+                days[i] = 0;
+            }
+        }
+    }
+}

+ 27 - 0
src/VitalMixtureService/Common/DBRepositoryFactory.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace VitalService.Common
+{
+    public class DBRepositoryFactory
+    {
+        private DBRepositoryFactory() { }
+        private static readonly Dictionary<string, object> _repositorys = new Dictionary<string, object>();
+        public static T GetRepository<T>() where T : new()
+        {
+            var repositoryName = typeof(T).Name;
+            if(_repositorys.Keys.Contains(repositoryName))
+            {
+                _repositorys.TryGetValue(repositoryName, out var repository);
+                return (T)repository;
+            }
+            else
+            {
+                var repository = new T();
+                _repositorys.TryAdd(repositoryName, repository);
+                return repository;
+            }
+        }
+    }
+}

+ 203 - 0
src/VitalMixtureService/Common/Encrypt/Base64EncryptHelper.cs

@@ -0,0 +1,203 @@
+using System;
+using System.Collections;
+using System.Text;
+using System.Text.RegularExpressions;
+using WingServerCommon.Log;
+
+namespace VitalService.Common
+{
+    /// <summary>
+    /// Base64 加密、解密
+    /// <para>主要方法如下:</para>
+    /// <para>01. Encrypt(string text)  //加密字符串</para>
+    /// <para>02. Decrypt(string text)  //解密字符串</para>
+    /// 6Bit数字【0~63】映射Base64字符表如下,补位我们使用=等号代替,按(64,'=')处理
+    /// </summary>
+    public class Base64EncryptHelper : IEncrypt
+    {
+        public string EncryptModeName => "BASE64";
+
+        public string Encrypt(string text)
+        {
+            var result = "";
+            for (int i = 0; i < text.Length; i++)
+            {
+                result += EncryptLocal(text[i].ToString());
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Base64加密
+        /// </summary>
+        /// <param name="text">待加密的字符串</param>
+        /// <returns>加密后字符串</returns>
+        private string EncryptLocal(string text)
+        {
+            //如果字符串为空,则返回
+            if (string.IsNullOrEmpty(text))
+            {
+                return "";
+            }
+
+            try
+            {
+                char[] Base64Code = new char[]{'0','1','2','3','4','5','6','7',
+                                            '8','9','+','/','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
+                                            'o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
+                                            'U','V','W','X','Y','Z','='};
+                byte empty = (byte)0;
+                ArrayList byteMessage = new ArrayList(Encoding.UTF8.GetBytes(text));
+                StringBuilder outmessage;
+                int messageLen = byteMessage.Count;
+                int page = messageLen / 3;
+                int use = 0;
+                if ((use = messageLen % 3) > 0)
+                {
+                    for (int i = 0; i < 3 - use; i++)
+                        byteMessage.Add(empty);
+                    page++;
+                }
+                outmessage = new System.Text.StringBuilder(page * 4);
+                for (int i = 0; i < page; i++)
+                {
+                    byte[] instr = new byte[3];
+                    instr[0] = (byte)byteMessage[i * 3];
+                    instr[1] = (byte)byteMessage[i * 3 + 1];
+                    instr[2] = (byte)byteMessage[i * 3 + 2];
+                    int[] outstr = new int[4];
+                    outstr[0] = instr[0] >> 2;
+                    outstr[1] = ((instr[0] & 0x03) << 4) ^ (instr[1] >> 4);
+                    if (!instr[1].Equals(empty))
+                        outstr[2] = ((instr[1] & 0x0f) << 2) ^ (instr[2] >> 6);
+                    else
+                        outstr[2] = 64;
+                    if (!instr[2].Equals(empty))
+                        outstr[3] = (instr[2] & 0x3f);
+                    else
+                        outstr[3] = 64;
+                    outmessage.Append(Base64Code[outstr[0]]);
+                    outmessage.Append(Base64Code[outstr[1]]);
+                    outmessage.Append(Base64Code[outstr[2]]);
+                    outmessage.Append(Base64Code[outstr[3]]);
+                }
+                var result = outmessage.ToString();
+                return result;
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+
+
+
+        /// <summary>
+        /// Base64解密
+        /// </summary>
+        /// <param name="encryptedData">待解密的字符串</param>
+        /// <returns>解密后的字符串</returns>
+        public string Decrypt(string encryptedData)
+        {
+            //如果字符串为空,则返回
+            if (string.IsNullOrEmpty(encryptedData))
+            {
+                return "";
+            }
+
+            //将空格替换为加号
+            encryptedData = encryptedData.Replace(" ", "+");
+
+            try
+            {
+                if ((encryptedData.Length % 4) != 0)
+                {
+                    Logger.WriteLineWarn($"包含不正确的BASE64编码:" + encryptedData);
+                    return "";
+                }
+                if (!Regex.IsMatch(encryptedData, "^[A-Z0-9/+=]*$", RegexOptions.IgnoreCase))
+                {
+
+                    Logger.WriteLineWarn($"包含不正确的BASE64编码:" + encryptedData);
+                    return "";
+                }
+                string Base64Code = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ=";
+                int page = encryptedData.Length / 4;
+                ArrayList outMessage = new ArrayList(page * 3);
+                char[] message = encryptedData.ToCharArray();
+                for (int i = 0; i < page; i++)
+                {
+                    byte[] instr = new byte[4];
+                    instr[0] = (byte)Base64Code.IndexOf(message[i * 4]);
+                    instr[1] = (byte)Base64Code.IndexOf(message[i * 4 + 1]);
+                    instr[2] = (byte)Base64Code.IndexOf(message[i * 4 + 2]);
+                    instr[3] = (byte)Base64Code.IndexOf(message[i * 4 + 3]);
+                    byte[] outstr = new byte[3];
+                    outstr[0] = (byte)((instr[0] << 2) ^ ((instr[1] & 0x30) >> 4));
+                    if (instr[2] != 64)
+                    {
+                        outstr[1] = (byte)((instr[1] << 4) ^ ((instr[2] & 0x3c) >> 2));
+                    }
+                    else
+                    {
+                        outstr[2] = 0;
+                    }
+                    if (instr[3] != 64)
+                    {
+                        outstr[2] = (byte)((instr[2] << 6) ^ instr[3]);
+                    }
+                    else
+                    {
+                        outstr[2] = 0;
+                    }
+                    outMessage.Add(outstr[0]);
+                    if (outstr[1] != 0)
+                        outMessage.Add(outstr[1]);
+                    if (outstr[2] != 0)
+                        outMessage.Add(outstr[2]);
+                }
+                byte[] outbyte = (byte[])outMessage.ToArray(Type.GetType("System.Byte"));
+                var result = Encoding.UTF8.GetString(outbyte);
+                if (!IsNotErrorCode(result))
+                {
+                    Logger.WriteLineWarn($"包含不正确的BASE64编码:" + encryptedData);
+                    return "";
+                }
+                return result;
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// 是否正常字符串不含乱码
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        private bool IsNotErrorCode(string str)
+        {
+            char[] ch = str.ToCharArray();
+            for (int i = 0; i < ch.Length; ++i)
+            {
+                 //乱码
+                 if(ch[i]<7||(ch[i]>13&&ch[i]<26)||(ch[i]>27&&ch[i]<32)||ch[i]>65532)
+                 {
+                    return false;
+                 }
+            }
+            return true;
+        }
+
+        public string Encrypt(string text, string key)
+        {
+            return Encrypt(text);
+        }
+
+        public string Decrypt(string encryptedData, string key)
+        {
+            return Decrypt(encryptedData);
+        }
+    }
+}

+ 74 - 0
src/VitalMixtureService/Common/Encrypt/DBEncryptHelper.cs

@@ -0,0 +1,74 @@
+using WingServerCommon.Config;
+using WingServerCommon.Config.Parameters;
+
+namespace VitalService.Common
+{
+    /// <summary>
+    /// 数据库加密
+    /// </summary>
+    public class DBEncryptHelper : IEncrypt
+    {
+        private IEncrypt _dbEncryptHelper = EncryptStrategy.GetEncryptStrategy("BASE64", EnvironmentConfigManager.GetParammeter<BoolParameter>("Encrypt", "DBEncrypt").Value);
+        public string EncryptModeName => "DBEncrypt";
+
+        /// <summary>
+        /// DB公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message)
+        {
+            if(!message.StartsWith("DBEncrypt_"))
+            {
+                return "DBEncrypt_" + _dbEncryptHelper.Encrypt(message);
+            }
+            return message;
+        }
+
+        /// <summary>
+        /// DB私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message)
+        {
+            if(message.StartsWith("DBEncrypt_"))
+            {
+                return _dbEncryptHelper.Decrypt(message.Replace("DBEncrypt_", ""));
+            }
+            return message;
+        }
+
+        /// <summary>
+        /// DB公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message, string key)
+        {
+            if(!message.StartsWith("DBEncrypt_"))
+            {
+                return "DBEncrypt_" + _dbEncryptHelper.Encrypt(message, key);
+            }
+            return message;
+        }
+
+        /// <summary>
+        /// DB私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message, string key)
+        {
+            if(message.StartsWith("DBEncrypt_"))
+            {
+                return _dbEncryptHelper.Decrypt(message.Replace("DBEncrypt_", ""),key);
+            }
+            return message;
+        }
+    }
+}

+ 171 - 0
src/VitalMixtureService/Common/Encrypt/DESHelper.cs

@@ -0,0 +1,171 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using JsonRpcLite.Log;
+
+namespace VitalService.Common
+{
+    public class DESHelper : IEncrypt
+    {
+        public string EncryptModeName => "DES";
+        private string _encryptKey = "V1NN0KEY";
+        private readonly byte[] Iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+
+        public DESHelper(string encryptKey = "V1NN0KEY")
+        {
+            _encryptKey = encryptKey;
+        }
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public string Encrypt(string encryptString)
+        {
+            try
+            {
+                //将字符转换为UTF - 8编码的字节序列
+                byte[] rgbKey = Encoding.UTF8.GetBytes(_encryptKey.Substring(0, 8));
+                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
+                //用指定的密钥和初始化向量创建CBC模式的DES加密标准
+                using (var dCSP = DES.Create())
+                {
+                    dCSP.Mode = CipherMode.CBC;
+                    dCSP.Padding = PaddingMode.PKCS7;
+                    using (MemoryStream mStream = new MemoryStream())
+                    {
+                        using (CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, Iv), CryptoStreamMode.Write))
+                        {
+                            cStream.Write(inputByteArray, 0, inputByteArray.Length);//写入内存流
+                            cStream.FlushFinalBlock();//将缓冲区中的数据写入内存流,并清除缓冲区
+                            return Convert.ToHexString(mStream.ToArray()); //将内存流转写入字节数组并转换为string字符
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"DESHelper Encrypt error {ex}");
+                return encryptString;
+            }
+        }
+
+        /// <summary>
+        /// 解密
+        /// </summary>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public string Decrypt(string decryptString)
+        {
+            try
+            {
+                //将字符转换为UTF - 8编码的字节序列
+                byte[] rgbKey = Encoding.UTF8.GetBytes(_encryptKey.Substring(0, 8));
+                var rgbKeyStr = Convert.ToHexString(rgbKey);
+                //Console.WriteLine($"rgbKey:{rgbKeyStr},Iv:{ivStr}");
+                byte[] inputByteArray = Convert.FromHexString(decryptString);
+                //用指定的密钥和初始化向量使用CBC模式的DES解密标准解密
+                using (var dCSP = DES.Create())
+                {
+                    dCSP.Mode = CipherMode.CBC;
+                    dCSP.Padding = PaddingMode.PKCS7;
+                    var decryptor = dCSP.CreateDecryptor(rgbKey, Iv);
+                    using (MemoryStream mStream = new MemoryStream())
+                    {
+                        using (CryptoStream cStream = new CryptoStream(mStream, decryptor, CryptoStreamMode.Write))
+                        {
+                            cStream.Write(inputByteArray, 0, inputByteArray.Length);
+                            cStream.FlushFinalBlock();
+                            var latinStr = Encoding.UTF8.GetString(mStream.ToArray());
+                            return System.Web.HttpUtility.UrlDecode(latinStr);
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"DESHelper Decrypt error {ex}");
+                return decryptString;
+            }
+        }
+        
+        /// <summary>
+        /// DES加密字符串
+        /// </summary>
+        /// <param name="encryptString">待加密的字符串</param>
+        /// <param name="encryptKey">加密密钥,要求为8位</param>
+        /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
+        public string Encrypt(string encryptString, string encryptKey)
+        {
+            try
+            {
+                //将字符转换为UTF - 8编码的字节序列
+                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
+                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
+                //用指定的密钥和初始化向量创建CBC模式的DES加密标准
+                using (var dCSP = DES.Create())
+                {
+                    dCSP.Mode = CipherMode.CBC;
+                    dCSP.Padding = PaddingMode.PKCS7;
+                    using (MemoryStream mStream = new MemoryStream())
+                    {
+                        using (CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, Iv), CryptoStreamMode.Write))
+                        {
+                            cStream.Write(inputByteArray, 0, inputByteArray.Length);//写入内存流
+                            cStream.FlushFinalBlock();//将缓冲区中的数据写入内存流,并清除缓冲区
+                            return Convert.ToHexString(mStream.ToArray()); //将内存流转写入字节数组并转换为string字符
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"DESHelper Encrypt error {ex}");
+                return encryptString;
+            }
+        }
+
+        /// <summary>
+        /// DES解密字符串
+        /// </summary>
+        /// <param name="decryptString">待解密的字符串</param>
+        /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
+        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
+        public string Decrypt(string decryptString, string decryptKey)
+        {
+            try
+            {
+                //将字符转换为UTF - 8编码的字节序列
+                byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
+                var rgbKeyStr = Convert.ToHexString(rgbKey);
+                //Console.WriteLine($"rgbKey:{rgbKeyStr},Iv:{ivStr}");
+                byte[] inputByteArray = Convert.FromHexString(decryptString);
+                //用指定的密钥和初始化向量使用CBC模式的DES解密标准解密
+                using (var dCSP = DES.Create())
+                {
+                    dCSP.Mode = CipherMode.CBC;
+                    dCSP.Padding = PaddingMode.PKCS7;
+                    var decryptor = dCSP.CreateDecryptor(rgbKey, Iv);
+                    using (MemoryStream mStream = new MemoryStream())
+                    {
+                        using (CryptoStream cStream = new CryptoStream(mStream, decryptor, CryptoStreamMode.Write))
+                        {
+                            cStream.Write(inputByteArray, 0, inputByteArray.Length);
+                            cStream.FlushFinalBlock();
+                            var latinStr = Encoding.UTF8.GetString(mStream.ToArray());
+                            return System.Web.HttpUtility.UrlDecode(latinStr);
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"DESHelper Decrypt error {ex}");
+                return decryptString;
+            }
+        }
+    }
+}

+ 49 - 0
src/VitalMixtureService/Common/Encrypt/EmptyEncrypt.cs

@@ -0,0 +1,49 @@
+namespace VitalService.Common
+{
+    /// <summary>
+    /// 不加密实现
+    /// </summary>
+    public class EmptyEncrypt : IEncrypt
+    {
+        public string EncryptModeName => "EMPTY";
+        /// <summary>
+        /// 使用公钥加密数据
+        /// </summary>
+        /// <param name="text">待加密文本</param>
+        /// <returns></returns>
+        public string Encrypt(string text)
+        {
+            return text;
+        }
+
+        /// <summary>
+        /// 使用私钥解密数据
+        /// </summary>
+        /// <param name="encryptedData">加密字符串</param>
+        /// <returns></returns>
+        public string Decrypt(string encryptedData)
+        {
+            return encryptedData;
+        }
+
+        /// <summary>
+        /// 使用公钥加密数据
+        /// </summary>
+        /// <param name="text">待加密文本</param>
+        /// <returns></returns>
+        public string Encrypt(string text, string key)
+        {
+            return text;
+        }
+
+        /// <summary>
+        /// 使用私钥解密数据
+        /// </summary>
+        /// <param name="encryptedData">加密字符串</param>
+        /// <returns></returns>
+        public string Decrypt(string encryptedData, string key)
+        {
+            return encryptedData;
+        }
+    }
+}

+ 78 - 0
src/VitalMixtureService/Common/Encrypt/EncryptStrategy.cs

@@ -0,0 +1,78 @@
+using WingServerCommon.Config;
+using WingServerCommon.Config.Parameters;
+
+namespace VitalService.Common
+{
+    public interface IEncrypt
+    {
+        string EncryptModeName { get; }
+        string Encrypt(string text);
+        string Encrypt(string text, string key);
+        string Decrypt(string encryptedData);
+        string Decrypt(string encryptedData, string key);
+    }
+
+    public class EncryptStrategy
+    {
+        private EncryptStrategy() {}
+        public static IEncrypt GetEncryptStrategy(string encryptMode, bool enableEncrypt)
+        {
+            string _encryptModeEncrypt = encryptMode;
+            bool _enableEncrypt = enableEncrypt;
+            if(_enableEncrypt)
+            {
+                if (_encryptModeEncrypt == "SM2")
+                {
+                    string _SM2PublicKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "SM2PublicKey").Value;
+                    string _SM2PrivateKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "SM2PrivateKey").Value;
+                    return new SM2Helper(_SM2PublicKey, _SM2PrivateKey);
+                }
+                else if(_encryptModeEncrypt == "RSA")
+                {
+                    string _RSAPublicKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "RSAPublicKey").Value;
+                    string _RSAPrivateKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "RSAPrivateKey").Value;
+                    return  new RSAHelper(_RSAPublicKey, _RSAPrivateKey);
+                }
+                else if(_encryptModeEncrypt == "DES")
+                {
+                    string desEncryptKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "DESEncryptKey").Value;
+                    return  new DESHelper(desEncryptKey);
+                }
+                else if(_encryptModeEncrypt == "SM4")
+                {
+                    string desEncryptKey = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "SM4EncryptKey").Value;
+                    return  new SM4Helper(desEncryptKey);
+                }
+                else if(_encryptModeEncrypt == "BASE64")
+                {
+                    return  new Base64EncryptHelper();
+                }
+            }
+            return new EmptyEncrypt();
+        }
+    }
+
+    public class RequestEncryptStrategy
+    {
+        public static IEncrypt Instance { get; set; }
+        private RequestEncryptStrategy(){}
+        static RequestEncryptStrategy()
+        {
+            string _encryptModeEncrypt = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "RequestEncryptMode").Value;
+            bool _enableEncrypt = EnvironmentConfigManager.GetParammeter<BoolParameter>("Encrypt", "RequestEncrypt").Value;
+            Instance = EncryptStrategy.GetEncryptStrategy(_encryptModeEncrypt, _enableEncrypt);
+        }
+    }
+
+    public class ResponseEncryptStrategy
+    {
+        public static IEncrypt Instance { get; set; }
+        private ResponseEncryptStrategy(){}
+        static ResponseEncryptStrategy()
+        {
+            string _encryptModeEncrypt = EnvironmentConfigManager.GetParammeter<StringParameter>("Encrypt", "ResponseEncryptMode").Value;
+            bool _enableEncrypt = EnvironmentConfigManager.GetParammeter<BoolParameter>("Encrypt", "ResponseEncrypt").Value;
+            Instance = EncryptStrategy.GetEncryptStrategy(_encryptModeEncrypt, _enableEncrypt);
+        }
+    }
+}

+ 165 - 0
src/VitalMixtureService/Common/Encrypt/RSAHelper.cs

@@ -0,0 +1,165 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using JsonRpcLite.Log;
+
+namespace VitalService.Common
+{
+    /// <summary>
+    /// RSA加密
+    /// </summary>
+    public class RSAHelper : IEncrypt
+    {
+        public string EncryptModeName => "RSA";
+        private readonly RSA _rsa = RSA.Create(2048);
+
+        public RSAHelper(string publicKeyString, string privateKeyString)
+        {
+            //var publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAln7CnpiqYguFVRUL5oCdFAQL6ypYQdnd84XN++mRvjkdjtpbCdGEj6S2U2Vn+Bt+vHL5bvUk6gtTx5FpV0Z8kDvDgBRweIvtJTZLx6ZjbI7habxclW9aB3b0SW3zuFuHMteDivTI0lkZ6y0QRiG7nMZYsi18IjReBssXsx38fpgIBAHIbkb98wtEffBbrbwfdxQnfc8r9Hy7iIbfVP0h7nR0FDMu1vYqi5PsnYDw681iO6GNxV6VHA6wcWkMokLZn51OP+OQmomJPElWfPgLDp1AxBeRhuHFlXslcE550bzWUs3iBylTgXwdTGqppCjCXhSLBiOnTc0ggHpDQHh17wIDAQAB";
+            if(!string.IsNullOrWhiteSpace(publicKeyString))
+            {
+                RSAParameters publicKeyParams = ParsePemPublicKey(publicKeyString);
+                _rsa.ImportParameters(publicKeyParams);
+            }
+            //var privateKeyString = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCWfsKemKpiC4VVFQvmgJ0UBAvrKlhB2d3zhc376ZG+OR2O2lsJ0YSPpLZTZWf4G368cvlu9STqC1PHkWlXRnyQO8OAFHB4i+0lNkvHpmNsjuFpvFyVb1oHdvRJbfO4W4cy14OK9MjSWRnrLRBGIbucxliyLXwiNF4GyxezHfx+mAgEAchuRv3zC0R98FutvB93FCd9zyv0fLuIht9U/SHudHQUMy7W9iqLk+ydgPDrzWI7oY3FXpUcDrBxaQyiQtmfnU4/45CaiYk8SVZ8+AsOnUDEF5GG4cWVeyVwTnnRvNZSzeIHKVOBfB1MaqmkKMJeFIsGI6dNzSCAekNAeHXvAgMBAAECggEAHuUa8xAIOmR/FL5jWQiiNo+2Gqrwv2QIiou3g7Wpc9Gp3b+53MQkYJDB1VEGDQsn82vvBPZSg7Gbm2agp4gS3lFGiy6nADhJkNAasnvYAVs7r0c6Ant/kfS7pa9qzzgLA0b2/DnQWE5uYbc4lg0qxL57SujHiQYTH3XmAaFwSlR/CQxQMK7WsZ25mZ5ZYV7+SpzE8rJWDpVzKpreflP/AuxGnxpuhjVjtsQPW/fFvUkpIXnEYf7x6/mZI2j3E+pSzVIBwBi17LhbYYJ+1baI7DBrPm26rDYedHfk3MLbH5je2DVwcG7d6X09UqXJ02AfqWgToZ2LWHOUpMOin00HMQKBgQDFyTsQDtUXxuYfhj17659wP3wqbmi4oDt84w5AGwMGioYSNVGqF7vPGKyPht2TJ2vqYuAnIb4cNtfjiiLu0UtFpe8c00NBkMmzc+FnaSJHkMiC6NuorbtBoQe+4HMD9FZPmDRajoez71Tnb0OWTpC9lKbArX+uTLy3A6XDh8dsNQKBgQDCykIcZuwbhIpPo/B3kT3WWIeYTJG0k7Py8+cwze2F7bS8m2NozU9nR/s57K3pyqSNX8J4HHdV8VzpMpV9vNjaf8XhnqkZY/lMD+oxD9nmTHKH6lyUD77DYeRcxOmBT5r/HcRnz7c7eli0jZhlZeuu539tr82zjYJ7Xf/umP92EwKBgFjGgeQrRCpv9EqiDmbY06+mTy0ccZStFwZvQ64ycaE1/AegNw+Jp5rFEG87saijQSTrTIFD+/jeBPj0v8lB1+9jE3h0uvNq8Z3CnaG05tYIfneD3VRQ5oQGq1tZk0ZrHXKMdrNO1kpFWm6m2kdU7FKrrk09ktnBR9M9p+GjyDchAoGALjuZU2puUd20glCT650ygySCEnjiAG0qQdj4H5JQ9P/FbRqojqBkX0wracUuRhZN1ixLWPzQqjpeZg8WgkCHa9z116Yz1o3vBsmkOT7c5hdw+6d5j77o9TDP5eDq10FQtYqYKleX0usoELqm2DJHrTzO9vbKKPrGZIecDkKMJ7cCgYBF2nginlxJnu1mbqP+nwEMMHZgto9p8XX6IFbLAENnDqsjH17bK9rasSWtTiuf6KAEet1ObYqUcPaI4oj/IeYYmwylB1+zX/LykuMbFKGEykmpwXnvlUTFDdiG6+0gyPfGPlptLhpBS04sl7D6Sisx2eWnasBqrXH3CuzC7Kk5dw==";
+            if(!string.IsNullOrWhiteSpace(privateKeyString))
+            {
+                _rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKeyString), out _);
+            }
+        }
+
+        // 解析PEM格式的公钥
+        private RSAParameters ParsePemPublicKey(string pemPublicKeyString)
+        {
+            // 去除PEM格式的头部和尾部
+            string publicKeyBody = pemPublicKeyString
+                .Replace("-----BEGIN PUBLIC KEY-----", "")
+                .Replace("-----END PUBLIC KEY-----", "")
+                .Replace("\n", "");
+
+            // 将Base64编码的PEM格式公钥转换为字节数组
+            byte[] publicKeyBytes = Convert.FromBase64String(publicKeyBody);
+
+            // 创建RSA实例
+            using (RSA rsa = RSA.Create())
+            {
+                // 导入公钥数据
+                rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
+
+                // 获取公钥参数
+                RSAParameters publicKeyParams = rsa.ExportParameters(false);
+
+                return publicKeyParams;
+            }
+        }
+
+        /// <summary>
+        /// 使用公钥加密数据
+        /// </summary>
+        /// <param name="text">待加密文本</param>
+        /// <returns></returns>
+        public string Encrypt(string text)
+        {
+            try
+            {
+                // 将字符串转为对应byte[]
+                byte[] textBytes = Encoding.UTF8.GetBytes(text);
+                // 使用私钥解密数据
+                byte[] encryptedBytes = _rsa.Encrypt(textBytes, RSAEncryptionPadding.Pkcs1);
+                // 将解密后的字节数组转换为字符串
+                string encryptedData = Convert.ToBase64String(encryptedBytes);
+                return encryptedData;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"RSA encrypt error {ex}");
+                return text;
+            }
+        }
+
+        /// <summary>
+        /// 使用私钥解密数据
+        /// </summary>
+        /// <param name="encryptedData">加密字符串</param>
+        /// <returns></returns>
+        public string Decrypt(string encryptedData)
+        {
+            try
+            {
+                // 将Base64编码的加密数据解码为字节数组
+                byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
+                // 使用私钥解密数据
+                byte[] decryptedBytes = _rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1);
+                // 将解密后的字节数组转换为字符串
+                string decryptedData = Encoding.UTF8.GetString(decryptedBytes);
+                return decryptedData;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"RSA decrypt error {ex}");
+                return encryptedData;
+            }
+        }
+
+        /// <summary>
+        /// 使用公钥加密数据
+        /// </summary>
+        /// <param name="text">待加密文本</param>
+        /// <returns></returns>
+        public string Encrypt(string text, string key)
+        {
+            try
+            {
+                using RSA rsa = RSA.Create(2048);
+                if(!string.IsNullOrWhiteSpace(key))
+                {
+                    RSAParameters publicKeyParams = ParsePemPublicKey(key);
+                    rsa.ImportParameters(publicKeyParams);
+                }
+                // 将字符串转为对应byte[]
+                byte[] textBytes = Encoding.UTF8.GetBytes(text);
+                // 使用私钥解密数据
+                byte[] encryptedBytes = rsa.Encrypt(textBytes, RSAEncryptionPadding.Pkcs1);
+                // 将解密后的字节数组转换为字符串
+                string encryptedData = Convert.ToBase64String(encryptedBytes);
+                return encryptedData;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"RSA encrypt error {ex}");
+                return text;
+            }
+        }
+
+        /// <summary>
+        /// 使用私钥解密数据
+        /// </summary>
+        /// <param name="encryptedData">加密字符串</param>
+        /// <returns></returns>
+        public string Decrypt(string encryptedData, string key)
+        {
+            try
+            {
+                using RSA rsa = RSA.Create(2048);
+                if(!string.IsNullOrWhiteSpace(key))
+                {
+                    rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(key), out _);
+                }
+                // 将Base64编码的加密数据解码为字节数组
+                byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
+                // 使用私钥解密数据
+                byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1);
+                // 将解密后的字节数组转换为字符串
+                string decryptedData = Encoding.UTF8.GetString(decryptedBytes);
+                return decryptedData;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"RSA decrypt error {ex}");
+                return encryptedData;
+            }
+        }
+    }
+
+
+}

+ 206 - 0
src/VitalMixtureService/Common/Encrypt/SM2Helper.cs

@@ -0,0 +1,206 @@
+using System;
+using System.Text;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace VitalService.Common
+{
+    /// <summary>
+    /// SM2加密
+    /// </summary>
+    public class SM2Helper : IEncrypt
+    {
+        public string EncryptModeName => "SM2";
+        private string _publicKey = "";
+        private string _privateKey = "";
+
+        public SM2Helper(string publicKeyString, string privateKeyString)
+        {
+            _publicKey = publicKeyString;
+            _privateKey = privateKeyString;
+        }
+
+        /// <summary>
+        /// 生成 SM2 密钥对,密钥对使用 Hex 进行编码
+        /// </summary>
+        /// <param name="privateKey"></param>
+        /// <param name="publicKey"></param>
+        private void GenerateSM2KeyPair(out string privateKey, out string publicKey)
+        {
+            // 获取 SM2 曲线参数
+            X9ECParameters curve = ECNamedCurveTable.GetByName("sm2p256v1");
+            KeyGenerationParameters parameters = new ECKeyGenerationParameters(new ECDomainParameters(curve), new SecureRandom());
+
+            // 创建 SM2 密钥对生成器
+            ECKeyPairGenerator generator = new ECKeyPairGenerator();
+            generator.Init(parameters);
+
+            // 创建密钥对
+            var keyPair = generator.GenerateKeyPair();
+
+            // 私钥
+            ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters)keyPair.Private;
+            privateKey = Hex.ToHexString(privateKeyParameters.D.ToByteArrayUnsigned());
+
+            // 公钥
+            ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters)keyPair.Public;
+            publicKey = Hex.ToHexString(publicKeyParameters.Q.GetEncoded());
+        }
+
+        /// <summary>
+        /// SM2 公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message))
+                {
+                    return message;
+                }
+                // 获取SM2曲线参数
+                X9ECParameters x9ec = ECNamedCurveTable.GetByName("sm2p256v1");
+                ICipherParameters domain = new ECPublicKeyParameters(x9ec.Curve.DecodePoint(Hex.Decode(_publicKey)), new ECDomainParameters(x9ec));
+
+                // 创建SM2公钥加密器
+                var cipher = new SM2Engine(SM2Engine.Mode.C1C3C2);
+                cipher.Init(true, new ParametersWithRandom(domain));
+
+                byte[] input = Encoding.UTF8.GetBytes(message);
+                byte[] encryptedData = cipher.ProcessBlock(input, 0, input.Length);
+
+                // 返回Hex编码的加密结果
+                return Convert.ToHexString(encryptedData);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message) || !IsSM2String(message))
+                {
+                    return message;
+                }
+                // 获取 SM2 曲线参数
+                X9ECParameters curve = ECNamedCurveTable.GetByName("sm2p256v1");
+                ECDomainParameters domain = new ECDomainParameters(curve);
+                BigInteger d = new BigInteger(1, Hex.Decode(_privateKey));
+                ECPrivateKeyParameters prik = new ECPrivateKeyParameters(d, domain);
+
+                // 创建SM2解密器
+                var cipher = new SM2Engine(SM2Engine.Mode.C1C3C2);
+                cipher.Init(false, prik);
+                
+                byte[] encryptedData = Convert.FromHexString(message);
+                byte[] decryptedData = cipher.ProcessBlock(encryptedData, 0, encryptedData.Length);
+
+                // 将解密结果转换为字符串
+                return Encoding.UTF8.GetString(decryptedData);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message, string key)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message))
+                {
+                    return message;
+                }
+                // 获取SM2曲线参数
+                X9ECParameters x9ec = ECNamedCurveTable.GetByName("sm2p256v1");
+                ICipherParameters domain = new ECPublicKeyParameters(x9ec.Curve.DecodePoint(Hex.Decode(key)), new ECDomainParameters(x9ec));
+
+                // 创建SM2公钥加密器
+                var cipher = new SM2Engine(SM2Engine.Mode.C1C3C2);
+                cipher.Init(true, new ParametersWithRandom(domain));
+
+                byte[] input = Encoding.UTF8.GetBytes(message);
+                byte[] encryptedData = cipher.ProcessBlock(input, 0, input.Length);
+
+                // 返回Hex编码的加密结果
+                return Convert.ToHexString(encryptedData);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message, string key)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message) || !IsSM2String(message))
+                {
+                    return message;
+                }
+                // 获取 SM2 曲线参数
+                X9ECParameters curve = ECNamedCurveTable.GetByName("sm2p256v1");
+                ECDomainParameters domain = new ECDomainParameters(curve);
+                BigInteger d = new BigInteger(1, Hex.Decode(key));
+                ECPrivateKeyParameters prik = new ECPrivateKeyParameters(d, domain);
+
+                // 创建SM2解密器
+                var cipher = new SM2Engine(SM2Engine.Mode.C1C3C2);
+                cipher.Init(false, prik);
+                
+                byte[] encryptedData = Convert.FromHexString(message);
+                byte[] decryptedData = cipher.ProcessBlock(encryptedData, 0, encryptedData.Length);
+
+                // 将解密结果转换为字符串
+                return Encoding.UTF8.GetString(decryptedData);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        private bool IsSM2String(string input)
+        {
+            return System.Text.RegularExpressions.Regex.IsMatch(input, @"^04(?=.*[a-zA-Z])(?=.*\d).+$");
+        }
+    }
+
+}

+ 147 - 0
src/VitalMixtureService/Common/Encrypt/SM4Helper.cs

@@ -0,0 +1,147 @@
+using System;
+using System.Text;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace VitalService.Common
+{
+    /// <summary>
+    /// SM2加密
+    /// </summary>
+    public class SM4Helper : IEncrypt
+    {
+        public string EncryptModeName => "SM4";
+        private string _encryptKey = "";
+
+        public SM4Helper(string encryptKey)
+        {
+            _encryptKey = encryptKey;
+        }
+
+        /// <summary>
+        /// SM2 公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message))
+                {
+                    return message;
+                }
+                // 创建SM4加密器
+                IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
+                KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", Convert.FromHexString(_encryptKey));
+                cipher.Init(true, key);
+                byte[] plaintext = Encoding.UTF8.GetBytes(message);
+                // 加密
+                byte[] ciphertext = cipher.DoFinal(plaintext);
+                return Convert.ToHexString(ciphertext);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message) || !IsSM2String(message))
+                {
+                    return message;
+                }
+                // 创建SM4解密器
+                IBufferedCipher decipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
+                KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", Convert.FromHexString(_encryptKey));
+                decipher.Init(false, key);
+                var spanMessage = Convert.FromHexString(message);
+                // 解密
+                byte[] decryptedText = decipher.DoFinal(spanMessage);
+                return Encoding.UTF8.GetString(decryptedText);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 公钥加密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="publicKey"></param>
+        /// <returns></returns>
+        public string Encrypt(string message, string key)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message))
+                {
+                    return message;
+                }
+                // 创建SM4加密器
+                IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
+                KeyParameter keyParameter = ParameterUtilities.CreateKeyParameter("SM4", Convert.FromHexString(key));
+                cipher.Init(true, keyParameter);
+                byte[] plaintext = Encoding.UTF8.GetBytes(message);
+                // 加密
+                byte[] ciphered = cipher.DoFinal(plaintext);
+                return Convert.ToHexString(ciphered);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        /// <summary>
+        /// SM2 私钥解密
+        /// </summary>
+        /// <param name="message"></param>
+        /// <param name="privateKey"></param>
+        /// <returns></returns>
+        public string Decrypt(string message, string key)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(message) || !IsSM2String(message))
+                {
+                    return message;
+                }
+                // 创建SM4解密器
+                IBufferedCipher decipher = CipherUtilities.GetCipher("SM4/ECB/PKCS7Padding");
+                KeyParameter keyParameter = ParameterUtilities.CreateKeyParameter("SM4", Convert.FromHexString(key));
+                decipher.Init(false, keyParameter);
+                var spanMessage = Convert.FromHexString(message);
+                // 解密
+                byte[] decryptedText = decipher.DoFinal(spanMessage);
+                return Encoding.UTF8.GetString(decryptedText);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                return message;
+            }
+        }
+
+        private bool IsSM2String(string input)
+        {
+            return System.Text.RegularExpressions.Regex.IsMatch(input, @"^04(?=.*[a-zA-Z])(?=.*\d).+$");
+        }
+    }
+}

+ 181 - 0
src/VitalMixtureService/Common/EnvironmentConfigManager.cs

@@ -0,0 +1,181 @@
+using System.Collections.Concurrent;
+using WingServerCommon.Config.Parameters;
+using WingServerCommon.Log;
+
+namespace VitalService.Config
+{
+    /// <summary>
+    /// This class will load system environment config data
+    /// </summary>
+    public class EnvironmentConfigManager
+    {
+        private static readonly AsyncLocal<DateTime> _lastLoadTime = new();
+        private static ConcurrentDictionary<string, IParameter> _parameters;
+        private static string configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json");
+        /// <summary>
+        /// Init load appsetting
+        /// </summary>
+        static EnvironmentConfigManager()
+        {
+            _lastLoadTime.Value = File.GetLastWriteTime(configFilePath);
+            _parameters = ParameterDictionarySerializer.Deserialize(configFilePath);
+        }
+
+        public static void RefreshConfig()
+        {
+            var newLoadTime = File.GetLastWriteTime(configFilePath);
+            if(_lastLoadTime.Value!=newLoadTime)
+            {
+                _parameters = ParameterDictionarySerializer.Deserialize(configFilePath);
+                _lastLoadTime.Value = newLoadTime;
+            }
+        }
+
+        /// <summary>
+        /// Add or Update Config File
+        /// </summary>
+        /// <param name="filePath">Config File Path</param>
+        public static void AddOrUpdateConfig(string filePath = "appsettings.json")
+        {
+            var configFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filePath);
+            var _newParameters = ParameterDictionarySerializer.Deserialize(configFilePath);
+            //替换原先的值_parameters
+            if (_newParameters?.Count > 0)
+            {
+                foreach(var key in _newParameters.Keys)
+                {
+                    if (_parameters != null && _parameters.ContainsKey(key))
+                    {
+                        _parameters[key] = _newParameters[key];
+                    }
+                    else
+                    {
+                        if (_parameters == null)
+                        {
+                           _parameters = new ConcurrentDictionary<string, IParameter>();
+                        }
+                        _parameters.TryAdd(key, _newParameters[key]);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Add or Update DB Config Data
+        /// </summary>
+        /// <param name="json">DB Config Datas json</param>
+        public static void AddOrUpdateDBConfig(string json)
+        {
+            var _newParameters = ParameterDictionarySerializer.Deserialize(json, 1);            
+            //替换原先的值_parameters
+            if (_newParameters?.Count > 0)
+            {
+                foreach(var key in _newParameters.Keys)
+                {
+                    if (_parameters != null && _parameters.ContainsKey(key))
+                    {
+                        _parameters[key] = _newParameters[key];
+                    }
+                    else
+                    {
+                        if (_parameters == null)
+                        {
+                           _parameters = new ConcurrentDictionary<string, IParameter>();
+                        }
+                        _parameters.TryAdd(key, _newParameters[key]);
+                    }
+                }
+            }
+        }
+
+        
+
+        /// <summary>
+        /// Get parameter by specifed section name and parameter name
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        public static T GetParammeter<T>(string sectionName, string paramName) where T : class
+        {
+            RefreshConfig();
+            //var parameter = _parameters.FirstOrDefault(x => x.Section == sectionName && x.Name == paramName) as T;
+            var key = sectionName + "_" + paramName;
+            if (_parameters.ContainsKey(key))
+            {
+                var res = _parameters.TryGetValue(key, out IParameter _value);
+                if (_value != null) 
+                {
+                    var parameter = _value as T;
+                    if (parameter != null)
+                    {
+                        return parameter;
+                    }
+                    else
+                    {
+                        Logger.WriteLineWarn($"EnvironmentConfigManager GetParammeter parameter is null, sectionName: {sectionName} - paramName: {paramName} not set correct");
+                    }
+                }
+                else
+                {
+                    Logger.WriteLineWarn($"EnvironmentConfigManager GetParammeter _value is null, sectionName: {sectionName} - paramName: {paramName} not set correct");
+                }
+            }
+            else
+            {
+                Logger.WriteLineWarn($"EnvironmentConfigManager GetParammeter key is not exist, sectionName: {sectionName} - paramName: {paramName} not set correct");                    
+            }
+            throw new System.ArgumentException($"{sectionName} - {paramName} not set correct");
+        }
+
+        /// <summary>
+        /// Get value by section name and item key
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="sectionName">The parameter section name</param>
+        /// <param name="key">The parameter key</param>
+        /// <param name="defaultValue">The parameter default value</param>
+        /// <returns></returns>
+        public static T GetValue<T>(string sectionName, string key, T defaultValue)
+        {
+            RefreshConfig();
+            var t = typeof(T);
+            //var itemValue = _parameters.FirstOrDefault(q => q.Section == sectionName && q.Name == key);
+            var dicKey = sectionName + "_" + key;
+            if (_parameters.ContainsKey(dicKey))
+            {
+                var res = _parameters.TryGetValue(dicKey, out IParameter itemValue);
+                if (itemValue == null)
+                {
+                    return defaultValue;
+                }
+                object value = null;
+                var type = itemValue.GetType();
+                if (type == typeof(StringParameter))
+                {
+                    value = ((StringParameter)itemValue).Value;
+                }
+                if (type == typeof(IntParameter))
+                {
+                    value = ((IntParameter)itemValue).Value.ToString();
+                }
+                if (type == typeof(BoolParameter))
+                {
+                    value = ((BoolParameter)itemValue).Value.ToString();
+                }
+                if (type == typeof(EnumStringParameter))
+                {
+                    value = ((EnumStringParameter)itemValue).Source;
+                }
+                if (t == typeof(bool) && (value?.ToString() == "0" || value?.ToString() == "1"))
+                {
+                    return (T)(object)(value?.ToString() != "0");
+                }
+                return (T)Convert.ChangeType(value, t);
+            }
+            else
+            {
+                return defaultValue;
+            }
+        }
+
+    }
+}

+ 17 - 0
src/VitalMixtureService/Common/Extensions.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace VitalService.Common
+{
+    public static class Extensions
+    {
+        /// <summary>
+        /// 获取时间如小于最小时间则为空
+        /// </summary>
+        /// <param name="time"></param>
+        /// <returns></returns>
+        public static DateTime? GetTimeOrNull(this DateTime time)
+        {
+            return time <= DateTime.MinValue ? null : time;
+        }
+    }
+}

+ 77 - 0
src/VitalMixtureService/Common/FileCache.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Concurrent;
+using System.IO;
+using JsonRpcLite.Log;
+
+namespace VitalService.Common
+{
+    public class FileCache : ICache
+    {
+        private ConcurrentDictionary<string, string> _cache = new();
+
+        private string _baseCacheDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"FileCache");
+        public FileCache()
+        {
+            if(!Directory.Exists(_baseCacheDir))
+            {
+                Directory.CreateDirectory(_baseCacheDir);
+            }
+        }
+
+        public string GetCache(string key)
+        {
+            if(string.IsNullOrWhiteSpace(key))
+            {
+                return string.Empty;
+            }
+            if(_cache.TryGetValue(key, out var value))
+            {
+                if(File.Exists(value))
+                {
+                    return File.ReadAllText(value);
+                }
+            }
+            return string.Empty;
+        }
+
+        public bool RemoveCache(string key)
+        {
+            if(string.IsNullOrWhiteSpace(key))
+            {
+                return false;
+            }
+            if(_cache.TryRemove(key, out var value))
+            {
+                if(File.Exists(value))
+                {
+                    try
+                    {
+                        File.Delete(value);
+                        return true;
+                    }
+                    catch(Exception ex)
+                    {
+                        Logger.WriteWarning($"RemoveCache error {ex}");
+                        return false;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public bool SetCache(string key, string value)
+        {
+            if(string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value))
+            {
+                return false;
+            }
+            var cacheFile = Path.Combine(_baseCacheDir, $"{key}.cache");
+            File.WriteAllText(cacheFile, value);
+            if(!_cache.TryAdd(key, cacheFile))
+            {
+                return _cache.TryUpdate(key, cacheFile, cacheFile);
+            }
+            return true;
+        }
+    }
+}

+ 11 - 0
src/VitalMixtureService/Common/ICache.cs

@@ -0,0 +1,11 @@
+namespace VitalService.Common
+{
+    public interface ICache
+    {
+        bool SetCache(string key,string value);
+
+        string GetCache(string key);
+
+        bool RemoveCache(string key);
+    }
+}

+ 45 - 0
src/VitalMixtureService/Common/MemoryCache.cs

@@ -0,0 +1,45 @@
+using System.Collections.Concurrent;
+using VitalService.Common;
+
+namespace VitalServerCommon.Cache
+{
+    public class MemoryCache : ICache
+    {
+        private ConcurrentDictionary<string, string> _cache = new();
+
+        public string GetCache(string key)
+        {
+            if(string.IsNullOrWhiteSpace(key))
+            {
+                return string.Empty;
+            }
+            if(_cache.TryGetValue(key, out var value))
+            {
+                return value;
+            }
+            return string.Empty;
+        }
+
+        public bool RemoveCache(string key)
+        {
+            if(string.IsNullOrWhiteSpace(key))
+            {
+                return false;
+            }
+            return _cache.TryRemove(key, out _);
+        }
+
+        public bool SetCache(string key, string value)
+        {
+            if(string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value))
+            {
+                return false;
+            }
+            if(!_cache.TryAdd(key, value))
+            {
+                return _cache.TryUpdate(key, value, value);
+            }
+            return true;
+        }
+    }
+}

+ 28 - 0
src/VitalMixtureService/Common/MemoryIds.cs

@@ -0,0 +1,28 @@
+using System.Collections.Concurrent;
+
+namespace VitalService.Common
+{
+    public class MemoryIds
+    {
+        private MemoryIds(){}
+        private static ConcurrentDictionary<string,string> _ids = new ConcurrentDictionary<string,string>();
+        public static void AddIds(IEnumerable<KeyValuePair<string,string>> ids)
+        {
+            foreach (var id in ids)
+            {
+                _ids.TryAdd(id.Key, id.Value);
+            }
+        }
+
+        public static bool CheckId(string key, out string token)
+        {
+            token = string.Empty;
+            if(_ids.ContainsKey(key))
+            {
+                _ = _ids.TryRemove(key, out token);
+                return true;
+            }
+            return false;
+        }
+    }
+}

+ 29 - 0
src/VitalMixtureService/Common/NumberGenerator.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Text;
+
+namespace VitalService.Common
+{
+    public class NumberGenerator
+    {
+        private static readonly Random random = new Random();
+
+        public static string GenerateNumber()
+        {
+            string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
+            string randomString = GenerateRandomString(6);
+            string number = timestamp + randomString;
+            return number;
+        }
+
+        private static string GenerateRandomString(int length)
+        {
+            const string chars = "0123456789";
+            StringBuilder stringBuilder = new StringBuilder(length);
+            for (int i = 0; i < length; i++)
+            {
+                stringBuilder.Append(chars[random.Next(chars.Length)]);
+            }
+            return stringBuilder.ToString();
+        }
+    }
+}

+ 137 - 0
src/VitalMixtureService/Common/ProcessStarter.cs

@@ -0,0 +1,137 @@
+using System.Diagnostics;
+using JsonRpcLite.Log;
+
+namespace VitalServer.Common
+{
+    public class ProcessStarter
+    {
+        private ProcessStarter() { }
+
+        /// <summary>
+        /// 开始执行工具程序
+        /// </summary>
+        /// <param name="processName">工具程序名称</param>
+        public static void StartTool(string processName, string paramsValue = "")
+        {
+            if (!string.IsNullOrEmpty(processName))
+            {
+                var toolsRootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Packages");
+                var toolPath = string.Empty;
+                if (processName.Contains("\\")) //路径
+                {
+                    toolPath = Path.Combine(toolsRootPath, processName);
+                }
+                else
+                {
+                    var subPath = GetPlatfromTitle();
+                    toolPath = Path.Combine(toolsRootPath, subPath, $"{subPath}_{processName}");
+                }
+
+                if (Process.GetProcessesByName(Path.GetFileName(toolPath)).Length == 0)
+                {
+                    using (Process process = new Process())
+                    {
+                        process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
+                        process.StartInfo.FileName = toolPath;
+                        process.StartInfo.Arguments = paramsValue;
+                        process.Start();
+                    }
+                }
+            }
+
+
+        }
+
+        /// <summary>
+        /// 开始执行工具程序
+        /// </summary>
+        /// <param name="processName">工具程序名称</param>
+        public static async void StartProcess(string namePath, string workingDirectory, string paramsValue = "")
+        {
+            var externalProcess = new Process
+            {
+                StartInfo = new ProcessStartInfo
+                {
+                    FileName = namePath,
+                    Arguments = paramsValue,
+                    WorkingDirectory = workingDirectory,
+                    RedirectStandardOutput = true,
+                    RedirectStandardError = true,
+                    CreateNoWindow = false,
+                    UseShellExecute = false
+                },
+                EnableRaisingEvents = true
+            };
+
+            externalProcess.OutputDataReceived += (sender, e) =>
+            {
+                if (!string.IsNullOrEmpty(e.Data))
+                {
+                    //Logger.WriteInfo(e.Data);
+                }
+            };
+
+            externalProcess.ErrorDataReceived += (sender, e) =>
+            {
+                if (!string.IsNullOrEmpty(e.Data))
+                {
+                    Logger.WriteError(e.Data);
+                }
+            };
+
+            // 注册一个事件处理程序,在主程序退出时关闭外部进程
+            AppDomain.CurrentDomain.ProcessExit += (sender, args) =>
+            {
+                if (externalProcess == null || externalProcess.HasExited)
+                {
+                    return;
+                }
+
+                externalProcess.CloseMainWindow();
+                externalProcess.WaitForExit();
+            };
+
+            externalProcess.Start();
+            externalProcess.BeginOutputReadLine();
+            externalProcess.BeginErrorReadLine();
+        }
+        /// <summary>
+        /// 停止工具程序
+        /// </summary>
+        /// <param name="processName">工具程序名称</param>
+        public static void StopTool(string processName)
+        {
+            var proc = Process.GetProcessesByName($"{GetPlatfromTitle()}_{processName}");
+            foreach (var p in proc)
+            {
+                try
+                {
+                    Console.WriteLine($"close {p.ProcessName}");
+                    Process.GetProcessById(p.Id).Kill();
+                }
+                catch (Exception pex)
+                {
+                    Console.WriteLine($"{pex}");
+                }
+            }
+        }
+
+        private static string GetPlatfromTitle()
+        {
+            string platfrom;
+            switch (Environment.OSVersion.Platform)
+            {
+                case PlatformID.Win32NT:
+                    platfrom = "win";
+                    break;
+                case PlatformID.MacOSX:
+                    platfrom = "mac";
+                    break;
+                default:
+                    platfrom = "lin";
+                    break;
+            }
+            return platfrom;
+        }
+    }
+}

+ 31 - 0
src/VitalMixtureService/Common/RequestConvertHelper.cs

@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Text.Json;
+using WingInterfaceLibrary.Request.DBVitalRequest;
+using WingInterfaceLibrary.Request.Vital;
+
+namespace VitalService.Common
+{
+    public static class RequestConvertHelper
+    {
+        public static CreateSystemSettingDBRequest ConvertToCreateSystemSettingDBRequest(this SetRegionVisibleConfigRequest request)
+        {
+            var jsonData = JsonSerializer.Serialize(request.RegionInfo);
+            var dbRequest = new CreateSystemSettingDBRequest
+            {
+                SettingKey = "RegionVisibleConfig",
+                SettingContent = jsonData
+            };
+            return dbRequest;
+        }
+
+        public static GetSystemSettingByKeyDBRequest ConvertToGetSystemSettingByKeyDBRequest(this GetRegionVisibleConfigRequest request)
+        {
+            var dbRequest = new GetSystemSettingByKeyDBRequest
+            {
+                Key = "SettingKey",
+                Value = "RegionVisibleConfig"
+            };
+            return dbRequest;
+        }
+    }
+}

+ 26 - 0
src/VitalMixtureService/Common/ResultConvertHelper.cs

@@ -0,0 +1,26 @@
+using System.Data.Common;
+using System.Threading.Tasks;
+using VitalService.Serialization;
+
+namespace VitalService.Common
+{
+    public static class ResultConvertHelper
+    {
+        public static async Task<bool> GetIsCreatedResult(this string data)
+        {
+            return await Task.FromResult(!string.IsNullOrWhiteSpace(data));
+        }
+
+        public static async Task<string> GetDataToJsonResult(this object obj)
+        {
+            if(obj == null) return null;
+            return await Task.FromResult(JsonHelper.SerializerToJson(obj));
+        }
+
+        public static async Task<T> GetJsonToDataResult<T>(this string json) where T : class
+        {
+            if(string.IsNullOrWhiteSpace(json)) return null;
+            return await Task.FromResult(JsonHelper.DeserializerJson<T>(json));
+        }
+    }
+}

+ 53 - 0
src/VitalMixtureService/Common/RpcClient.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using AutoMapper;
+using WingInterfaceLibrary.DTO.Vital;
+using WingInterfaceLibrary.Result;
+using WingServerCommon.Log;
+
+namespace VitalService.Common
+{
+    public class RpcClient
+    {
+        private static HttpClient _httpClient;
+
+        public RpcClient()
+        {
+            _httpClient = new HttpClient();
+            _httpClient.Timeout = TimeSpan.FromSeconds(30);
+        }
+
+        public async Task<T> GetRPCResult<T>(string rpcUrl, string request)
+        {
+            try
+            {
+                var data = await _httpClient.PostAsync(rpcUrl, new StringContent(request));
+                var resString = data?.Content?.ReadAsStringAsync()?.Result;
+                if (!string.IsNullOrWhiteSpace(resString))
+                {
+                    try
+                    {
+                        Logger.WriteLineInfo($"Call GetRPCResult request:{request}, result:{resString}");
+                        var rpcResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<RpcBaseResult<T>>(resString);
+                        return rpcResponse.result;
+                    }
+                    catch (Exception ex)
+                    {
+                        Logger.WriteLineWarn($"Call GetRPCResult error {ex}");
+                        return default;
+                    }
+                }
+                else
+                {
+                    return default;
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLineWarn($"Call GetRPCResult error {ex}");
+                return default;
+            }
+        }
+    }
+}

+ 22 - 0
src/VitalMixtureService/Common/SequentialNumberGenerator.cs

@@ -0,0 +1,22 @@
+namespace VitalService.Common
+{
+    public class SequentialNumberGenerator
+    {
+        private long _currentNumber;
+        private object lockObject = new object();
+
+        public SequentialNumberGenerator(long lastNumber)
+        {
+            _currentNumber = lastNumber;
+        }
+
+        public long GetNextNumber()
+        {
+            lock (lockObject)
+            {
+                _currentNumber++;
+                return _currentNumber;
+            }
+        }
+    }
+}

+ 81 - 0
src/VitalMixtureService/Common/ServerLoggerEngine.cs

@@ -0,0 +1,81 @@
+using System.Diagnostics;
+using Serilog;
+using VitalService.Config;
+using WingServerCommon.Config.Parameters;
+using WingServerCommon.Log;
+
+namespace VitalService.Common
+{
+    public class ServerLoggerEngine : ILogEngine
+    {
+        private Serilog.Core.Logger _logger;
+
+        private static string _server => EnvironmentConfigManager.GetParammeter<StringParameter>("Database", "Server").Value;
+
+        private static int _port => EnvironmentConfigManager.GetParammeter<IntParameter>("Database", "Port").Value;
+
+        private static bool _debugMode => EnvironmentConfigManager.GetParammeter<BoolParameter>("Log", "Debug").Value;
+
+        private static string _logDBName => EnvironmentConfigManager.GetParammeter<StringParameter>("Log", "DBName").Value;
+
+        private static string _collectionName => EnvironmentConfigManager.GetParammeter<StringParameter>("Log", "CollectionName").Value;
+
+
+
+        public ServerLoggerEngine()
+        {
+            if (_debugMode)
+            {
+                _logger = new LoggerConfiguration()
+                .MinimumLevel.Debug()
+                .MinimumLevel.Verbose()
+                    .WriteTo.MongoDB($"mongodb://{_server}:{_port}/{_logDBName}", _collectionName, batchPostingLimit: 1000)
+                    .WriteTo.Console()
+                    .CreateLogger();
+            }
+            else
+            {
+                _logger = new LoggerConfiguration()
+               .MinimumLevel.Debug()
+               .MinimumLevel.Verbose()
+                   .WriteTo.MongoDB($"mongodb://{_server}:{_port}/{_logDBName}", _collectionName, batchPostingLimit: 1000)
+                   .CreateLogger();
+            }
+        }
+
+        /// <summary>
+        /// Write the log
+        /// </summary>
+        /// <param name="level">Log's level see <see cref="TraceLevel"/></param>
+        /// <param name="msg">The message to write</param>
+        public void Write(TraceLevel level, string msg)
+        {
+            var threadId = Thread.CurrentThread.ManagedThreadId;
+            var log = $"Thead({threadId})-{msg}";
+            //截断
+            if (log.Length > 1000)
+            {
+                log = log.Substring(0, 1000);
+            }
+            switch (level)
+            {
+                case TraceLevel.Error:
+                    _logger.Error(log);
+                    break;
+                case TraceLevel.Warning:
+                    _logger.Warning(log);
+                    break;
+                case TraceLevel.Info:
+                    _logger.Information(log);
+                    break;
+                case TraceLevel.Verbose:
+                    _logger.Verbose(log);
+                    break;
+                case TraceLevel.Off:
+                    _logger.Debug(log);
+                    break;
+            }
+
+        }
+    }
+}

+ 100 - 0
src/VitalMixtureService/Common/UserHeartRateManager.cs

@@ -0,0 +1,100 @@
+using System.Collections.Concurrent;
+using WingServerCommon.Log;
+
+namespace VitalService.Common
+{
+    internal class UserHeartRateManager
+    {
+        private ConcurrentDictionary<string, UserHeartRateDTO> _users = new ConcurrentDictionary<string, UserHeartRateDTO>();
+        private Func<string, bool, bool> OnSetOnlineState;
+
+        public UserHeartRateManager(Func<string, bool, bool> setOnlineState)
+        {
+            OnSetOnlineState = setOnlineState;
+            StartCheckClients();
+        }
+
+        /// <summary>
+        /// 加入检测集合
+        /// </summary>
+        /// <param name="token"></param>
+        public void AddOrUpdate(string token)
+        {
+            _users.AddOrUpdate(token, new UserHeartRateDTO(token), (k, v) =>
+            {
+                v.Activate();
+                return v;
+            });
+        }
+
+        /// <summary>
+        /// 设备心跳有效期验证
+        /// </summary>
+        private void StartCheckClients()
+        {
+            Logger.WriteLineInfo($"UserHeartRateManager start check clients");
+            Task.Run(async () =>
+            {
+                while (true)
+                {
+                    await Task.Delay(1 * 60 * 1000);
+                    foreach (var token in _users.Keys)
+                    {
+                        var heartRate = _users[token];
+                        heartRate.DeActivate();
+                        try
+                        {
+                            if (heartRate.LeftTime < 0)
+                            {
+                                OnSetOnlineState?.Invoke(token, false);
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Logger.WriteLineWarn($"check user token {token} err, {ex}");
+                        }
+                        finally
+                        {
+                            if (heartRate.LeftTime < 0)
+                            {
+                                _users.TryRemove(token, out _);
+                            }
+                        }
+                    }
+                }
+            });
+            Logger.WriteLineInfo($"UserHeartRateManager finished");
+        }
+    }
+
+    internal class UserHeartRateDTO
+    {
+        public UserHeartRateDTO(string token)
+        {
+            Token = token;
+        }
+
+        private volatile int _livingTime = 0;
+        private readonly int _clientLifecycle = 10; //10 minutes 
+
+        public string Token { get; set; }
+
+        public int LeftTime => _clientLifecycle - _livingTime;
+
+        /// <summary>
+        /// Reset the living time.
+        /// </summary>
+        public virtual void Activate()
+        {
+            _livingTime = 0;
+        }
+
+        /// <summary>
+        /// Deactive the session.
+        /// </summary>
+        public virtual void DeActivate()
+        {
+            _livingTime++;
+        }
+    }
+}

+ 334 - 0
src/VitalMixtureService/DBService/DBAutoMapperProfile.cs

@@ -0,0 +1,334 @@
+using VitalService.Entities;
+using AutoMapper;
+using WingInterfaceLibrary.Interface;
+using WingInterfaceLibrary.DTO.Vital;
+using WingInterfaceLibrary.Request.Vital;
+using WingInterfaceLibrary.Request.DBVitalRequest;
+using WingInterfaceLibrary.Request;
+namespace VitalServer
+{
+	/// <summary>
+	/// Auto mapper profile
+	/// </summary>
+	public class DBAutoMapperProfile : Profile
+	{
+		public DBAutoMapperProfile()
+		{
+            CreateMap<TokenDTO, TokenEntity>().ReverseMap();
+			CreateMap<CompletionRecordDTO, CompletionRecordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CompletionRecordPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ContractRecordDTO, ContractRecordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ContractRecordPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ContractTemplateDTO, ContractTemplateEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ContractTemplatePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateCompletionRecordDBRequest, CompletionRecordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateCompletionRecordRequest, CreateCompletionRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateContractRecordDBRequest, ContractRecordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateContractRecordRequest, CreateContractRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateContractTemplateDBRequest, ContractTemplateEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateContractTemplateRequest, CreateContractTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDeviceDBRequest, DeviceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDeviceRequest, CreateDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDiagnosisDBRequest, DiagnosisEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDiagnosisRequest, CreateDiagnosisDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDictionaryDBRequest, DictionaryEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDictionaryRequest, CreateDictionaryDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDynamicTypeDBRequest, DynamicTypeEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateDynamicTypeRequest, CreateDynamicTypeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateExamDBRequest, ExamEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateExamRequest, CreateExamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateFollowUpDBRequest, FollowUpEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateFollowUpRequest, CreateFollowUpDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateLabelDBRequest, LabelEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateLabelRequest, CreateLabelDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateAnalyzeConfigDBRequest, AnalyzeConfigEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateAnalyzeConfigRequest, CreateAnalyzeConfigDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateNotificationDBRequest, NotificationEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateNotificationRequest, CreateNotificationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateOperationLogDBRequest, OperationLogEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateOperationLogRequest, CreateOperationLogDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateOrganizationDBRequest, OrganizationEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateOrganizationRequest, CreateOrganizationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePatientDBRequest, PatientEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePatientExtensionDBRequest, PatientExtensionEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePatientExtensionRequest, CreatePatientExtensionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePatientRequest, CreatePatientDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePeripheralDeviceDBRequest, PeripheralDeviceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreatePeripheralDeviceRequest, CreatePeripheralDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateReportDBRequest, ReportEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateReportRequest, CreateReportDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateResidenceDBRequest, ResidenceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateResidenceRequest, CreateResidenceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateRoleDBRequest, RoleEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateRoleRequest, CreateRoleDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateServiceItemDBRequest, ServiceItemEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateServiceItemRequest, CreateServiceItemDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateServicePackDBRequest, ServicePackEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateServicePackRequest, CreateServicePackDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateStatisticDBRequest, StatisticEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateStatisticRequest, CreateStatisticDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateSystemSettingDBRequest, SystemSettingEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateSystemSettingRequest, CreateSystemSettingDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTeamDBRequest, TeamEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTeamRegionDBRequest, TeamRegionEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTeamRegionRequest, CreateTeamRegionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTeamRequest, CreateTeamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTemplateDBRequest, TemplateEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTemplateRequest, CreateTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTownDBRequest, TownEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateTownRequest, CreateTownDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUpgradeDBRequest, UpgradeEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUpgradeRequest, CreateUpgradeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserDBRequest, UserEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserFeatureDBRequest, UserFeatureEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserFeatureRequest, CreateUserFeatureDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserPasswordDBRequest, UserPasswordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserPasswordRequest, CreateUserPasswordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUserRequest, CreateUserDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DeviceDTO, DeviceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DevicePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DiagnosisDTO, DiagnosisEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DiagnosisPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DictionaryDTO, DictionaryEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DictionaryPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DynamicTypeDTO, DynamicTypeEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DynamicTypePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ExamDTO, ExamEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ExamPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<FollowUpDTO, FollowUpEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<FollowUpPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetCompletionRecordByKeyRequest, GetCompletionRecordByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetCompletionRecordListRequest, GetCompletionRecordListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetCompletionRecordRequest, GetCompletionRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractRecordByKeyRequest, GetContractRecordByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractRecordListRequest, GetContractRecordListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractRecordRequest, GetContractRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractTemplateByKeyRequest, GetContractTemplateByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractTemplateListRequest, GetContractTemplateListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetContractTemplateRequest, GetContractTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDeviceRequest, GetDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDiagnosisByKeyRequest, GetDiagnosisByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDiagnosisListRequest, GetDiagnosisListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDiagnosisRequest, GetDiagnosisDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDictionaryByKeyRequest, GetDictionaryByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDictionaryListRequest, GetDictionaryListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDictionaryRequest, GetDictionaryDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDynamicTypeByKeyRequest, GetDynamicTypeByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDynamicTypeListRequest, GetDynamicTypeListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetDynamicTypeRequest, GetDynamicTypeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetExamByKeyRequest, GetExamByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetExamListRequest, GetExamListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetExamRequest, GetExamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetFollowUpByKeyRequest, GetFollowUpByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetFollowUpListRequest, GetFollowUpListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetFollowUpRequest, GetFollowUpDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetLabelByKeyRequest, GetLabelByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetLabelListRequest, GetLabelListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetLabelRequest, GetLabelDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetAnalyzeConfigByKeyRequest, GetAnalyzeConfigByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetAnalyzeConfigListRequest, GetAnalyzeConfigListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetAnalyzeConfigRequest, GetAnalyzeConfigDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetNotificationRequest, GetNotificationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOperationLogByKeyRequest, GetOperationLogByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOperationLogListRequest, GetOperationLogListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOperationLogRequest, GetOperationLogDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOrganizationByKeyRequest, GetOrganizationByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOrganizationListRequest, GetOrganizationListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetOrganizationRequest, GetOrganizationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetPatientByKeyRequest, GetPatientByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetPatientExtensionListRequest, GetPatientExtensionListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetPatientExtensionRequest, GetPatientExtensionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetPatientListRequest, GetPatientListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetPatientRequest, GetPatientDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetReportByKeyRequest, GetReportByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetReportListRequest, GetReportListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetReportRequest, GetReportDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetResidenceByKeyRequest, GetResidenceByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetResidenceListRequest, GetResidenceListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetResidenceRequest, GetResidenceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetRoleByKeyRequest, GetRoleByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetRoleListRequest, GetRoleListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetRoleRequest, GetRoleDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetServiceItemListRequest, GetServiceItemListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetServiceItemRequest, GetServiceItemDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetServicePackRequest, GetServicePackDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetStatisticByKeyRequest, GetStatisticByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetStatisticListRequest, GetStatisticListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetStatisticRequest, GetStatisticDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetSystemSettingByKeyRequest, GetSystemSettingByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetSystemSettingListRequest, GetSystemSettingListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetSystemSettingRequest, GetSystemSettingDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamByKeyRequest, GetTeamByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamListRequest, GetTeamListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamRegionByKeyRequest, GetTeamRegionByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamRegionListRequest, GetTeamRegionListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamRegionRequest, GetTeamRegionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTeamRequest, GetTeamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTemplateByKeyRequest, GetTemplateByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTemplateListRequest, GetTemplateListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTemplateRequest, GetTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTownByKeyRequest, GetTownByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTownListRequest, GetTownListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetTownRequest, GetTownDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUpgradeRequest, GetUpgradeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserByKeyRequest, GetUserByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserFeatureByKeyRequest, GetUserFeatureByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserFeatureListRequest, GetUserFeatureListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserFeatureRequest, GetUserFeatureDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserListRequest, GetUserListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserPasswordByKeyRequest, GetUserPasswordByKeyDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserPasswordListRequest, GetUserPasswordListDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserPasswordRequest, GetUserPasswordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<GetUserRequest, GetUserDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<LabelDTO, LabelEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<LabelPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<AnalyzeConfigDTO, AnalyzeConfigEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<AnalyzeConfigPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<NotificationDTO, NotificationEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<NotificationPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<OperationLogDTO, OperationLogEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<OperationLogPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<OrganizationDTO, OrganizationEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<OrganizationPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<CompletionRecordDTO>, PageCollection<CompletionRecordEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ContractRecordDTO>, PageCollection<ContractRecordEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ContractTemplateDTO>, PageCollection<ContractTemplateEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<DeviceDTO>, PageCollection<DeviceEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<DiagnosisDTO>, PageCollection<DiagnosisEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<DictionaryDTO>, PageCollection<DictionaryEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<DynamicTypeDTO>, PageCollection<DynamicTypeEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ExamDTO>, PageCollection<ExamEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<FollowUpDTO>, PageCollection<FollowUpEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<LabelDTO>, PageCollection<LabelEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<AnalyzeConfigDTO>, PageCollection<AnalyzeConfigEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<NotificationDTO>, PageCollection<NotificationEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<OperationLogDTO>, PageCollection<OperationLogEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<OrganizationDTO>, PageCollection<OrganizationEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<PatientDTO>, PageCollection<PatientEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<PatientExtensionDTO>, PageCollection<PatientExtensionEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<PeripheralDeviceDTO>, PageCollection<PeripheralDeviceEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ReportDTO>, PageCollection<ReportEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ResidenceDTO>, PageCollection<ResidenceEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<RoleDTO>, PageCollection<RoleEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ScheduleDTO>, PageCollection<ScheduleEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ServiceItemDTO>, PageCollection<ServiceItemEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<ServicePackDTO>, PageCollection<ServicePackEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<StatisticDTO>, PageCollection<StatisticEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<SystemSettingDTO>, PageCollection<SystemSettingEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<TeamDTO>, PageCollection<TeamEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<TeamRegionDTO>, PageCollection<TeamRegionEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<TemplateDTO>, PageCollection<TemplateEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<TownDTO>, PageCollection<TownEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<UpgradeDTO>, PageCollection<UpgradeEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<UserDTO>, PageCollection<UserEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<UserFeatureDTO>, PageCollection<UserFeatureEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PageCollection<UserPasswordDTO>, PageCollection<UserPasswordEntity>>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PatientDTO, PatientEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PatientExtensionDTO, PatientExtensionEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PatientExtensionPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PatientPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<PeripheralDeviceDTO, PeripheralDeviceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveCompletionRecordRequest, RemoveCompletionRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveContractRecordRequest, RemoveContractRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveContractTemplateRequest, RemoveContractTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveDeviceRequest, RemoveDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveDiagnosisRequest, RemoveDiagnosisDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveDictionaryRequest, RemoveDictionaryDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveDynamicTypeRequest, RemoveDynamicTypeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveExamRequest, RemoveExamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveFollowUpRequest, RemoveFollowUpDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveLabelRequest, RemoveLabelDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveAnalyzeConfigRequest, RemoveAnalyzeConfigDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveOperationLogRequest, RemoveOperationLogDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveOrganizationRequest, RemoveOrganizationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemovePatientExtensionRequest, RemovePatientExtensionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemovePatientRequest, RemovePatientDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemovePeripheralDeviceRequest, RemovePeripheralDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveReportRequest, RemoveReportDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveResidenceRequest, RemoveResidenceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveRoleRequest, RemoveRoleDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveStatisticRequest, RemoveStatisticDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveSystemSettingRequest, RemoveSystemSettingDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveTeamRegionRequest, RemoveTeamRegionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveTeamRequest, RemoveTeamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveTemplateRequest, RemoveTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveTownRequest, RemoveTownDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveUserFeatureRequest, RemoveUserFeatureDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveUserPasswordRequest, RemoveUserPasswordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RemoveUserRequest, RemoveUserDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ReportDTO, ReportEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ReportPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ResidenceDTO, ResidenceEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ResidencePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RoleDTO, RoleEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<RolePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ScheduleDTO, ScheduleEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ServiceItemDTO, ServiceItemEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ServicePackDTO, ServicePackEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ServicePackPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<StatisticDTO, StatisticEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<StatisticPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<SystemSettingDTO, SystemSettingEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<SystemSettingPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TeamDTO, TeamEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TeamPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TeamRegionDTO, TeamRegionEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TeamRegionPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TemplateDTO, TemplateEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TemplatePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TownDTO, TownEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<TownPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateCompletionRecordRequest, UpdateCompletionRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateContractRecordRequest, UpdateContractRecordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateContractTemplateRequest, UpdateContractTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateDeviceRequest, UpdateDeviceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateDiagnosisRequest, UpdateDiagnosisDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateDictionaryRequest, UpdateDictionaryDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateDynamicTypeRequest, UpdateDynamicTypeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateExamRequest, UpdateExamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateFollowUpRequest, UpdateFollowUpDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateLabelRequest, UpdateLabelDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateAnalyzeConfigRequest, UpdateAnalyzeConfigDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateOperationLogRequest, UpdateOperationLogDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateOrganizationRequest, UpdateOrganizationDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdatePatientExtensionRequest, UpdatePatientExtensionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdatePatientRequest, UpdatePatientDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateReportRequest, UpdateReportDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateResidenceRequest, UpdateResidenceDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateRoleRequest, UpdateRoleDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateServiceItemRequest, UpdateServiceItemDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateServicePackRequest, UpdateServicePackDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateStatisticRequest, UpdateStatisticDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateSystemSettingRequest, UpdateSystemSettingDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateTeamRegionRequest, UpdateTeamRegionDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateTeamRequest, UpdateTeamDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateTemplateRequest, UpdateTemplateDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateTownRequest, UpdateTownDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateUpgradeRequest, UpdateUpgradeDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateUserFeatureRequest, UpdateUserFeatureDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateUserPasswordRequest, UpdateUserPasswordDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpdateUserRequest, UpdateUserDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpgradeDTO, UpgradeEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UpgradePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserDTO, UserEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserFeatureDTO, UserFeatureEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserFeaturePageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserPasswordDTO, UserPasswordEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<UserPasswordPageRequest, DBPageRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			
+
+
+			CreateMap<UpgradeDTO, UpgradeEntity>().ReverseMap().ForMember(opt=> opt.Version, dest => dest.Ignore()).ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<CreateUpgradeDBRequest, UpgradeEntity>().ReverseMap().ForMember(opt=> opt.Version, dest => dest.Ignore()).ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<OrganizationTreeDTO, OrganizationEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+		    CreateMap<TeamBaseDTO, TeamEntity>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<DBLog, LogEntry>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ExamDTO, ExamRecordDTO>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ExamEntity, ExamRecordDataDTO>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<ContractRecordDTO, ContractRecordEntity>().ReverseMap().ForMember(opt => opt.ServicePacks, dest => dest.Ignore()).ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<SyncPatientAndDiagnosisDataDBRequest, CreatePatientDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+			CreateMap<SyncPatientAndDiagnosisDataDBRequest, SubmitDiagnosisDBRequest>().ReverseMap().ForAllOtherMembers(opt => opt.AllowNull());
+		}
+	}
+}

+ 62 - 0
src/VitalMixtureService/DBService/Driver/Other/SpinThread.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Threading.Tasks;
+
+namespace VitalService.Mongodb.Driver
+{
+    public class SpinThread
+    {
+        private bool _keepRunning = false;
+        private string _taskName { get; set; }
+        private TimeSpan _waitTime;
+        private Action<object> _action;
+        private object _param;
+        public SpinThread(string taskName, TimeSpan waitTime, Action<object> action, object param = null)
+        {
+            _taskName = taskName;
+            _waitTime = waitTime;
+            _action = action;
+            _param = param;
+        }
+
+        /// <summary>
+        /// 开始运行
+        /// </summary>
+        public void Start()
+        {
+            _keepRunning = true;
+            Task.Run(async() =>
+            {
+                Console.WriteLine($"[ScheduledWork] {_taskName} start running");
+                while (_keepRunning)
+                {
+                    try
+                    {
+                        _action?.Invoke(_param);
+                        await Task.Delay(_waitTime);
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine($"[ScheduledWork] {_taskName} error:{ex}");
+                    }
+                }
+                Console.WriteLine($"[ScheduledWork] {_taskName} stoped");
+            });
+        }
+
+        /// <summary>
+        /// 停止运行
+        /// </summary>
+        public void Stop()
+        {
+            _keepRunning = false;
+        }
+
+        /// <summary>
+        /// 析构时停止
+        /// </summary>
+        ~SpinThread()
+        {
+            Stop();
+        }
+    }
+}

+ 85 - 0
src/VitalMixtureService/DBService/Driver/Query/MongoRepertoryCenter.cs

@@ -0,0 +1,85 @@
+using MongoDB.Driver;
+using WingServerCommon.Log;
+
+namespace VitalService.Mongodb.Driver
+{
+    /// <summary>
+    /// 仓储中心创建者
+    /// </summary>
+    public class MongoRepertoryCenter
+    {
+        private static MongoRepertoryCenter _instance;
+        private MongoClient _single;
+        private string _dbName;
+
+        /// <summary>
+        /// 单例对象
+        /// </summary>
+        /// <value></value>
+        internal static MongoRepertoryCenter Instance
+        {
+            get => _instance ?? (_instance = new MongoRepertoryCenter());
+        }
+
+        /// <summary>
+        /// 创建DB客户端仓储
+        /// </summary>
+        /// <param name="host">主机ip</param>
+        /// <param name="port">端口</param>
+        /// <param name="dbName">db名称</param>
+        public void Init(string host, int port, string dbName)
+        {
+            try
+            {
+                _dbName = dbName;
+                _single = CreateClient(host, port);
+            }
+            catch (System.Exception ex)
+            {
+                Console.WriteLine($"MongoRepertoryCenter init error {ex}");
+            }
+        }
+
+
+        public IMongoDatabase GetDatabase(string dbName)
+        {
+            return _single.GetDatabase(dbName);
+        }
+
+        private MongoClient CreateClient(string host, int port)
+        {
+            MongoClientSettings mongoClientSettings = new MongoClientSettings
+            {
+                ConnectTimeout = TimeSpan.FromSeconds(60),
+                Server = new MongoServerAddress(host, port)
+            };
+            var client = new MongoClient(mongoClientSettings);
+            return client;
+        }
+
+        /// <summary>
+        /// 用于判定是否初次部署
+        /// </summary>
+        /// <returns></returns>
+        public bool DatabaseExist()
+        {
+            if (GetDatabase(_dbName) != null)
+            {
+                return GetDatabase(_dbName).ListCollectionNames().Any();
+            }
+            Logger.WriteLineError($"MongoDatabase is null");
+            return false;
+        }
+
+        /// <summary>
+        /// > 从缓存中获取集合,如果不存在则创建并添加到缓存中
+        /// </summary>
+        /// <returns>
+        /// MongoCollectionProxy<T>
+        /// </returns>
+        internal IMongoCollection<T> GetCollection<T>(string typeName)
+        {
+            return GetDatabase(_dbName).GetCollection<T>(typeName);
+        }
+    }
+}

+ 63 - 0
src/VitalMixtureService/DBService/Driver/Server/BackupDBJob.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+
+namespace VitalService.Driver
+{
+    public class BackupDBJob
+    {
+        private BackupDBJob(){}
+        
+        /// <summary>
+        /// > 执行 mongodump 命令备份数据库
+        /// </summary>
+        public static void Execute()
+        {
+            try
+            {
+                Console.WriteLine($"Mongodb backup job starting");
+                var toolPath = string.Empty;
+                var mongoPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Packages");
+                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+                {
+                    toolPath = Path.Combine(mongoPath, "mongodump.exe");
+                }
+                else
+                {
+                    toolPath = Path.Combine(mongoPath, "mongodump");
+                }
+                var bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Mongodb", "Bak");
+                Directory.CreateDirectory(bakPath);
+                var directories = Directory.GetDirectories(bakPath);
+                if (directories.Length > 10)
+                {
+                    var needDelInfos = directories.Select(f => new { path = f, createTime = Directory.GetCreationTime(f) });
+                    var needDelPaths = needDelInfos.OrderBy(f => f.createTime).Take(5);
+                    foreach (var delPath in needDelPaths)
+                    {
+                        Directory.Delete(delPath.path, true);
+                    }
+                }
+                var needMakePath = Path.Combine(bakPath, DateTime.UtcNow.ToString("yyyyMMddHHmmss"));
+                var mkdir = Directory.CreateDirectory(needMakePath);
+                var arguments = $"-h 127.0.0.1:9100 -d WingCloudDB -o {mkdir} --quiet";
+                var startInfo = new ProcessStartInfo
+                {
+                    FileName = toolPath,
+                    Arguments = arguments,
+                    RedirectStandardOutput = false,
+                };
+                using (var process = Process.Start(startInfo))
+                {
+                    Console.WriteLine($"Mongodb backup job completed");
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Mongodb backup job error {ex}");
+                throw;
+            }
+        }
+    }
+}

+ 35 - 0
src/VitalMixtureService/DBService/Entities/AnalyzeConfigEntity.cs

@@ -0,0 +1,35 @@
+namespace VitalService.Entities
+{
+    public class AnalyzeConfigEntity: BaseEntity
+    {
+        /// <summary>
+        /// 输入的字段
+        /// </summary>
+        /// <value></value>
+        public string InField { get; set; }
+
+        /// <summary>
+        /// 输出的字段
+        /// </summary>
+        /// <value></value>
+        public string OutField  { get; set; }
+
+        /// <summary>
+        /// 解析方式
+        /// </summary>
+        /// <value></value>
+        public string Mode { get; set; }
+
+        /// <summary>
+        /// 模版
+        /// </summary>
+        /// <value></value>
+        public string Template { get; set; }
+
+        /// <summary>
+        /// 解析配置
+        /// </summary>
+        /// <value></value>
+        public string AnalyzeConfigItems { get; set; }
+    }
+}

+ 56 - 0
src/VitalMixtureService/DBService/Entities/BaseEntity.cs

@@ -0,0 +1,56 @@
+using System;
+using VitalService.Mongodb.Driver;
+using VitalService.Entities;
+
+namespace VitalService.Entities
+{
+    /// <summary>
+    /// basic Entity
+    /// </summary>
+    public class BaseEntity : IBaseEntity
+    {
+        /// <summary>
+        /// The unique database table id
+        /// </summary>
+        /// <returns></returns>
+        public string Id { get; set; } = Guid.NewGuid().ToString("N");
+
+        /// <summary>
+        /// Code
+        /// </summary>
+        public string Code { get; set; } = Guid.NewGuid().ToString("N");
+
+        /// <summary>
+        /// Create time
+        /// </summary>
+        public DateTime CreateTime { get; set; } = DateTime.UtcNow;
+
+        /// <summary>
+        /// Update time
+        /// </summary>
+        public DateTime UpdateTime { get; set; } = DateTime.UtcNow;
+
+        /// <summary>
+        /// Is delete
+        /// </summary>
+        public bool IsDelete { get; set; } = false;
+
+        /// <summary>
+        /// 创建团队
+        /// </summary>
+        /// <value></value>
+        public string CreatedTeamCode { get; set; }
+
+        /// <summary>
+        /// 创建医生
+        /// </summary>
+        /// <value></value>
+        public string CreatedDoctor { get; set; }
+
+        /// <summary>
+        /// 创建机构编码
+        /// </summary>
+        /// <value></value>
+        public string CreatedOrgCode { get; set; }
+    }
+}

+ 65 - 0
src/VitalMixtureService/DBService/Entities/CompletionRecordEntity.cs

@@ -0,0 +1,65 @@
+using System;
+
+namespace VitalService.Entities
+{
+    public class CompletionRecordEntity : BaseEntity
+    {
+        /// <summary>
+        /// 履约医生
+        /// </summary>
+        public string CompletionDoctor { get; set; }
+
+        /// <summary>
+        /// 履约居民
+        /// </summary>
+        public string PatientCode { get; set; }
+
+		/// <summary>
+		/// 服务包装代码
+		/// </summary>
+		/// <value></value>
+		public string ServicePackCode { get; set; }
+
+		/// <summary>
+		/// 服务包装名称
+		/// </summary>
+		/// <value></value>
+		public string ServicePackName { get; set; }
+
+		/// <summary>
+		/// 服务商品代码
+		/// </summary>
+		/// <value></value>
+		public string ServiceItemCode { get; set; }
+        
+		/// <summary>
+		/// 服务商品名称
+		/// </summary>
+		/// <value></value>
+		public string ServiceItemName { get; set; }
+
+        /// <summary>
+        /// 履约内容
+        /// </summary>
+        /// <value></value>
+        public string CompletionContent { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <value></value>
+        public string Notes { get; set; }
+
+        /// <summary>
+        /// 履约日期
+        /// </summary>
+        /// <value></value>
+        public DateTime CompletionTime { get; set; }
+
+        /// <summary>
+        /// 下次履约日期
+        /// </summary>
+        /// <value></value>
+        public DateTime NextCompletionTime { get; set; }
+    }
+}

+ 90 - 0
src/VitalMixtureService/DBService/Entities/ContractRecordEntity.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class ContractRecordEntity : BaseEntity
+    {
+        /// <summary>
+        /// 协议编号
+        /// </summary>
+        public string ContractRecordNo { get; set; }
+
+        /// <summary>
+        /// 签约状态
+        /// </summary>
+        public ContractStateEnum ContractState { get; set; }
+
+        /// <summary>
+        /// 是否生效
+        /// </summary>
+        public bool ContractIsValid { get; set; }
+
+        /// <summary>
+        /// 签约医生
+        /// </summary>
+        public string ContractedDoctor { get; set; }
+
+        /// <summary>
+        /// 签约人
+        /// </summary>
+        public string ContractedPatient { get; set; }
+
+        /// <summary>
+		/// 已签约团队
+		/// </summary>
+		/// <value></value>
+		public string ContractedTeam { get; set; }
+
+        /// <summary>
+        /// 签约时间
+        /// </summary>
+        public DateTime ContractedTime { get; set; } = DateTime.Now.Date;
+
+        /// <summary>
+        /// 签约审核状态
+        /// </summary>
+        public AuditStateEnum AuditState { get; set; }
+
+        /// <summary>
+        /// 签约文件地址
+        /// </summary>
+        public string ContractedFileUrl { get; set; }
+
+        /// <summary>
+        /// 服务包
+        /// </summary>
+        public List<string> ServicePacks { get; set; }
+
+        /// <summary>
+        /// 服务开始时间
+        /// </summary>
+        /// <value></value>
+        public DateTime ServiceStartDate { get; set; }  
+        
+        /// <summary>
+        /// 服务结束时间
+        /// </summary>
+        /// <value></value>
+        public DateTime ServiceEndDate { get; set; }
+
+        /// <summary>
+        /// 照片
+        /// </summary>
+        /// <value></value>
+        public List<string> Photos { get; set; } 
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <value></value>
+        public string Notes { get; set; } 
+
+        /// <summary>
+        /// 原因
+        /// </summary>
+        /// <value></value>
+        public string Reason { get; set; }
+    }
+}

+ 21 - 0
src/VitalMixtureService/DBService/Entities/ContractTemplateEntity.cs

@@ -0,0 +1,21 @@
+
+namespace VitalService.Entities
+{
+    public class ContractTemplateEntity : BaseEntity
+    {
+        /// <summary>
+        /// Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// Template Name
+        /// </summary>
+        public string TemplateName { get; set; }
+
+        /// <summary>
+        /// Template Content
+        /// </summary>
+        public string TemplateContent { get; set; }
+    }
+}

+ 105 - 0
src/VitalMixtureService/DBService/Entities/DeviceEntity.cs

@@ -0,0 +1,105 @@
+using System.Collections.Generic;
+using System;
+
+namespace VitalService.Entities
+{
+    public class DeviceEntity : BaseEntity
+    {
+        
+        /// <summary>
+        /// 设备唯一码
+        /// </summary>
+        /// <value>0000</value>
+        public string UniqueCode { get; set; }
+
+        /// <summary>
+        /// 序列号(物理唯一码)
+        /// </summary>
+        /// <value>0000-1234</value>
+        public string SerialNumber { get; set; }
+
+        /// <summary>
+        /// 型号
+        /// </summary>
+        /// <value>健康一体机V2</value>
+        public string Model { get; set; }
+
+        /// <summary>
+        /// 软件版本
+        /// </summary>
+        ///  <value>2.0.0.1</value>
+        public string SoftwareVersion { get; set; }
+
+        /// <summary>
+        /// 系统版本
+        /// </summary>
+        ///  <value>1.0.0.1</value>
+        public string OSVersion { get; set; }
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        ///  <value>第一个组织</value>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 组织代码
+        /// </summary>
+        /// <value></value>
+        /// <value>090990</value>
+        public string OrganizationCode { get; set; }
+
+        /// <summary>
+        /// 团队代码
+        /// </summary>
+        /// <value></value>
+        public string TeamCode { get; set; }
+
+        /// <summary>
+        /// 外设设备权限
+        /// </summary>
+        public List<PeripheralDeviceEntity> PeripheralPermissions { get; set; }
+    }
+
+
+    /// <summary>
+    /// 外设设备
+    /// </summary>
+    public class PeripheralDeviceEntity
+    {
+        /// <summary>
+        /// 设备编码
+        /// </summary>
+        /// <value></value>
+        public string Code { get; set; } = Guid.NewGuid().ToString("N");
+
+        /// <summary>
+        /// 设备Key
+        /// </summary>
+        /// <value></value>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 外设设备名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 使能
+        /// </summary>
+        public bool Enable { get; set; }
+
+        /// <summary>
+        /// 创建医生
+        /// </summary>
+        /// <value></value>
+        public string CreatedDoctor { get; set; }
+
+        /// <summary>
+        /// 创建机构编码
+        /// </summary>
+        /// <value></value>
+        public string CreatedOrgCode { get; set; }
+
+    }
+}

+ 53 - 0
src/VitalMixtureService/DBService/Entities/DiagnosisEntity.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class DiagnosisEntity : BaseEntity
+    {
+        /// <summary>
+        /// 字典Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 居民编码
+        /// </summary>
+        public string PatientCode { get; set; }
+
+        /// <summary>
+        /// 医生编码
+        /// </summary>
+        public string DoctorCode { get; set; }
+
+        /// <summary>
+        /// 诊疗数据
+        /// </summary>
+        /// <value></value>
+        public Dictionary<string,string> DiagnosisData { get; set; }
+
+        /// <summary>
+        /// 诊疗时间
+        /// </summary>
+        /// <value></value>
+        public DateTime DiagnosisTime { get; set; }
+
+        /// <summary>
+        /// 客户端对应诊疗数据的Id,此Id用于确认上传的数据属于那一份诊疗数据
+        /// </summary>
+        /// <value></value>
+        public string AppDataId { get; set; }
+
+        /// <summary>
+        /// 体检号(健康体检专用)
+        /// </summary>
+        /// <value></value>
+        public string PhysicalExamNumber { get; set; }
+
+        /// <summary>
+        /// 检查code
+        /// </summary>
+        /// <value></value>
+        public string ExamCode { get; set; }
+    }
+}

+ 28 - 0
src/VitalMixtureService/DBService/Entities/DictionaryEntity.cs

@@ -0,0 +1,28 @@
+
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class DictionaryEntity : BaseEntity
+    {
+        /// <summary>
+        /// 字典键
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 字典名
+        /// </summary>
+        public string Name { get; set; }
+        
+        /// <summary>
+        /// 字典类型
+        /// </summary>
+        public DictionaryTypeEnum Type { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Description { get; set; }
+    }
+}

+ 16 - 0
src/VitalMixtureService/DBService/Entities/DynamicTypeEntity.cs

@@ -0,0 +1,16 @@
+
+namespace VitalService.Entities
+{
+    public class DynamicTypeEntity : BaseEntity
+    {
+        /// <summary>
+        /// 类型名称
+        /// </summary>
+        public string TypeName { get; set; }
+
+        /// <summary>
+        /// 标签类型字典
+        /// </summary>
+        public string TypeKey { get; set; }
+    }
+}

+ 59 - 0
src/VitalMixtureService/DBService/Entities/ExamEntity.cs

@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class ExamEntity : BaseEntity
+    {
+        /// <summary>
+        /// 批次号
+        /// </summary>
+        /// <value></value>
+        public string BatchNumber { get; set; }
+
+        /// <summary>
+        /// 字典Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 居民编码
+        /// </summary>
+        public string PatientCode { get; set; }
+
+        /// <summary>
+        /// 签约医生
+        /// </summary>
+        public string ContractedDoctor { get; set; }
+
+        /// <summary>
+        /// 体检信息
+        /// </summary>
+        /// <value></value>
+        public Dictionary<string, string> ExamData { get; set; }
+
+        /// <summary>
+        /// 体检状态
+        /// </summary>
+        /// <value></value>
+        public ExamStateEnum ExamState { get; set; }
+
+        /// <summary>
+        /// 模版编码
+        /// </summary>
+        /// <value></value>
+        public string TemplateCode { get; set; }
+
+        /// <summary>
+        /// 体检医生
+        /// </summary>
+        /// <value></value>
+        public string ExamDoctor { get; set; }
+
+        /// <summary>
+        /// 体检号(健康体检专用)
+        /// </summary>
+        /// <value></value>
+        public string PhysicalExamNumber { get; set; }
+    }
+}

+ 78 - 0
src/VitalMixtureService/DBService/Entities/FollowUpEntity.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class FollowUpEntity : BaseEntity
+    {
+        /// <summary>
+        /// 字典Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 居民编码
+        /// </summary>
+        public string PatientCode { get; set; }
+
+        /// <summary>
+        /// 签约医生
+        /// </summary>
+        public string ContractedDoctor { get; set; }
+
+        /// <summary>
+        /// 随访信息
+        /// </summary>
+        /// <value></value>
+        public Dictionary<string, string> FollowUpData { get; set; }
+
+        /// <summary>
+        /// 随访状态
+        /// </summary>
+        /// <value></value>
+        public FollowUpStateEnum FollowUpState { get; set; }
+
+        /// <summary>
+        /// 模版编码
+        /// </summary>
+        /// <value></value>
+        public string TemplateCode { get; set; }
+
+        /// <summary>
+        /// 本次随访时间
+        /// </summary>
+        /// <value></value>
+        public DateTime FollowUpTime { get; set; } = DateTime.UtcNow;
+
+        /// <summary>
+        /// 下次随访时间
+        /// </summary>
+        /// <value></value>
+        public DateTime NextFollowUpTime { get; set; } = DateTime.MinValue;
+
+        /// <summary>
+        /// 随访方式
+        /// </summary>
+        /// <value></value>
+        public FollowUpModeEnum FollowUpMode { get; set; }
+
+        /// <summary>
+        /// 随访照片
+        /// </summary>
+        /// <value></value>
+        public List<string> FollowUpPhotos { get; set; }
+
+        /// <summary>
+        /// 随访医生
+        /// </summary>
+        /// <value></value>
+        public string FollowUpDoctor { get; set; }
+
+        /// <summary>
+        /// 体检号(健康体检专用)
+        /// </summary>
+        /// <value></value>
+        public string PhysicalExamNumber { get; set; }
+    }
+}

+ 28 - 0
src/VitalMixtureService/DBService/Entities/IBaseEntity.cs

@@ -0,0 +1,28 @@
+using System;
+
+namespace VitalService.Entities
+{
+    public interface IBaseEntity
+    {
+        
+        /// <summary>
+        /// Code
+        /// </summary>
+        string Code { get; set; }
+
+        /// <summary>
+        /// Create time
+        /// </summary>
+        DateTime CreateTime { get; set; }
+
+        /// <summary>
+        /// Update time
+        /// </summary>
+        DateTime UpdateTime { get; set; }
+
+        /// <summary>
+        /// Is delete
+        /// </summary>
+        bool IsDelete { get; set; }
+    }
+}

+ 21 - 0
src/VitalMixtureService/DBService/Entities/LabelEntity.cs

@@ -0,0 +1,21 @@
+
+namespace VitalService.Entities
+{
+    public class LabelEntity : BaseEntity
+    {
+        /// <summary>
+        /// 标签名称
+        /// </summary>
+        public string LabelName { get; set; }
+
+        /// <summary>
+        /// 组织编码
+        /// </summary>
+        public string OrganizationCode { get; set; }
+
+        /// <summary>
+        /// 标签类型字典
+        /// </summary>
+        public string LabelTypeKey { get; set; }
+    }
+}

+ 39 - 0
src/VitalMixtureService/DBService/Entities/NotificationEntity.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class NotificationEntity : BaseEntity
+    {
+        /// <summary>
+        /// 通知序号
+        /// </summary>
+        /// <value></value>
+        public long NotificationNo { get; set; }
+
+        /// <summary>
+        /// 特定版本号
+        /// </summary>
+        /// <value></value>
+        public Version Version { get; set; }
+
+        /// <summary>
+        /// 特定设备
+        /// </summary>
+        /// <value></value>
+        public List<string> ApplicableEquipment { get; set; }
+
+        /// <summary>
+        /// 通知内容
+        /// </summary>
+        /// <value></value>
+        public string NotificationContent { get; set; }
+
+        /// <summary>
+        /// 通知类型
+        /// </summary>
+        /// <value></value>
+        public NotificationTypeEnum NotificationType { get; set; }
+    }
+}

+ 25 - 0
src/VitalMixtureService/DBService/Entities/OperationLogEntity.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace VitalService.Entities
+{
+    public class OperationLogEntity : BaseEntity
+    {
+        /// <summary>
+        /// 操作内容
+        /// </summary>
+        /// <value></value>
+        public string Operation { get; set; }
+
+        /// <summary>
+        /// 操作时间
+        /// </summary>
+        /// <value></value>
+        public DateTime OperationTime { get; set; }
+
+        /// <summary>
+        /// 操作类型
+        /// </summary>
+        /// <value></value>
+        public int OperationType { get; set; }
+    }
+}

+ 98 - 0
src/VitalMixtureService/DBService/Entities/OrganizationEntity.cs

@@ -0,0 +1,98 @@
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class OrganizationEntity : BaseEntity
+    {
+        /// <summary>
+        /// 省份编码
+        /// </summary>
+        /// <value></value>
+        public string ProvinceCode { get; set; }
+
+        /// <summary>
+        /// 城市编码
+        /// </summary>
+        /// <value></value>
+        public string CityCode { get; set; }
+
+        /// <summary>
+        /// 区编码
+        /// </summary>
+        /// <value></value>
+        public string DistrictCode { get; set; }
+
+        /// <summary>
+        /// 乡镇编码
+        /// </summary>
+        /// <value></value>
+        public string TownCode { get; set; }
+
+        /// <summary>
+        /// 村、小区编码
+        /// </summary>
+        /// <value></value>
+        public string ResidenceCode { get; set; }
+
+        /// <summary>
+        /// 医院名称
+        /// </summary>
+        public string OrganizationName { get; set; }
+
+        /// <summary>
+        /// 联系电话
+        /// </summary>
+        public string ContactNumber { get; set; }
+
+        /// <summary>
+        /// 医院照片
+        /// </summary>
+        public string LogoUrl { get; set; }
+
+        /// <summary>
+        /// 医院地址
+        /// </summary>
+        public string Address { get; set; }
+
+        /// <summary>
+        /// 父级编码
+        /// </summary>
+        /// <value></value>
+        public string FatherCode { get; set; }
+
+        /// <summary>
+        /// 权限编码集合
+        /// </summary>
+        public List<string> FeatureCodes { get; set; }
+
+        /// <summary>
+        /// 顾客类型
+        /// </summary>
+        /// <value></value>
+        public CustomTypeEnum CustomType { get; set; }
+
+        /// <summary>
+        /// 可使用的设备Key集合
+        /// </summary>
+        public List<string> PeripheralDeviceKeys { get; set; }
+
+        /// <summary>
+		/// 动态参数配置
+		/// </summary>
+		/// <value></value>
+		public string DynamicParameter { get; set; }
+
+        /// <summary>
+        /// 体检地区码(3位)
+        /// </summary>
+        /// <value></value>
+        public string OrganizationUniqueCode { get; set; }
+
+        /// <summary>
+        /// 体检项目集合
+        /// </summary>
+        /// <value></value>
+        public List<string> ExamItemCodes { get; set; }
+    }
+}

+ 100 - 0
src/VitalMixtureService/DBService/Entities/PatientEntity.cs

@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class PatientEntity : BaseEntity
+    {
+        /// <summary>
+        /// 档案编号
+        /// </summary>
+        public string RecordNo { get; set; }
+
+        /// <summary>
+        /// 姓名
+        /// </summary>
+        public string PatientName { get; set; }
+
+        /// <summary>
+        /// 联系电话
+        /// </summary>
+        public string Phone { get; set; }
+
+        /// <summary>
+        /// 紧急联系人手机号
+        /// </summary>
+        public string EmergencyPhone { get; set; }
+
+        /// <summary>
+        /// 证件号
+        /// </summary>
+        public string CardNo { get; set; }
+
+        /// <summary>
+        /// 民族
+        /// </summary>
+        /// <value></value>
+        public string Nationality { get; set; }
+
+        /// <summary>
+        /// 生日
+        /// </summary>
+        /// <value></value>
+        public DateTime Birthday { get; set; }
+
+        /// <summary>
+        /// 人群分类
+        /// </summary>
+        /// <value></value>
+        public List<string> CrowdLabels { get; set; }
+
+        /// <summary>
+        /// 证件类型
+        /// </summary>
+        /// <value></value>
+        public CardTypeEnum CardType { get; set; }
+
+        /// <summary>
+        /// 性别
+        /// </summary>
+        /// <value></value>
+        public GenderEnum PatientGender { get; set; }
+
+        /// <summary>
+        /// 现住地址
+        /// </summary>
+        /// <value></value>
+        public string PatientAddress { get; set; }
+
+        /// <summary>
+        /// 户籍地址
+        /// </summary>
+        /// <value></value>
+        public string PermanentResidenceAddress { get; set; }
+
+        /// <summary>
+        /// 所属负责区域
+        /// </summary>
+        /// <value></value>
+        public string TeamRegionCode { get; set; }
+
+        /// <summary>
+        /// 签约医生
+        /// </summary>
+        /// <value></value>
+        public string ContractedDoctor { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        /// <value>0</value>
+        public PatientStatusEnum Status { get; set; }
+
+        /// <summary>
+        /// 照片
+        /// </summary>
+        /// <value></value>
+        public List<string> Photos { get;set; }
+    }
+}

+ 23 - 0
src/VitalMixtureService/DBService/Entities/PatientExtensionEntity.cs

@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class PatientExtensionEntity : BaseEntity
+    {
+        /// <summary>
+        /// 居民编码
+        /// </summary>
+        public string PatientCode { get; set; }
+
+        /// <summary>
+        /// Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 扩展信息
+        /// </summary>
+        /// <value></value>
+        public Dictionary<string,string> ExtensionData { get; set; }
+    }
+}

+ 79 - 0
src/VitalMixtureService/DBService/Entities/ReportEntity.cs

@@ -0,0 +1,79 @@
+
+
+using WingInterfaceLibrary.Enum.VitalEnum;
+using WingInterfaceLibrary.Request.DBVitalRequest;
+
+namespace VitalService.Entities
+{
+    public class ReportEntity : BaseEntity
+    {
+        /// <summary>
+        /// 字典Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 居民编码
+        /// </summary>
+        public string PatientCode { get; set; }
+
+        /// <summary>
+        /// 签约医生
+        /// </summary>
+        public string ContractedDoctor { get; set; }
+
+        /// <summary>
+        /// 体检信息
+        /// </summary>
+        /// <value></value>
+        public Dictionary<string,string> ReportData { get; set; }
+
+        /// <summary>
+        /// 体检信息数据
+        /// </summary>
+        /// <value></value>
+        public string ReportDataJson { get; set; }
+
+        /// <summary>
+        /// 体检模板数据
+        /// </summary>
+        /// <value></value>
+        public string ReportTemplateJson { get; set; }
+
+		/// <summary>
+		/// 报告状态
+		/// </summary>
+		/// <value></value>
+		public ReportStateEnum ReportState { get; set; }
+
+        /// <summary>
+        /// 模版编码
+        /// </summary>
+        /// <value></value>
+        public string TemplateCode { get; set; }
+
+        /// <summary>
+        /// 预览信息
+        /// </summary>
+        /// <value></value>
+        public PreviewDTO PreviewInfo { get; set; }        
+
+        /// <summary>
+        /// 体检号(健康体检专用)
+        /// </summary>
+        /// <value></value>
+        public string PhysicalExamNumber { get; set; }
+
+        /// <summary>
+        /// 检查code
+        /// </summary>
+        /// <value></value>
+        public string ExamCode { get; set; }
+
+        /// <summary>
+        /// 报告信息列表
+        /// </summary>
+        /// <value></value>
+        public IList<PreviewDTO> PreviewList { get; set; }    
+    }
+}

+ 17 - 0
src/VitalMixtureService/DBService/Entities/ResidenceEntity.cs

@@ -0,0 +1,17 @@
+
+namespace VitalService.Entities
+{
+    public class ResidenceEntity : BaseEntity
+    {
+        /// <summary>
+        /// 乡镇编码
+        /// </summary>
+        /// <value></value>
+        public string TownCode { get; set; }
+
+        /// <summary>
+        /// 区域名称
+        /// </summary>
+        public string Name { get; set; }
+    }
+}

+ 22 - 0
src/VitalMixtureService/DBService/Entities/RoleEntity.cs

@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class RoleEntity : BaseEntity
+    {
+        /// <summary>
+        /// 角色名称
+        /// </summary>
+        public string RoleName { get; set; }
+
+        /// <summary>
+        /// 权限编码集合
+        /// </summary>
+        public List<string> FeatureCodes { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Description { get; set; }
+    }
+}

+ 54 - 0
src/VitalMixtureService/DBService/Entities/ScheduleEntity.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    /// <summary>
+    ///日程
+    /// </summary>
+    public class ScheduleEntity:BaseEntity
+    {
+        /// <summary>
+        /// 日程标题
+        /// </summary>
+        /// <value></value>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 日程状态
+        /// </summary>
+        /// <value></value>
+        public TransactionStatusEnum Status { get; set; }
+
+        /// <summary>
+        /// 日程关联类型
+        /// </summary>
+        /// <value></value>
+        public ScheduleTypeEnum ScheduleType { get; set; }
+
+        /// <summary>
+        /// 日程开始时间
+        /// </summary>
+        /// <value></value>
+        public DateTime StartTime { get; set; }
+
+        /// <summary>
+        /// 日程结束时间
+        /// </summary>
+        /// <value></value>
+        public DateTime EndTime { get; set; }
+
+        /// <summary>
+        /// 关联业务事项的编码
+        /// </summary>
+        /// <value></value>
+        public string RelevanceCode { get; set; }
+        
+        /// <summary>
+        /// 参与人员编码集合
+        /// </summary>
+        /// <value></value>
+        public List<string> UserCodes { get; set; }=new List<string>();
+    }
+}

+ 58 - 0
src/VitalMixtureService/DBService/Entities/ServiceItemEntity.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    /// <summary>
+    /// 服务项信息
+    /// </summary>
+    public class ServiceItemEntity : BaseEntity
+    {
+
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 服务项内容
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// 服务项类型
+        /// </summary>
+        public ServiceItemTypeEnum ServiceItemType { get; set; }
+        
+        /// <summary>
+        /// 服务次数
+        /// </summary>
+        public string ServiceNumber { get; set; }
+
+        /// <summary>
+        /// 服务科室
+        /// </summary>
+        public string Department { get; set; }
+
+        /// <summary>
+        /// 指导价格
+        /// </summary>
+        public string GuidancePrice { get; set; }
+
+        /// <summary>
+        /// 拟调价格
+        /// </summary>
+        public string AdjustedPrice { get; set; }
+
+        /// <summary>
+        /// 总价格
+        /// </summary>
+        public string TotalPrice { get; set; }
+
+        /// <summary>
+        /// 收费标准说明
+        /// </summary>
+        public string PriceExplanation { get; set; }
+    }
+}

+ 36 - 0
src/VitalMixtureService/DBService/Entities/ServicePackEntity.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using WingInterfaceLibrary.Enum.VitalEnum;
+namespace VitalService.Entities
+{
+    /// <summary>
+    /// 服务包
+    /// </summary>
+    public class ServicePackEntity : BaseEntity
+    {
+        /// <summary>
+        /// 服务包名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 服务包类型
+        /// </summary>
+        public ServicePackTypeEnum ServicePackType{ get; set; }
+
+        /// <summary>
+        /// 服务包内容
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// 服务项Id集合
+        /// </summary>
+        public List<string> Items { get; set; }
+
+        /// <summary>
+        /// 人群标签
+        /// </summary>
+        public List<string> Labels{ get; set; }
+    }
+}

+ 32 - 0
src/VitalMixtureService/DBService/Entities/StatisticEntity.cs

@@ -0,0 +1,32 @@
+
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class StatisticEntity : BaseEntity
+    {
+        /// <summary>
+        /// 统计Key
+        /// </summary>
+        /// <value></value>
+        public string StatisticKey { get; set; }
+
+        /// <summary>
+        /// 统计类型
+        /// </summary>
+        /// <value></value>
+        public StatisticTypeEnum StatisticType { get; set; }
+
+        /// <summary>
+        /// 统计时间
+        /// </summary>
+        /// <value></value>
+        public string Time { get; set; }
+
+        /// <summary>
+        /// 统计数据
+        /// </summary>
+        /// <value></value>
+        public string StatisticData { get; set; } 
+    }
+}

+ 16 - 0
src/VitalMixtureService/DBService/Entities/SystemSetting.cs

@@ -0,0 +1,16 @@
+
+namespace VitalService.Entities
+{
+    public class SystemSettingEntity : BaseEntity
+    {
+        /// <summary>
+        /// 配置字典
+        /// </summary>
+        public string SettingKey { get; set; }
+
+        /// <summary>
+        /// 配置内容
+        /// </summary>
+        public string SettingContent { get; set; }
+    }
+}

+ 34 - 0
src/VitalMixtureService/DBService/Entities/TeamEntity.cs

@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class TeamEntity : BaseEntity
+    {
+        /// <summary>
+        /// 团队名称
+        /// </summary>
+        public string TeamName { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 组织编码
+        /// </summary>
+        public string OrganizationCode { get; set; }
+
+        /// <summary>
+        /// 团队成员
+        /// </summary>
+        /// <value></value>
+        public List<string> Members { get; set; }
+
+        /// <summary>
+        /// 负责人
+        /// </summary>
+        /// <value></value>
+        public string Principal { get; set; }
+    }
+}

+ 20 - 0
src/VitalMixtureService/DBService/Entities/TeamRegionEntity.cs

@@ -0,0 +1,20 @@
+namespace VitalService.Entities
+{
+    public class TeamRegionEntity : BaseEntity
+    {
+        /// <summary>
+        /// 团队编码
+        /// </summary>
+        public string TeamCode { get; set; }
+
+        /// <summary>
+        /// 区域完整名称
+        /// </summary>
+        public string FullName { get; set; }
+
+        /// <summary>
+        /// 最小区域编码
+        /// </summary>
+        public string RegionCode { get; set; }
+    }
+}

+ 28 - 0
src/VitalMixtureService/DBService/Entities/TemplateEntity.cs

@@ -0,0 +1,28 @@
+
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class TemplateEntity : BaseEntity
+    {
+        /// <summary>
+        /// Template Name
+        /// </summary>
+        public string TemplateName { get; set; }
+
+        /// <summary>
+        /// Template Type
+        /// </summary>
+        public TemplateTypeEnum TemplateType { get; set; }
+
+        /// <summary>
+        /// Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// Template Content
+        /// </summary>
+        public string TemplateContent { get; set; }
+    }
+}

+ 65 - 0
src/VitalMixtureService/DBService/Entities/TokenEntity.cs

@@ -0,0 +1,65 @@
+using System;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class TokenEntity : BaseEntity
+    {
+        /// <summary>
+        /// The token version
+        /// </summary>
+        /// <value></value>
+        public int Version { get; set; }
+        /// <summary>
+        /// The Account Type of logined client
+        /// </summary>
+        /// <value></value>
+        public AccountType AccountType { get; set; }
+        /// <summary>
+        /// The Account name
+        /// </summary>
+        /// <value></value>
+        public string AccountName { get; set; } = string.Empty;
+        /// <summary>
+        /// The login source of account
+        /// </summary>
+        /// <value></value>
+        public LoginSource LoginSource { get; set; }
+
+        /// <summary>
+        /// The Client Id(User code , admin code or device code)
+        /// </summary>
+        /// <value></value>
+        public string ClientId { get; set; }
+
+        /// <summary>
+        /// The Login server url
+        /// </summary>
+        /// <value></value>
+        public string LoginServer { get; set; }
+
+        /// <summary>
+        /// Token expiretion time
+        /// </summary>
+        /// <value></value>
+        public DateTime Expiration { get; set; }
+
+        /// <summary>
+        /// The client ip address
+        /// </summary>
+        /// <value></value>
+        public long IpValue { get; set; }
+
+        /// <summary>
+        /// The token online state
+        /// </summary>
+        /// <value></value>
+        public bool IsOnline { get; set; }
+
+        /// <summary>
+        /// 安装版本
+        /// </summary>
+        /// <value></value>
+        public string InstallVersion { get; set; }
+    }
+}

+ 28 - 0
src/VitalMixtureService/DBService/Entities/TownEntity.cs

@@ -0,0 +1,28 @@
+namespace VitalService.Entities
+{
+    public class TownEntity : BaseEntity
+    {
+        /// <summary>
+        /// 省份编码
+        /// </summary>
+        /// <value></value>
+        public string ProvinceCode { get; set; }
+
+        /// <summary>
+        /// 城市编码
+        /// </summary>
+        /// <value></value>
+        public string CityCode { get; set; }
+
+        /// <summary>
+        /// 区编码
+        /// </summary>
+        /// <value></value>
+        public string DistrictCode { get; set; }
+
+        /// <summary>
+        /// 乡镇名称
+        /// </summary>
+        public string Name { get; set; }
+    }
+}

+ 38 - 0
src/VitalMixtureService/DBService/Entities/UpgradeEntity.cs

@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class UpgradeEntity : BaseEntity
+    {
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        /// <value></value>
+        public Version Version { get; set; }
+
+        /// <summary>
+        /// 更新日志
+        /// </summary>
+        /// <value></value>
+        public string UpgradeNotes { get; set; }
+
+        /// <summary>
+        /// 更新文件
+        /// </summary>
+        /// <value></value>
+        public string UpgradeFileUrl { get; set; }
+
+        /// <summary>
+        /// 适用设备
+        /// </summary>
+        /// <value></value>
+        public List<string> ApplicableEquipment { get; set; }
+
+        /// <summary>
+        /// 是否灰度发布
+        /// </summary>
+        /// <value></value>
+        public bool IsGatedLaunch { get; set; }
+    }
+}

+ 66 - 0
src/VitalMixtureService/DBService/Entities/UserEntity.cs

@@ -0,0 +1,66 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class UserEntity : BaseEntity
+    {
+        /// <summary>
+        /// 用户名
+        /// </summary>
+        public string UserName { get; set; }
+
+        /// <summary>
+        /// 联系电话
+        /// </summary>
+        public string Phone { get; set; }
+
+        /// <summary>
+        /// 证件号
+        /// </summary>
+        public string CardNo { get; set; }
+
+        /// <summary>
+        /// 用户姓名
+        /// </summary>
+        public string RealName { get; set; }
+
+        /// <summary>
+        /// 头像
+        /// </summary>
+        public string HeadImageToken { get; set; }
+
+        /// <summary>
+        /// 所属组织
+        /// </summary>
+        public string OrganizationCode { get; set; }
+
+        /// <summary>
+        /// 团队编码
+        /// </summary>
+        /// <value>RootOrg000001</value>
+        public string TeamCode { get; set; }
+
+        /// <summary>
+        /// 角色编码
+        /// </summary>
+        public string RoleCode { get; set; }
+
+        /// <summary>
+        /// 负责区域
+        /// </summary>
+        /// <value></value>
+        public List<string> ResidenceCodes { get; set; }
+
+        /// <summary>
+        /// 职位职称
+        /// </summary>
+        /// <value></value>
+        public string RankName { get; set; }
+
+        /// <summary>
+        /// 医生签名
+        /// </summary>
+        /// <value></value>
+        public string Signature { get; set; }
+    }
+}

+ 48 - 0
src/VitalMixtureService/DBService/Entities/UserFeatureEntity.cs

@@ -0,0 +1,48 @@
+using System;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class UserFeatureEntity : BaseEntity
+    {
+        /// <summary>
+        /// 权限名称
+        /// </summary>
+        public string FeatureName { get; set; }
+
+        /// <summary>
+        /// 外显名称
+        /// </summary>
+        public string FeatureShowName { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Description { get; set; }
+
+        /// <summary>
+        /// 父级code
+        /// </summary>
+        /// <value></value>
+        public string FatherCode { get; set; }
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        /// <value></value>
+        public int Sort { get; set; } 
+
+        /// <summary>
+        /// 应用类型
+        /// </summary>
+        /// <value></value>
+        public ApplicationTypeEnum AppType { get; set; }
+
+        /// <summary>
+        /// 权限类型
+        /// </summary>
+        /// <value></value>
+        public FeatureTypeEnum FeatureType { get; set; }
+
+    }
+}

+ 18 - 0
src/VitalMixtureService/DBService/Entities/UserPasswordEntity.cs

@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entities
+{
+    public class UserPasswordEntity : BaseEntity
+    {
+        /// <summary>
+        /// 密码
+        /// </summary>
+        public string SecretPassword { get; set; }
+
+        /// <summary>
+        /// 最近使用过的密码
+        /// </summary>
+        /// <value></value>
+        public List<string> RecentlyUsedPassword { get; set; }
+    }
+}

+ 25 - 0
src/VitalMixtureService/DBService/Entity/BaseDataEntity.cs

@@ -0,0 +1,25 @@
+using VitalService.Entities;
+
+namespace VitalService.Entity
+{
+    public class BaseDataEntity<T> where T : IBaseEntity
+    {  
+        /// <summary>
+        /// 实际业务数据
+        /// </summary>
+        /// <value></value>
+        public T Data { get; set; }
+
+        /// <summary>
+        /// 扩展字段
+        /// </summary>
+        /// <value></value>
+        public string ExtendsData { get; set; }
+
+        public BaseDataEntity(IBaseEntity data, string extendsData)
+        {
+            Data = (T)data;
+            ExtendsData = extendsData;
+        }
+    }
+}

+ 88 - 0
src/VitalMixtureService/DBService/Entity/CodeCreator.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Text;
+using WingServerCommon.Utilities;
+
+namespace VitalService.Entity
+{
+    public class CodeCreator
+    {
+        private CodeCreator(){}
+
+        /// <summary>
+        /// 生成单个随机数字
+        /// </summary>
+        private static int CreateNum()
+        {
+            Random random = new Random(Guid.NewGuid().GetHashCode());
+            int num = random.Next(10);
+            return num;
+        }
+    
+        /// <summary>
+        /// 生成单个大写随机字母
+        /// </summary>
+        private static string CreateBigAbc()
+        {
+            //A-Z的 ASCII值为65-90
+            Random random = new Random(Guid.NewGuid().GetHashCode());
+            int num = random.Next(65, 91);
+            string abc = Convert.ToChar(num).ToString();
+            return abc;
+        }
+    
+        /// <summary>
+        /// 生成单个小写随机字母
+        /// </summary>
+        private static string CreateSmallAbc()
+        {
+            //a-z的 ASCII值为97-122
+            Random random = new Random(Guid.NewGuid().GetHashCode());
+            int num = random.Next(97, 123);
+            string abc = Convert.ToChar(num).ToString();
+            return abc;
+        }
+
+        /// <summary>
+        /// 生成随机字符串
+        /// </summary>
+        /// <param name="length">字符串的长度</param>
+        /// <returns></returns>
+        public static string CreateRandomStr(int length)
+        {
+            // 创建一个StringBuilder对象存储密码
+            StringBuilder sb = new StringBuilder();
+            //使用for循环把单个字符填充进StringBuilder对象里面变成14位密码字符串
+            for (int i = 0; i < length; i++)
+            {
+                Random random = new Random(Guid.NewGuid().GetHashCode());
+                //随机选择里面其中的一种字符生成
+                switch (random.Next(3))
+                {
+                    case 0:
+                        //调用生成生成随机数字的方法
+                        sb.Append(CreateNum());
+                        break;
+                    case 1:
+                        //调用生成生成随机小写字母的方法
+                        sb.Append(CreateSmallAbc());
+                        break;
+                    case 2:
+                        //调用生成生成随机大写字母的方法
+                        sb.Append(CreateBigAbc());
+                        break;
+                }
+            }
+            return sb.ToString();
+        }
+
+        /// <summary>
+        /// 创建编码
+        /// </summary>
+        /// <param name="prefix"></param>
+        /// <returns></returns>
+        public static string CreateCode(string prefix)
+        {
+            return IdHelper.Generate<string>();
+        }
+    }
+}

+ 28 - 0
src/VitalMixtureService/DBService/Entity/LogEntryDO.cs

@@ -0,0 +1,28 @@
+using System;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Attributes;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Entities
+{
+    public class LogEntry
+    {
+        public ObjectId Id { get; set; }
+
+        [BsonRepresentation(BsonType.String)]
+        public LogEventLevel Level { get; set; }
+
+        public DateTime Timestamp { get; set; }
+
+        public string UtcTimestamp { get; set; }
+
+        public string MessageTemplate { get; set; }
+
+        public string RenderedMessage { get; set; }
+
+        public BsonDocument Properties { get; set; }
+
+        public BsonDocument Exception { get; set; }
+
+    }
+}

+ 15 - 0
src/VitalMixtureService/DBService/Entity/MongoDataItem.cs

@@ -0,0 +1,15 @@
+namespace VitalService.Entity
+{
+    public sealed class MongoDataItem
+    {
+        /// <summary>
+        /// Key
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// Value
+        /// </summary>
+        public string Value { get; set; }
+    }
+}

+ 12 - 0
src/VitalMixtureService/DBService/Entity/MongoPlatform.cs

@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entity
+{
+    public sealed class MongoPlatform
+    {
+        /// <summary>
+        /// Platform items
+        /// </summary>
+        public HashSet<MongoDataItem> PlatformItems { get; set; } = new HashSet<MongoDataItem>();
+    }
+}

+ 12 - 0
src/VitalMixtureService/DBService/Entity/MongoQuery.cs

@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace VitalService.Entity
+{
+    public sealed class MongoQuery
+    {
+        /// <summary>
+        /// Query items
+        /// </summary>
+        public HashSet<MongoDataItem> QueryItems { get; set; } = new HashSet<MongoDataItem>();
+    }
+}

+ 55 - 0
src/VitalMixtureService/DBService/Entity/MongoTable.cs

@@ -0,0 +1,55 @@
+using System;
+using VitalService.Entities;
+
+namespace VitalService.Entity
+{
+    public sealed class MongoTable
+    {
+        public string Id { get; set; } = Guid.NewGuid().ToString("N");
+
+        /// <summary>
+        /// 平台相关数据,记录平台类型、标识、特性 + 自定义数据
+        /// </summary>
+        public MongoPlatform PlatformData { get; set; }
+
+        /// <summary>
+        /// 查询关键数据,查询关键字列表+自定义数据
+        /// </summary>
+        public MongoQuery QueryData { get; set; }
+
+        /// <summary>
+        /// 基础数据,存放基本数据对象,数据为Json或自定义加密格式
+        /// </summary>
+        public IBaseEntity BaseData { get; set; }
+
+        /// <summary>
+        /// 扩展数据,存放扩展数据对象,数据为Json或自定义加密格式
+        /// </summary>
+        public string ExtendsData { get; set; }
+    }
+
+    public class MongoTableBase<T> where T : IBaseEntity
+    {
+        public string Id { get; set; } = Guid.NewGuid().ToString("N");
+
+        /// <summary>
+        /// 平台相关数据,记录平台类型、标识、特性 + 自定义数据
+        /// </summary>
+        public MongoPlatform PlatformData { get; set; }
+
+        /// <summary>
+        /// 查询关键数据,查询关键字列表+自定义数据
+        /// </summary>
+        public MongoQuery QueryData { get; set; }
+
+        /// <summary>
+        /// 基础数据,存放基本数据对象,数据为Json或自定义加密格式
+        /// </summary>
+        public T BaseData { get; set; }
+
+        /// <summary>
+        /// 扩展数据,存放扩展数据对象,数据为Json或自定义加密格式
+        /// </summary>
+        public string ExtendsData { get; set; }
+    }
+}

+ 27 - 0
src/VitalMixtureService/DBService/Job/DataPullingJobs/DataPullingJobBase.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Threading.Tasks;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    public abstract class DataPullingJobBase : IJob
+    {
+        public DateTime UpdateTime { get; set; }
+        public DateTime LastRunTime { get; set; } = DateTime.Now;
+        public string JobName { get; set; } = "DataPullingJobBase";
+        public DataPullingTypeEnum DataPullingType { get; set; }
+        public string CronExpression { get; set; } = "0 5/10 * * * *";
+
+
+        public virtual async Task<bool> ExecuteAsync(string requestData, DateTime lastCreateTime)
+        {
+            if(lastCreateTime > UpdateTime)
+            {
+                //TODO 数据拉取公共逻辑
+                UpdateTime = lastCreateTime;
+            }
+            LastRunTime = DateTime.Now;
+            return await Task.FromResult(true);
+        }
+    }
+}

+ 369 - 0
src/VitalMixtureService/DBService/Job/DataPullingJobs/VNoteDiagnosisDataPullingJob.cs

@@ -0,0 +1,369 @@
+using System.Net.Http.Headers;
+using System.Text;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using JsonRpcLite.Log;
+using MongoDB.Driver;
+using Newtonsoft.Json.Linq;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using VitalService.Config;
+using WingServerCommon.Config.Parameters;
+using WingInterfaceLibrary.Enum.VitalEnum;
+using WingInterfaceLibrary.Internal.Request;
+
+namespace VitalService.Job
+{
+    public class VNoteDiagnosisDataPullingJob : DataPullingJobBase
+    {
+        private string vnoteHospitalCode = "608808D45A42B34EF3B6D8D0A94C04E0";
+        private string vnoteTeamCode = "B58E994AF5A356DBEA21FC1087B3890A";
+        private string vnoteUserCode = "8404B000976740D4CC9FAF99FF7698F1";
+        private IEncrypt _encryptInstance = new DBEncryptHelper();
+        private AnalyzeConfigDBRepository _analyzeConfigDBRepository = DBRepositoryFactory.GetRepository<AnalyzeConfigDBRepository>();
+        private DiagnosisDBRepository _diagnosisDBRepository = DBRepositoryFactory.GetRepository<DiagnosisDBRepository>();
+        private string _OldVersionApi => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldVersionApi").Value;
+        private string _OldAccount => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldAccount").Value;
+        private string _OldPassword => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldPassword").Value;
+        private readonly string _jobPath = string.Empty;
+        private readonly string _diagnosisQueuePath = string.Empty;
+        private readonly string _errorPath = string.Empty;
+        private readonly string _tokenFilePath = string.Empty;
+        private List<AnalyzeConfig> analyzeConfigsList = new();
+        private string _vnoteToken = string.Empty;
+        public VNoteDiagnosisDataPullingJob()
+        {
+            JobName = "VNoteDiagnosisDataPullingJob";
+            CronExpression = "0 0/1 * * * *";
+            DataPullingType = DataPullingTypeEnum.Simple;
+            _jobPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Job");
+            _diagnosisQueuePath = Path.Combine(_jobPath, "DiagnosisQueue");
+            Directory.CreateDirectory(_diagnosisQueuePath);
+            _errorPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Error");
+            Directory.CreateDirectory(_errorPath);
+            _tokenFilePath = Path.Combine(_jobPath, "token.txt");
+            InitAnalyzeConfig();
+        }
+        private void InitAnalyzeConfig()
+        {
+            var analyzeFilter = Builders<AnalyzeConfigEntity>.Filter.Empty;
+            var analyzeConfigs = _analyzeConfigDBRepository.FindAllAsync(analyzeFilter).Result;
+            foreach (var analyzeConfig in analyzeConfigs)
+            {
+                var newAnalyzeConfig = new AnalyzeConfig
+                {
+                    InField = analyzeConfig.InField,
+                    OutField = analyzeConfig.OutField,
+                    Mode = analyzeConfig.Mode,
+                    Template = analyzeConfig.Template,
+                    AnalyzeConfigItems = JsonSerializer.Deserialize<List<AnalyzeConfigItem>>(analyzeConfig.AnalyzeConfigItems),
+                };
+                analyzeConfigsList.Add(newAnalyzeConfig);
+            }
+        }
+
+        private async Task<string> GetDiagnosisAsync(string data, string inField, string outField)
+        {
+            if (!string.IsNullOrWhiteSpace(data))
+            {
+                var analyzeConfig = analyzeConfigsList.FirstOrDefault(f => f.InField == inField && f.OutField == outField);
+                if (analyzeConfig != null)
+                {
+                    return await AnalyzeStrategy.GetAnalyzeResult(data, analyzeConfig);
+                }
+            }
+            return string.Empty;
+        }
+
+        public override async Task<bool> ExecuteAsync(string requestData, DateTime lastCreateTime)
+        {
+            if (string.IsNullOrWhiteSpace(_vnoteToken))
+            {
+                _vnoteToken = File.ReadAllText(_tokenFilePath);
+            }
+            if (string.IsNullOrWhiteSpace(_vnoteToken)) return false;
+            var queueFiles = Directory.GetFiles(_diagnosisQueuePath, "*.queue");
+            using var httpClient = new HttpClient();
+            httpClient.Timeout = new TimeSpan(0, 0, 2, 0);
+            httpClient.DefaultRequestHeaders.Add("Accept", "*/*");
+            httpClient.DefaultRequestHeaders.Add("Host", _OldVersionApi.Replace("http://", "").Replace("https://", ""));
+            httpClient.DefaultRequestHeaders.Add("User-Agent", "VNoteServer");
+            httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
+            httpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
+            foreach (var queue in queueFiles)
+            {
+                try
+                {
+                    var patientJson = File.ReadAllText(queue);
+                    if (string.IsNullOrWhiteSpace(patientJson)) continue;
+                    VNotePatient patient = JsonSerializer.Deserialize<VNotePatient>(patientJson);
+                    if (patient == null) continue;
+                    DateTime.TryParse(patient.RegistTime, out DateTime startDate);
+                    var patientNo = Path.GetFileNameWithoutExtension(queue);
+                    var serverApiUrl = $"{_OldVersionApi}/api/vinno/sync/syncrecord?page=1&startDate={startDate.AddDays(-10).Date}&endDate={startDate.AddDays(10).Date}&pageSize=200&cardId={patient.CardNo}";
+                    var syncData = await PostRequest(httpClient, serverApiUrl, string.Empty, _vnoteToken);
+                    if (syncData.statusCode == ((int)System.Net.HttpStatusCode.Unauthorized).ToString())
+                    {
+                        _vnoteToken = GetVNoteToken(httpClient, true).Result;
+                        syncData = await PostRequest(httpClient, serverApiUrl, string.Empty, _vnoteToken);
+                    }
+                    if (!string.IsNullOrWhiteSpace(syncData.data))
+                    {
+                        syncData.data = Regex.Replace(syncData.data, "\"Total\":[\\s]*\"([0-9]+)\"", ReplaceTotal);
+                        var data = JsonSerializer.Deserialize<VNotePageResult<VNoteHealthData>>(syncData.data);
+                        if (data != null && data.Data != null && data.Data.Any())
+                        {
+                            bool isHappenError = false;
+                            foreach (var item in data.Data)
+                            {
+                                if (patientNo == item.PatientNo)
+                                {
+                                    if (item == null || string.IsNullOrWhiteSpace(item.CardNo)) continue;
+                                    var diagnosisFilter = Builders<DiagnosisEntity>.Filter.Eq(x => x.AppDataId, item.PatientNo);
+                                    var existsDiagnosis = await _diagnosisDBRepository.Exists(diagnosisFilter);
+                                    if (!existsDiagnosis && (item.National == null || item.Address == null))
+                                    {
+                                        try
+                                        {
+                                            var diagnosisEntity = new DiagnosisEntity();
+                                            diagnosisEntity.AppDataId = item.PatientNo;
+                                            diagnosisEntity.PatientCode = item.CardNo;
+                                            diagnosisEntity.DoctorCode = vnoteUserCode;
+                                            diagnosisEntity.CreatedDoctor = vnoteUserCode;
+                                            diagnosisEntity.CreatedOrgCode = vnoteHospitalCode;
+                                            diagnosisEntity.CreatedTeamCode = vnoteTeamCode;
+                                            if (DateTime.TryParse(item.CreatedTime, out DateTime diagnosisTime))
+                                            {
+                                                DateTime.SpecifyKind(diagnosisTime, DateTimeKind.Utc);
+                                                diagnosisEntity.DiagnosisTime = diagnosisTime;
+                                            }
+                                            var insertDiagnosisData = async (string itemData, string name) =>
+                                            {
+                                                try
+                                                {
+                                                    if (!string.IsNullOrWhiteSpace(itemData))
+                                                    {
+                                                        var diagnosisData = await GetDiagnosisAsync(itemData, $"{name}Pull", name);
+                                                        if (!string.IsNullOrWhiteSpace(diagnosisData))
+                                                        {
+                                                            diagnosisEntity.DiagnosisData = new Dictionary<string, string> { { "Data", diagnosisData } };
+                                                            diagnosisEntity.Key = name;
+                                                            diagnosisEntity.Id = Guid.NewGuid().ToString("N");
+                                                            diagnosisEntity.Code = Guid.NewGuid().ToString("N");
+                                                            await _diagnosisDBRepository.InsertOneAsync(diagnosisEntity);
+                                                            Logger.WriteInfo($"添加居民检测数据{item.CardNo}_{name}成功!");
+                                                        }
+                                                        try
+                                                        {
+                                                            var keys = new List<string> { "NIBP", "SpO2", "Heart" };
+                                                            if (keys.Contains(name))
+                                                            {
+                                                                var diagnosisFilter = Builders<DiagnosisEntity>.Filter.Where(f => f.AppDataId == diagnosisEntity.AppDataId && f.PatientCode == diagnosisEntity.PatientCode);
+                                                                diagnosisFilter &= Builders<DiagnosisEntity>.Filter.In(f => f.Key, keys);
+                                                                var diagnosis = await _diagnosisDBRepository.FindAllAsync(diagnosisFilter);
+                                                                var nibp = diagnosis.FirstOrDefault(w => w.Key == "NIBP");
+                                                                var spo2 = diagnosis.FirstOrDefault(w => w.Key == "SpO2");
+                                                                var twelveHeart = diagnosis.FirstOrDefault(w => w.Key == "TwelveHeart");
+                                                                var heart = diagnosis.FirstOrDefault(w => w.Key == "Heart");
+                                                                var breatheData = new Dictionary<string, string>();
+                                                                var felidName = string.Empty;
+                                                                if (nibp != null && nibp.DiagnosisData.Count > 0 && !string.IsNullOrWhiteSpace(nibp.DiagnosisData["Data"]))
+                                                                {
+                                                                    breatheData = nibp.DiagnosisData;
+                                                                    felidName = "Pulse_Beat";
+                                                                }
+                                                                else if (twelveHeart != null && twelveHeart.DiagnosisData.Count > 0 && !string.IsNullOrWhiteSpace(twelveHeart.DiagnosisData["Data"]))
+                                                                {
+                                                                    breatheData = twelveHeart.DiagnosisData;
+                                                                    felidName = "HEART12";
+                                                                }
+                                                                else if (heart != null && heart.DiagnosisData.Count > 0 && !string.IsNullOrWhiteSpace(heart.DiagnosisData["Data"]))
+                                                                {
+                                                                    breatheData = heart.DiagnosisData;
+                                                                    felidName = "HEART";
+                                                                }
+                                                                else if (spo2 != null && spo2.DiagnosisData.Count > 0 && !string.IsNullOrWhiteSpace(spo2.DiagnosisData["Data"]))
+                                                                {
+                                                                    breatheData = spo2.DiagnosisData;
+                                                                    felidName = "Pulse_Frequency";
+                                                                }
+                                                                if (breatheData.Count > 0)
+                                                                {
+                                                                    var data = breatheData["Data"];
+                                                                    if (!string.IsNullOrWhiteSpace(data))
+                                                                    {
+                                                                        JObject obj = JObject.Parse(data);
+                                                                        var beat = obj[felidName]?.Value<int>();
+                                                                        if (beat != null && beat > 0)
+                                                                        {
+                                                                            var breatheExistsFilter = Builders<DiagnosisEntity>.Filter.Where(f => f.AppDataId == diagnosisEntity.AppDataId && f.PatientCode == diagnosisEntity.PatientCode && f.Key == "Breathe");
+                                                                            var breatheExists = await _diagnosisDBRepository.FindOneAsync(breatheExistsFilter);
+                                                                            if(breatheExists==null)
+                                                                            {
+                                                                                diagnosisEntity.Key = "Breathe";
+                                                                                diagnosisEntity.Id = Guid.NewGuid().ToString("N");
+                                                                                diagnosisEntity.Code = Guid.NewGuid().ToString("N");
+                                                                                diagnosisEntity.DiagnosisData = new Dictionary<string, string> { { "Data", $"{{\"Breathe\":\"{beat / 4}\"}}" } };
+                                                                                await _diagnosisDBRepository.InsertOneAsync(diagnosisEntity);
+                                                                                Logger.WriteInfo($"添加呼吸频率数据{item.CardNo}_{name}成功!");
+                                                                            }
+                                                                            else
+                                                                            {
+                                                                                var updateFilter = Builders<DiagnosisEntity>.Filter.Eq(f => f.Code, breatheExists.Code);
+                                                                                var updateDefinition = Builders<DiagnosisEntity>.Update.Set(f => f.DiagnosisData, new Dictionary<string, string> { { "Data", $"{{\"Breathe\":\"{beat / 4}\"}}" } });
+                                                                                await _diagnosisDBRepository.UpdateOneAsync(updateFilter, updateDefinition);
+                                                                                Logger.WriteInfo($"更新呼吸频率数据{item.CardNo}_{name}成功!");
+                                                                            }
+                                                                        }
+                                                                    }
+                                                                }
+                                                            }
+                                                        }
+                                                        catch (Exception ex)
+                                                        {
+                                                            Logger.WriteError($"SubmitDiagnosisAsync InsertOrUpdate Breathe error{ex}");
+                                                        }
+                                                    }
+                                                }
+                                                catch (Exception ex)
+                                                {
+                                                    isHappenError = true;
+                                                    Logger.WriteError($"解析数据失败,Name:{name},error:{ex}");
+                                                    File.WriteAllText(Path.Combine(_errorPath, $"{item.CardNo}_{name}.txt"), itemData);
+                                                }
+                                            };
+                                            await insertDiagnosisData(item.BloodFat, "BloodFat");
+                                            await insertDiagnosisData(item.BoolSugar, "GLU");
+                                            await insertDiagnosisData(item.BodyFat, "BodyFat");
+                                            await insertDiagnosisData(item.Heart, "Heart");
+                                            await insertDiagnosisData(item.Lung, "Lung");
+                                            await insertDiagnosisData(item.Nibp, "NIBP");
+                                            await insertDiagnosisData(item.Spo2, "SpO2");
+                                            await insertDiagnosisData(item.Temp, "Temp");
+                                            await insertDiagnosisData(item.TwelveHeart, "TwelveHeart");
+                                            await insertDiagnosisData(item.Urine, "Urine");
+                                            await insertDiagnosisData(item.Weight, "BMI");
+                                            await insertDiagnosisData(item.WHB, "WHB");
+                                        }
+                                        catch (Exception ex)
+                                        {
+                                            isHappenError = true;
+                                            Logger.WriteError($"添加居民检测数据{item.CardNo}_{item.Name}失败!错误内容:{ex}");
+                                        }
+                                    }
+                                }
+                            }
+                            if (!isHappenError)
+                            {
+                                var queueFile = Path.Combine(_diagnosisQueuePath, $"{patientNo}.queue");
+                                File.Delete(queueFile);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        Logger.WriteError($"请求错误Code:{syncData.statusCode},Result:{syncData.data}");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Logger.WriteError($"添加居民检测数据失败!错误内容:{ex}");
+                }
+            }
+            return await base.ExecuteAsync(requestData, lastCreateTime);
+        }
+
+        private string ReplaceTotal(Match match)
+        {
+            if(match.Success)
+            {
+                if(match.Groups.Count>1)
+                {
+                    return $"\"Total\":{match.Groups[1].Value}"; 
+                }
+            }
+            return match.Value;
+        }
+
+        private async Task<string> GetVNoteToken(HttpClient httpClient, bool isForced = false)
+        {
+            if (!isForced && File.Exists(_tokenFilePath))
+            {
+                return File.ReadAllText(_tokenFilePath);
+            }
+            var serverApiUrl = $"{_OldVersionApi}/api/identity/token";
+            var req = $"{{\"grantType\":\"password\",\"account\":\"{_OldAccount}\",\"password\":\"{_OldPassword}\",\"clientType\":\"3\"}}";
+            var result = await PostRequest(httpClient, serverApiUrl, req);
+            if (!string.IsNullOrWhiteSpace(result.data))
+            {
+                dynamic tokenInfo = JObject.Parse(result.data);
+                if (tokenInfo != null && tokenInfo.Data != null)
+                {
+                    File.WriteAllText(_tokenFilePath, (string)tokenInfo.Data.AccessToken);
+                    return tokenInfo.Data.AccessToken;
+                }
+            }
+            return string.Empty;
+        }
+
+        private async Task<(string statusCode, string data)> GetRequest(HttpClient httpClient, string serverApiUrl, string req, string token = "")
+        {
+            if (!string.IsNullOrWhiteSpace(token))
+            {
+                httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {token}");
+            }
+            var syncData = await httpClient.GetAsync(serverApiUrl);
+            var statusCode = ((int)syncData.StatusCode).ToString();
+            var result = await syncData.Content.ReadAsStringAsync();
+            return (statusCode, result);
+        }
+
+        private async Task<(string statusCode, string data)> PostRequest(HttpClient httpClient, string serverApiUrl, string req, string token = "")
+        {
+            var stringContent = new StringContent(req, Encoding.UTF8, "application/json");
+            if (!string.IsNullOrWhiteSpace(token))
+            {
+                httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse($"Bearer {token}");
+            }
+            var syncData = await httpClient.PostAsync(serverApiUrl, stringContent);
+            var statusCode = ((int)syncData.StatusCode).ToString();
+            var result = await syncData.Content.ReadAsStringAsync();
+            return (statusCode, result);
+        }
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="entity"></param>
+        /// <returns></returns>
+        private PatientEntity Encrypt(PatientEntity entity)
+        {
+            if (!string.IsNullOrWhiteSpace(entity.CardNo))
+            {
+                entity.CardNo = _encryptInstance.Encrypt(entity.CardNo);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PatientAddress))
+            {
+                entity.PatientAddress = _encryptInstance.Encrypt(entity.PatientAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PermanentResidenceAddress))
+            {
+                entity.PermanentResidenceAddress = _encryptInstance.Encrypt(entity.PermanentResidenceAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PatientName))
+            {
+                entity.PatientName = _encryptInstance.Encrypt(entity.PatientName);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.Phone))
+            {
+                entity.Phone = _encryptInstance.Encrypt(entity.Phone);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.EmergencyPhone))
+            {
+                entity.EmergencyPhone = _encryptInstance.Encrypt(entity.EmergencyPhone);
+            }
+            return entity;
+        }
+    }
+}

+ 258 - 0
src/VitalMixtureService/DBService/Job/DataPullingJobs/VNotePatientDataPullingJob.cs

@@ -0,0 +1,258 @@
+using System.Collections.Concurrent;
+using System.Text;
+using System.Text.Json;
+using System.Text.RegularExpressions;
+using JsonRpcLite.Log;
+using MongoDB.Driver;
+using Newtonsoft.Json.Linq;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using VitalService.Config;
+using WingServerCommon.Config.Parameters;
+using WingInterfaceLibrary.Enum.VitalEnum;
+using WingInterfaceLibrary.Internal.Request;
+
+namespace VitalService.Job
+{
+    public class VNotePatientDataPullingJob : DataPullingJobBase
+    {
+        private string vnoteHospitalCode = "608808D45A42B34EF3B6D8D0A94C04E0";
+        private string vnoteTeamCode = "B58E994AF5A356DBEA21FC1087B3890A";
+        private string vnoteUserCode = "8404B000976740D4CC9FAF99FF7698F1";
+        private IEncrypt _encryptInstance = new DBEncryptHelper();
+        private PatientDBRepository _patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+        private string _OldVersionApi => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldVersionApi").Value;
+        private string _OldAccount => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldAccount").Value;
+        private string _OldPassword => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldPassword").Value;
+        private string _vnoteToken = string.Empty;
+        private int _currentPage = 1;
+        private readonly string _jobPath = string.Empty;
+        private readonly string _indexPath = string.Empty;
+        private readonly string _tokenFilePath = string.Empty;
+        private readonly string _diagnosisQueuePath = string.Empty;
+        private int _pageSize = 1000;
+        private ConcurrentDictionary<string, string> _patientNoDictionary = new();
+        public VNotePatientDataPullingJob()
+        {
+            JobName = "VNotePatientDataPullingJob";
+            CronExpression = "0 0/1 * * * *";
+            DataPullingType = DataPullingTypeEnum.Simple;
+            _jobPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Job");
+            _diagnosisQueuePath = Path.Combine(_jobPath, "DiagnosisQueue");
+            Directory.CreateDirectory(_diagnosisQueuePath);
+            _indexPath = Path.Combine(_jobPath, "PatientPullingJobIndex.txt");
+            _tokenFilePath = Path.Combine(_jobPath, "token.txt");
+            _vnoteToken = GetVNoteToken().Result;
+        }
+        public override async Task<bool> ExecuteAsync(string requestData, DateTime lastCreateTime)
+        {
+            foreach(var patinetNoInfo in _patientNoDictionary.ToArray())
+            {
+                if(patinetNoInfo.Value != DateTime.Now.Date.ToString("yyyyMMdd"))
+                {
+                    _patientNoDictionary.TryRemove(patinetNoInfo.Key, out _);
+                }
+            }
+            if (File.Exists(_indexPath))
+            {
+                var indexContent = File.ReadAllText(_indexPath);
+                if(indexContent.Contains(','))
+                {
+                    var pageIndexContent = indexContent.Split(',');
+                    if (int.TryParse(pageIndexContent[0], out int pageIndex))
+                    {
+                        _currentPage = pageIndex;
+                    }
+                    if (int.TryParse(pageIndexContent[1], out int pageSize))
+                    {
+                        _pageSize = pageSize;
+                    }
+                }
+            }
+            var serverApiUrl = $"{_OldVersionApi}/api/vinno/HealthRegist/Read";
+            var syncData = await PostRequest(serverApiUrl, $"{{\"PageCondition\":{{\"PageIndex\": {_currentPage},\"PageSize\": {_pageSize}}}}}", _vnoteToken);
+            if (syncData.statusCode == ((int)System.Net.HttpStatusCode.Unauthorized).ToString())
+            {
+                _vnoteToken = GetVNoteToken(true).Result;
+                //syncData = await PostRequest(serverApiUrl, $"{{\"PageCondition\":{{\"PageIndex\": {_currentPage},\"PageSize\": 1000}},\"FilterGroup\":{{\"Rules\":[{{\"Field\":\"CreatedTime\",\"Value\":\"{_currentRegistTime:yyyy-MM-dd HH:mm:ss}\",\"Operate\":8}}]}}}}", _vnoteToken);
+                syncData = await PostRequest(serverApiUrl, $"{{\"PageCondition\":{{\"PageIndex\": {_currentPage},\"PageSize\": {_pageSize}}}}}", _vnoteToken);
+            }
+            if (!string.IsNullOrWhiteSpace(syncData.data))
+            {
+                syncData.data = Regex.Replace(syncData.data, "\"Total\":[\\s]*\"([0-9]+)\"", ReplaceTotal);
+                var data = JsonSerializer.Deserialize<VNotePageResult<VNotePatient>>(syncData.data);
+                if (data != null && data.Data != null && data.Data.Any())
+                {
+                    var maxTime = data.Data.Max(f=>{
+                        if (DateTime.TryParse(f.RegistTime, out DateTime registTime))
+                        {
+                            DateTime.SpecifyKind(registTime, DateTimeKind.Utc);
+                            return registTime;
+                        }
+                        else
+                        {
+                            return DateTime.MinValue;
+                        }
+                    });
+                    foreach (var item in data.Data)
+                    {
+                        if(_patientNoDictionary.ContainsKey(item.PatientNo)) continue;
+                        if (item == null || string.IsNullOrWhiteSpace(item.CardNo)) continue;
+                        var patientFilter = Builders<PatientEntity>.Filter.Eq(x => x.Code, item.CardNo);
+                        var existsPatient = await _patientDBRepository.Exists(patientFilter);
+                        if (!existsPatient)
+                        {
+                            try
+                            {
+                                var patientInfo = new PatientEntity();
+                                if (DateTime.TryParse(item.BirthDay, out DateTime birthday))
+                                {
+                                    DateTime.SpecifyKind(birthday, DateTimeKind.Utc);
+                                    patientInfo.Birthday = birthday;
+                                }
+                                if (DateTime.TryParse(item.RegistTime, out DateTime registTime))
+                                {
+                                    DateTime.SpecifyKind(registTime, DateTimeKind.Utc);
+                                    patientInfo.CreateTime = registTime;
+                                }
+                                patientInfo.Code = item.CardNo;
+                                patientInfo.PatientName = item.Name;
+                                patientInfo.Nationality = item.National;
+                                patientInfo.PatientAddress = item.Address;
+                                patientInfo.CardNo = item.CardNo;
+                                patientInfo.PatientGender = (GenderEnum)(item.Gender == "男" ? 1 : 2);
+                                patientInfo.UpdateTime = DateTime.UtcNow;
+                                patientInfo.CreatedDoctor = vnoteUserCode;
+                                patientInfo.CreatedOrgCode = vnoteHospitalCode;
+                                patientInfo.CreatedTeamCode = vnoteTeamCode;
+                                patientInfo = Encrypt(patientInfo);
+                                var result = await _patientDBRepository.InsertOneAsync(patientInfo);
+                                if(!string.IsNullOrWhiteSpace(result))
+                                {
+                                    Logger.WriteInfo($"添加居民{item.CardNo}_{item.Name}成功!");
+                                    var queueFile = Path.Combine(_diagnosisQueuePath, $"{item.PatientNo}.queue");
+                                    File.WriteAllText(queueFile, JsonSerializer.Serialize(item));
+                                    _patientNoDictionary.TryAdd(item.PatientNo, DateTime.Now.Date.ToString("yyyyMMdd"));
+                                }
+                            }
+                            catch(Exception ex)
+                            {
+                                Logger.WriteError($"添加居民{item.CardNo}_{item.Name}失败!错误内容:{ex}");
+                            }
+                        }
+                        else if(item.National==null || item.Address==null)
+                        {
+                            Logger.WriteInfo($"已存在居民{item.CardNo}_{item.Name}直接入列!");
+                            var queueFile = Path.Combine(_diagnosisQueuePath, $"{item.PatientNo}.queue");
+                            File.WriteAllText(queueFile, JsonSerializer.Serialize(item));
+                            _patientNoDictionary.TryAdd(item.PatientNo, DateTime.Now.Date.ToString("yyyyMMdd"));
+                        }
+                    }
+                    var dataCount = data.Data.Count();
+                    if(dataCount >= 1000)
+                    {
+                        _currentPage++;
+                        File.WriteAllText(_indexPath, $"{_currentPage},{1000}");
+                    }
+                    else
+                    {
+                        File.WriteAllText(_indexPath, $"1,100");
+                    }
+                }
+                else
+                {
+                    File.WriteAllText(_indexPath, $"1,100");
+                }
+            }
+            return await base.ExecuteAsync(requestData, lastCreateTime);
+        }
+
+        private string ReplaceTotal(Match match)
+        {
+            if(match.Success)
+            {
+                if(match.Groups.Count>1)
+                {
+                    return $"\"Total\":{match.Groups[1].Value}"; 
+                }
+            }
+            return match.Value;
+        }
+
+        private async Task<string> GetVNoteToken(bool isForced =false)
+        {
+            if(!isForced && File.Exists(_tokenFilePath))
+            {
+                return File.ReadAllText(_tokenFilePath);
+            }
+            var serverApiUrl = $"{_OldVersionApi}/api/identity/token";
+            var req = $"{{\"grantType\":\"password\",\"account\":\"{_OldAccount}\",\"password\":\"{_OldPassword}\",\"clientType\":\"3\"}}";
+            var result = await PostRequest(serverApiUrl, req);
+            if (!string.IsNullOrWhiteSpace(result.data))
+            {
+                dynamic tokenInfo = JObject.Parse(result.data);
+                if (tokenInfo != null && tokenInfo.Data != null)
+                {
+                    File.WriteAllText(_tokenFilePath, (string)tokenInfo.Data.AccessToken);
+                    return tokenInfo.Data.AccessToken;
+                }
+            }
+            return string.Empty;
+        }
+
+        private async Task<(string statusCode, string data)> PostRequest(string serverApiUrl, string req, string token = "")
+        {
+            using var httpClient = new HttpClient();
+            httpClient.Timeout = new TimeSpan(0, 0, 0, 30);
+            httpClient.DefaultRequestHeaders.Add("Accept", "*/*");
+            httpClient.DefaultRequestHeaders.Add("Host", _OldVersionApi.Replace("http://","").Replace("https://",""));
+            httpClient.DefaultRequestHeaders.Add("User-Agent", "VNoteServer");
+            httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
+            httpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
+            var stringContent = new StringContent(req, Encoding.UTF8, "application/json");
+            if (!string.IsNullOrWhiteSpace(token))
+            {
+                httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
+            }
+            var syncData = await httpClient.PostAsync(serverApiUrl, stringContent);
+            var statusCode = ((int)syncData.StatusCode).ToString();
+            var result = await syncData.Content.ReadAsStringAsync();
+            return (statusCode, result);
+        }
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="entity"></param>
+        /// <returns></returns>
+        private PatientEntity Encrypt(PatientEntity entity)
+        {
+            if (!string.IsNullOrWhiteSpace(entity.CardNo))
+            {
+                entity.CardNo = _encryptInstance.Encrypt(entity.CardNo);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PatientAddress))
+            {
+                entity.PatientAddress = _encryptInstance.Encrypt(entity.PatientAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PermanentResidenceAddress))
+            {
+                entity.PermanentResidenceAddress = _encryptInstance.Encrypt(entity.PermanentResidenceAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.PatientName))
+            {
+                entity.PatientName = _encryptInstance.Encrypt(entity.PatientName);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.Phone))
+            {
+                entity.Phone = _encryptInstance.Encrypt(entity.Phone);
+            }
+            if (!string.IsNullOrWhiteSpace(entity.EmergencyPhone))
+            {
+                entity.EmergencyPhone = _encryptInstance.Encrypt(entity.EmergencyPhone);
+            }
+            return entity;
+        }
+    }
+}

+ 14 - 0
src/VitalMixtureService/DBService/Job/IJob.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Threading.Tasks;
+
+namespace VitalService.Job
+{
+    public interface IJob
+    {
+        DateTime UpdateTime { get; set; }
+        DateTime LastRunTime { get; set; }
+        string JobName { get; }
+        string CronExpression { get; }
+        Task<bool> ExecuteAsync(string data, DateTime lastCreateTime);
+    }
+}

+ 110 - 0
src/VitalMixtureService/DBService/Job/JobQueue.cs

@@ -0,0 +1,110 @@
+using System.Collections.Concurrent;
+using System.Reflection;
+using JsonRpcLite.Log;
+using NCrontab;
+using VitalService.Config;
+using WingServerCommon.Config.Parameters;
+
+namespace VitalService.Job
+{
+    public class JobQueue
+    {
+        private string _exclusionsJob => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "ExclusionsJob").Value;
+        private ConcurrentQueue<IJob> _queue = new ConcurrentQueue<IJob>();
+        private CancellationToken _cancellationToken;
+        public int GetWaitTime()
+        {
+            return 100/(_queue.Count>0? _queue.Count:1);
+        }
+
+        public JobQueue(string baseTypeName)
+        {
+            Assembly assembly = Assembly.GetAssembly(typeof(IJob));
+            Type[] types = assembly.GetTypes();
+
+            foreach (Type type in types)
+            {
+                if (IsJobImplementation(type, baseTypeName))
+                {
+                    var job = Activator.CreateInstance(type);
+                    _queue.Enqueue((IJob)job);
+                }
+            }
+            _cancellationToken = CancellationToken.None;
+            Start(_cancellationToken).ConfigureAwait(false);
+        }
+
+        public Task Start(CancellationToken cancellationToken)
+        {
+            return Task.Run(
+                async () =>
+                {
+                    while (true)
+                    {
+                        if (_queue.TryDequeue(out IJob job))
+                        {
+                            try
+                            {
+                                // 创建一个Cron表达式解析器
+                                CrontabSchedule schedule = CrontabSchedule.Parse(job.CronExpression, new CrontabSchedule.ParseOptions{ IncludingSeconds = true });
+                                // 获取下一个执行时间
+                                DateTime nextRun = schedule.GetNextOccurrence(job.LastRunTime);
+                                if(
+                                    nextRun < DateTime.Now
+                                    && nextRun > job.LastRunTime
+                                )
+                                {
+                                    await job.ExecuteAsync(string.Empty, DateTime.MinValue).ConfigureAwait(false);
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                Logger.WriteError($"Execute job {job.JobName} error {ex}");
+                            }
+                            finally
+                            {
+                                _queue.Enqueue(job);  
+                                await Task.Delay(GetWaitTime());
+                            }
+                        }
+                    }
+                },
+                cancellationToken
+            );
+        }
+        private bool IsJobImplementation(Type type, string baseTypeName)
+        {
+            if(!string.IsNullOrWhiteSpace(_exclusionsJob))
+            {
+                var exclusionsJob = _exclusionsJob.Split(',',StringSplitOptions.RemoveEmptyEntries);
+                if(exclusionsJob.Any(x=>x.Trim() == type.Name))
+                {
+                    return false;
+                }
+            }
+            if(type.BaseType?.Name == baseTypeName)
+            {
+                if(GetJobInterfaceType(type)!=null)
+                {
+                    return type.IsClass && !type.IsAbstract;
+                }
+            }
+            return false;
+        }
+
+        private Type GetJobInterfaceType(Type implementationType)
+        {
+            Type[] interfaces = implementationType.GetInterfaces();
+
+            foreach (Type interfaceType in interfaces)
+            {
+                if (interfaceType == typeof(IJob))
+                {
+                    return interfaceType;
+                }
+            }
+
+            return null;
+        }
+    }
+}

+ 484 - 0
src/VitalMixtureService/DBService/Job/ReportSendJobs/ReportDiagnosisDataJob.cs

@@ -0,0 +1,484 @@
+using System.Text.Json;
+using JsonRpcLite.Log;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingServerCommon.Config.Parameters;
+using WingServerCommon.Mapper;
+using VitalService.Config;
+using WingInterfaceLibrary.Enum.VitalEnum;
+using WingInterfaceLibrary.DTO.Vital;
+using WingInterfaceLibrary.Request;
+
+namespace VitalService.Job
+{
+    public class ReportDiagnosisDataJob : ReportSendJobBase
+    {
+        private IEncrypt _encryptInstance = new DBEncryptHelper();
+        private AnalyzeConfigDBRepository _analyzeConfigDBRepository = DBRepositoryFactory.GetRepository<AnalyzeConfigDBRepository>();
+        private DiagnosisDBRepository _diagnosisDBRepository = DBRepositoryFactory.GetRepository<DiagnosisDBRepository>();
+        private UserDBRepository _userDBRepository = DBRepositoryFactory.GetRepository<UserDBRepository>();
+        private PatientDBRepository _patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+        private LabelDBRepository _labelDBRepository = DBRepositoryFactory.GetRepository<LabelDBRepository>();
+        private OrganizationDBRepository _organizationDBRepository = DBRepositoryFactory.GetRepository<OrganizationDBRepository>();
+        private ContractRecordDBRepository _contractRecordDBRepository = DBRepositoryFactory.GetRepository<ContractRecordDBRepository>();
+        private TeamDBRepository _teamDBRepository = DBRepositoryFactory.GetRepository<TeamDBRepository>();
+        private string _OldVersionApi => EnvironmentConfigManager.GetParammeter<StringParameter>("Incidental", "OldVersionApi").Value;
+        private List<AnalyzeConfig> analyzeConfigsList = new();
+        private ICache _fileCache = CacheCreator.GetCache<FileCache>();
+        public ReportDiagnosisDataJob()
+        {
+            JobName = "ReportDiagnosisDataJob";
+            CronExpression = "0/30 * * * * *";
+            ReportSendType = ReportSendTypeEnum.Simple;
+            InitAnalyzeConfig();
+        }
+
+        private void InitAnalyzeConfig()
+        {
+            var analyzeFilter = Builders<AnalyzeConfigEntity>.Filter.Empty;
+            var analyzeConfigs = _analyzeConfigDBRepository.FindAllAsync(analyzeFilter).Result;
+            foreach (var analyzeConfig in analyzeConfigs)
+            {
+                var newAnalyzeConfig = new AnalyzeConfig
+                {
+                    InField = analyzeConfig.InField,
+                    OutField = analyzeConfig.OutField,
+                    Mode = analyzeConfig.Mode,
+                    Template = analyzeConfig.Template,
+                    AnalyzeConfigItems = JsonSerializer.Deserialize<List<AnalyzeConfigItem>>(analyzeConfig.AnalyzeConfigItems),
+                };
+                analyzeConfigsList.Add(newAnalyzeConfig);
+            }
+            _fileCache.SetCache("analyzeConfigs", JsonSerializer.Serialize(analyzeConfigsList));
+        }
+
+        public override async Task<bool> ExecuteAsync(string reportData, DateTime lastCreateTime)
+        {
+            Logger.WriteInfo("ReportDiagnosisDataJob start");
+            try
+            {
+                lastCreateTime = await _diagnosisDBRepository.GetLastUpdateTime();
+                if (lastCreateTime > UpdateTime)
+                {
+                    var getGender = (GenderEnum gender) =>
+                    {
+                        switch (gender)
+                        {
+                            case GenderEnum.Male: return "男";
+                            case GenderEnum.Female: return "女";
+                            case GenderEnum.Unknown: return "未知";
+                            case GenderEnum.Unspecified: return "未说明的性别";
+                            default: return "未知";
+                        }
+                    };
+                    var getAge = (DateTime birthday) =>
+                    {
+                        var diffYears = DateTime.Now.Year - birthday.Year;
+                        if (diffYears < 0)
+                        {
+                            return 0;
+                        }
+                        return diffYears;
+                    };
+                    var getDiagnosios = async (DiagnosisAggregationRecord record, string inField, string outField) =>
+                    {
+                        try
+                        {
+                            var analyzeConfig = analyzeConfigsList.FirstOrDefault(f=>f.InField == inField && f.OutField == outField);
+                            if(analyzeConfig!=null)
+                            {
+                                var data = record.DiagnosisAggregationData?.FirstOrDefault(w => w.Key == inField)?.DiagnosisData;
+                                if (data == null) return string.Empty;
+                                return await AnalyzeStrategy.GetAnalyzeResult(data, analyzeConfig);
+                            }
+                            return string.Empty;
+                        }
+                        catch (Exception ex)
+                        {
+                            Logger.WriteError($"Analyze diagnosios {inField} error {ex}");
+                            return string.Empty;
+                        }
+                    };
+                    var lastUploadTimeRecordFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LastUpdateTime.txt");
+                    var lastUploadTime = DateTime.Now.Date;
+                    if (File.Exists(lastUploadTimeRecordFile))
+                    {
+                        var time = File.ReadAllText(lastUploadTimeRecordFile);
+                        lastUploadTime = DateTime.Parse(time);
+                    }
+                    var filter = Builders<DiagnosisEntity>.Filter.Where(x => x.IsDelete == false && x.DiagnosisData != null);
+                    var filterB = Builders<DiagnosisEntity>.Filter.Gt(x => x.UpdateTime, DateTime.Now.Date.ToUniversalTime());
+                    var filterC = Builders<DiagnosisEntity>.Filter.Regex(x => x.AppDataId, new MongoDB.Bson.BsonRegularExpression(@"^[0-9a-fA-F]{8}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{12}$"));
+                    var filterAll = Builders<DiagnosisEntity>.Filter.And(filter, filterB, filterC);
+                    var diagnosisData = await _diagnosisDBRepository.FindAllAsync(filterAll, new FindOptions<DiagnosisEntity> { Sort = Builders<DiagnosisEntity>.Sort.Descending(x => x.UpdateTime) });
+                    if (diagnosisData != null && diagnosisData.Count > 0)
+                    {
+                        var newUpdateTime = diagnosisData.Max(f => f.UpdateTime);
+                        if(newUpdateTime > lastUploadTime.ToUniversalTime())
+                        {
+                            var diagnosisAggregationData = await ConvertToAggregationRecordDTOPage(diagnosisData, 1, 99999);
+                            if (diagnosisAggregationData != null && diagnosisAggregationData.PageData != null && diagnosisAggregationData.PageData.Count > 0)
+                            {
+                                var httpClient = new HttpClient();
+                                var serverApiUrl = $"{_OldVersionApi}/api/vinno/Patient/syncrecord";
+                                foreach (var page in diagnosisAggregationData.PageData)
+                                {
+                                    if (page.DiagnosisAggregationData == null || page.DiagnosisAggregationData.Count == 0)
+                                    {
+                                        continue;
+                                    }
+                                    if (page.DiagnosisTime <= lastUploadTime.ToUniversalTime())
+                                    {
+                                        continue;
+                                    }
+                                    var dto = new RecordDto();
+                                    dto.Regist = new HealthRegistInDto
+                                    {
+                                        PatientNo = page.PatientCode,
+                                        Name = page.PatientName,
+                                        CardNo = page.CardNo,
+                                        Gender = getGender(page.PatientGender),
+                                        Age = getAge(page.Birthday).ToString(),
+                                        BirthDay = page.Birthday,
+                                        National = page.National,
+                                        Address = page.PatientAddress,
+                                        RegistTime = page.RegistTime
+                                    };
+                                    dto.Detail = new HealthDetailInDto
+                                    {
+                                        PatientNo = page.PatientCode,
+                                        BloodFat = await getDiagnosios(page, "BloodFat", "BloodFat"),
+                                        BoolSugar = await getDiagnosios(page, "GLU", "BoolSugar"),
+                                        BodyFat = await getDiagnosios(page, "BodyFat", "BodyFat"),
+                                        Heart = await getDiagnosios(page, "Heart", "Heart"),
+                                        Lung = await getDiagnosios(page, "Lung", "Lung"),
+                                        Nibp = await getDiagnosios(page, "NIBP", "Nibp"),
+                                        Spo2 = await getDiagnosios(page, "SpO2", "Spo2"),
+                                        Temp = await getDiagnosios(page, "Temp", "Temp"),
+                                        Urine = await getDiagnosios(page, "Urine", "Urine"),
+                                        TwelveHeart = await getDiagnosios(page, "TwelveHeart", "TwelveHeart"),
+                                        Weight = await getDiagnosios(page, "BMI", "Weight"),
+                                        WHB = await getDiagnosios(page, "WHB", "WHB"),
+                                    };
+
+                                    var postContent = JsonSerializer.Serialize(dto);
+                                    Logger.WriteInfo($"ReportDiagnosisDataJob post data {postContent}");
+                                    var formContent = new MultipartFormDataContent();
+                                    formContent.Add(new StringContent(postContent), "json");
+                                    var syncData = await httpClient.PostAsync(serverApiUrl, formContent);
+                                    var syncRes = await syncData.Content.ReadAsStringAsync();
+                                    Logger.WriteInfo($"ReportDiagnosisDataJob post result {syncRes}");
+                                }
+                                lastUploadTime = diagnosisData.Max(f => f.DiagnosisTime);
+                                File.WriteAllText(lastUploadTimeRecordFile, lastUploadTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss.fffffff"));
+                            }
+                        }
+                    }
+                }
+                Logger.WriteInfo($"ReportDiagnosisDataJob end");
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteError($"ReportDiagnosisDataJob error {ex}");
+            }
+            return await base.ExecuteAsync(reportData, lastCreateTime);
+        }
+
+        private async Task<PageCollection<DiagnosisAggregationRecord>> ConvertToAggregationRecordDTOPage(List<DiagnosisEntity> entitys, int pageIndex, int pageSize)
+        {
+            var ternaryFun = (DiagnosisEntity entity) => entity?.DiagnosisData?.Keys?.Contains("Data") == true ? entity.DiagnosisData["Data"] : string.Empty;
+            var groupData = entitys.OrderBy(o => o.DiagnosisTime).GroupBy(f => f.AppDataId);
+            int TotalCount = groupData.Count();
+            groupData = groupData.Skip((pageIndex - 1) * pageSize).Take(pageSize);
+            var aggregationRecord = groupData.Select(f => new DiagnosisAggregationRecord
+            {
+                AppDataId = f.Key,
+                DiagnosisTime = f.Max(f1 => f1.DiagnosisTime),
+                UpdateTime = f.Max(f1 => f1.UpdateTime),
+                PatientCode = f.LastOrDefault()?.PatientCode,
+                DoctorCode = f.LastOrDefault()?.DoctorCode,
+                DiagnosisAggregationData = f.GroupBy(g => g.Key).Select(s =>
+                {
+                    var data = ternaryFun(s.OrderBy(o => o.UpdateTime).FirstOrDefault());
+                    return new DiagnosisAggregationData
+                    {
+                        Key = s.Key,
+                        DiagnosisData = data
+                    };
+                }).ToList()
+            }).ToList();
+            if (aggregationRecord == null || aggregationRecord.Count == 0) return new PageCollection<DiagnosisAggregationRecord>
+            {
+                PageData = new List<DiagnosisAggregationRecord>(),
+                CurrentPage = pageIndex,
+                PageSize = pageSize,
+                DataCount = 0
+            };
+            var userCodes = entitys.Select(f => f.DoctorCode).Distinct();
+            var filterUsers = Builders<UserEntity>.Filter.In(f => f.Code, userCodes);
+            var usersInfo = await _userDBRepository.FindAllAsync(filterUsers);
+
+            var patientCodes = entitys.Select(f => f.PatientCode).Distinct();
+            var filterPatients = Builders<PatientEntity>.Filter.In(f => f.Code, patientCodes);
+            var patientsInfo = await _patientDBRepository.FindAllAsync(filterPatients);
+
+            var filterLabel = Builders<LabelEntity>.Filter.In(f => f.LabelTypeKey, new List<string> { "RQFL", "CJJB", "TSZG" });
+            var labels = await _labelDBRepository.FindAllAsync(filterLabel);
+
+            foreach (var entity in aggregationRecord)
+            {
+                if (!string.IsNullOrWhiteSpace(entity.DoctorCode))
+                {
+                    var userInfo = usersInfo.FirstOrDefault(w => w.Code == entity.DoctorCode);
+                    entity.DoctorName = !string.IsNullOrWhiteSpace(userInfo.RealName) ? userInfo.RealName : userInfo.UserName;
+                }
+                if (!string.IsNullOrWhiteSpace(entity.PatientCode))
+                {
+                    var patientInfo = patientsInfo.FirstOrDefault(w => w.Code == entity.PatientCode);
+                    if (patientInfo != null)
+                    {
+                        var dto = await ConvertToDTO(patientInfo);
+                        if (dto != null)
+                        {
+                            entity.RegistTime = UTCToBeijing(dto.CreateTime);
+                            entity.National = dto.Nationality;
+                            entity.PatientName = dto.PatientName;
+                            entity.Birthday = dto.Birthday;
+                            entity.CardNo = dto.CardNo;
+                            entity.Phone = dto.Phone;
+                            entity.PatientGender = dto.PatientGender;
+                            entity.PatientAddress = dto.PatientAddress;
+                        }
+                        entity.DiagnosisTime = entity.DiagnosisTime;
+                    }
+                }
+            }
+            return new PageCollection<DiagnosisAggregationRecord>
+            {
+                PageData = aggregationRecord,
+                CurrentPage = pageIndex,
+                PageSize = pageSize,
+                DataCount = TotalCount
+            };
+        }
+
+        private DateTime UTCToBeijing(DateTime utcTime)
+        {
+            // 获取中国标准时间 (CST) 的时区信息
+            TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
+            // 将UTC时间转换为北京时间
+            DateTime beijingTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, cstZone);
+            return beijingTime;
+        }
+
+
+        private async Task<PatientDTO> ConvertToDTO(PatientEntity entity)
+        {
+            if (entity == null) return null;
+            var dto = entity.MappingTo<PatientDTO>();
+            if (!string.IsNullOrWhiteSpace(entity.CreatedOrgCode))
+            {
+                var filter = Builders<OrganizationEntity>.Filter.Eq(f => f.Code, entity.CreatedOrgCode);
+                var org = await _organizationDBRepository.FindOneAsync(filter);
+                dto.CreatedOrgName = org?.OrganizationName;
+            }
+            if (!string.IsNullOrWhiteSpace(entity.CreatedTeamCode))
+            {
+                var filter = Builders<TeamEntity>.Filter.Eq(f => f.Code, entity.CreatedTeamCode);
+                var team = await _teamDBRepository.FindOneAsync(filter);
+                dto.CreatedTeamName = team?.TeamName;
+            }
+            if (!string.IsNullOrWhiteSpace(entity.Code))
+            {
+                var filter = Builders<ContractRecordEntity>.Filter.Eq(f => f.ContractedPatient, entity.Code);
+                var contractRecord = await _contractRecordDBRepository.FindOneAsync(filter);
+                if (!string.IsNullOrWhiteSpace(contractRecord?.ContractedDoctor))
+                {
+                    var filterUser = Builders<UserEntity>.Filter.Eq(f => f.Code, contractRecord?.ContractedDoctor);
+                    var userInfo = await _userDBRepository.FindOneAsync(filterUser);
+                    dto.ContractedDoctorName = !string.IsNullOrWhiteSpace(userInfo.RealName) ? userInfo.RealName : userInfo.UserName;
+                }
+            }
+            if (!string.IsNullOrWhiteSpace(entity.CreatedDoctor))
+            {
+                var filter = Builders<UserEntity>.Filter.Eq(f => f.Code, entity.CreatedDoctor);
+                var userInfo = await _userDBRepository.FindOneAsync(filter);
+                dto.CreatedDoctorName = !string.IsNullOrWhiteSpace(userInfo.RealName) ? userInfo.RealName : userInfo.UserName;
+            }
+            if (entity.CrowdLabels != null && entity.CrowdLabels.Count > 0)
+            {
+                var filterLabel = Builders<LabelEntity>.Filter.In(f => f.LabelTypeKey, new List<string> { "RQFL", "CJJB", "TSZG" });
+                var labels = await _labelDBRepository.FindAllAsync(filterLabel);
+                dto.LabelNames = labels?.Where(w => entity.CrowdLabels.Contains(w.Code)).Select(f => f.LabelName).ToList();
+            }
+            if (!string.IsNullOrWhiteSpace(entity.Code))
+            {
+                var contractFilter = Builders<ContractRecordEntity>.Filter.Eq(f => f.ContractedPatient, entity.Code);
+                var contract = await _contractRecordDBRepository.FindOneAsync(contractFilter);
+                dto.ContractState = contract?.ContractState ?? ContractStateEnum.Unsigned;
+            }
+            return Decrypt(dto);
+        }
+
+        /// <summary>
+        /// 解密
+        /// </summary>
+        /// <param name="entity"></param>
+        /// <returns></returns>
+        private PatientDTO Decrypt(PatientDTO dto)
+        {
+            if (!string.IsNullOrWhiteSpace(dto.CardNo))
+            {
+                dto.CardNo = _encryptInstance.Decrypt(dto.CardNo);
+            }
+            if (!string.IsNullOrWhiteSpace(dto.PatientAddress))
+            {
+                dto.PatientAddress = _encryptInstance.Decrypt(dto.PatientAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(dto.PermanentResidenceAddress))
+            {
+                dto.PermanentResidenceAddress = _encryptInstance.Decrypt(dto.PermanentResidenceAddress);
+            }
+            if (!string.IsNullOrWhiteSpace(dto.PatientName))
+            {
+                dto.PatientName = _encryptInstance.Decrypt(dto.PatientName);
+            }
+            if (!string.IsNullOrWhiteSpace(dto.Phone))
+            {
+                dto.Phone = _encryptInstance.Decrypt(dto.Phone);
+            }
+            return dto;
+        }
+    }
+
+    public class RecordDto
+    {
+        public HealthRegistInDto Regist { get; set; }
+
+        public HealthDetailInDto Detail { get; set; }
+    }
+
+    public class HealthRegistInDto
+    {
+        public Guid Id { get; set; } = Guid.NewGuid();
+
+        ///<summary>
+        /// 获取或设置 患者唯一编号
+        ///</summary>
+        public string PatientNo { get; set; }
+
+        /// <summary>
+        /// 登记时间
+        /// </summary>
+        public DateTime RegistTime { get; set; }
+
+        ///<summary>
+        /// 获取或设置 患者姓名
+        ///</summary>
+        public string Name { get; set; }
+
+        ///<summary>
+        /// 获取或设置 身份证号
+        ///</summary>
+        public string CardNo { get; set; }
+
+        /// <summary>
+        /// 获取或设置 性别
+        /// </summary>
+        public string Gender { get; set; }
+
+        /// <summary>
+        /// 获取或设置 年龄
+        /// </summary>
+        public string Age { get; set; }
+
+        ///<summary>
+        /// 获取或设置 出生日期
+        ///</summary>
+        public DateTime? BirthDay { get; set; }
+
+        ///<summary>
+        /// 获取或设置 民族
+        ///</summary>
+        public string National { get; set; }
+
+        ///<summary>
+        /// 获取或设置 地址
+        ///</summary>
+        public string Address { get; set; }
+
+    }
+
+    public class HealthDetailInDto
+    {
+        public Guid Id { get; set; } = Guid.NewGuid();
+
+        ///<summary>
+        /// 获取或设置 患者唯一编号
+        ///</summary>
+        public string PatientNo { get; set; }
+
+        /// <summary>
+        /// 获取或设置 血脂
+        /// </summary>
+        public string BloodFat { get; set; }
+
+        /// <summary>
+        /// 获取或设置 血糖
+        /// </summary>
+        public string BoolSugar { get; set; }
+
+        /// <summary>
+        /// 获取或设置 体脂
+        /// </summary>
+        public string BodyFat { get; set; }
+
+        /// <summary>
+        /// 获取或设置 心电
+        /// </summary>
+        public string Heart { get; set; }
+
+        /// <summary>
+        /// 获取或设置 肺活仪
+        /// </summary>
+        public string Lung { get; set; }
+
+        /// <summary>
+        /// 获取或设置 血压
+        /// </summary>
+        public string Nibp { get; set; }
+
+        /// <summary>
+        /// 获取或设置 血氧饱和
+        /// </summary>
+        public string Spo2 { get; set; }
+
+        /// <summary>
+        /// 获取或设置 体温
+        /// </summary>
+        public string Temp { get; set; }
+
+        /// <summary>
+        /// 获取或设置 12导联心电
+        /// </summary>
+        public string TwelveHeart { get; set; }
+
+        /// <summary>
+        /// 获取或设置 尿液分析仪
+        /// </summary>
+        public string Urine { get; set; }
+
+        /// <summary>
+        /// 获取或设置 体重身高比
+        /// </summary>
+        public string Weight { get; set; }
+
+        /// <summary>
+        /// 获取或设置 腰臀比
+        /// </summary>
+        public string WHB { get; set; }
+
+    }
+}

+ 27 - 0
src/VitalMixtureService/DBService/Job/ReportSendJobs/ReportSendJobBase.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Threading.Tasks;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    public abstract class ReportSendJobBase : IJob
+    {
+        public DateTime UpdateTime { get; set; }
+        public DateTime LastRunTime { get; set; } = DateTime.Now;
+        public string JobName { get; set; } = "ReportSendJobBase";
+        public ReportSendTypeEnum ReportSendType { get; set; }
+        public string CronExpression { get; set; } = "0 5/10 * * * *";
+
+
+        public virtual async Task<bool> ExecuteAsync(string reportData, DateTime lastCreateTime)
+        {
+            if(lastCreateTime > UpdateTime)
+            {
+                //TODO 报告推送公共逻辑
+                UpdateTime = lastCreateTime;
+            }
+            LastRunTime = DateTime.Now;
+            return await Task.FromResult(true);
+        }
+    }
+}

+ 58 - 0
src/VitalMixtureService/DBService/Job/StatisticJobs/CompletionRecordStatisticJob.cs

@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    /// <summary>
+    /// 签约覆盖率
+    /// </summary>
+    public class CompletionRecordStatisticJob : StatisticJobBase
+    {
+        public CompletionRecordStatisticJob()
+        {
+            JobName = "CompletionRecordStatisticJob";
+            CronExpression = "0 0/5 * * * *";
+            StatisticType = StatisticTypeEnum.Customer;
+        }
+        public override async Task<bool> ExecuteAsync(string statisticData, DateTime lastCreateTime)
+        {
+            var teamDB = DBRepositoryFactory.GetRepository<TeamDBRepository>();
+            var patientDB = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+            var contractRecordDB = DBRepositoryFactory.GetRepository<ContractRecordDBRepository>();
+            lastCreateTime = await contractRecordDB.GetLastCreateTime();
+            if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            {
+                var patientFilter = Builders<PatientEntity>.Filter.Where(f=>f.IsDelete == false);
+                var patients = await patientDB.FindAllAsync(patientFilter, new FindOptions<PatientEntity>() { Projection = Builders<PatientEntity>.Projection.Include(f=>f.PatientName).Include(f=>f.CrowdLabels) });
+                var patientCount = patients.Count;
+                var contractFilter = Builders<ContractRecordEntity>.Filter.Where(f=>f.ContractState == ContractStateEnum.Signed);
+                var contracts = await contractRecordDB.FindAllAsync(contractFilter);
+                var contractCount = contracts.Count;
+                var getRatio = (int ratioCount,int totality) => (ratioCount*1.0/(totality==0?1:totality)).ToString("P");
+                var contractRatio = getRatio(contractCount, patientCount);
+
+                var labels = new List<string>{ "RQFL_ET","RQFL_YF","RQFL_LNR","CJJB_GXY","CJJB_TNB","CJJB_FJH","CJJB_CJR","TSZG_JHSYTSJT" };
+                var keyPopulation = patients.Where(f=> f.CrowdLabels!=null && f.CrowdLabels.Any(a=>labels.Contains(a)));
+                var keyPopulationCount = patients.Count;
+                var keyPopulationContractCount = contracts.Count(f=>patients.Any(a=>a.Code == f.ContractedPatient));
+                var keyPopulationRatio = getRatio(keyPopulationContractCount, keyPopulationCount);
+                var data = new 
+                {
+                    ContractRatio = contractRatio,
+                    KeyPopulationRatio = keyPopulationRatio
+                };
+                statisticData = JsonSerializer.Serialize(data);
+                return await base.ExecuteAsync(statisticData, lastCreateTime);
+            }
+            return await Task.FromResult(true);
+        }
+    }
+}

+ 131 - 0
src/VitalMixtureService/DBService/Job/StatisticJobs/HomeStatisticJob.cs

@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Encodings.Web;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    public class HomeStatisticJob : StatisticJobBase
+    {
+        public HomeStatisticJob()
+        {
+            JobName = "HomeStatisticJob";
+            CronExpression = "0 2/5 * * * *";
+            StatisticType = StatisticTypeEnum.Customer;
+        }
+        public override async Task<bool> ExecuteAsync(string statisticData, DateTime lastCreateTime)
+        {
+            var followUpDB = DBRepositoryFactory.GetRepository<FollowUpDBRepository>();
+            var examDB = DBRepositoryFactory.GetRepository<ExamDBRepository>();
+            var contractRecordDB = DBRepositoryFactory.GetRepository<ContractRecordDBRepository>();
+            var patientDB = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+            lastCreateTime = await contractRecordDB.GetLastCreateTime();
+            if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            {
+                var patientFilter = Builders<PatientEntity>.Filter.Where(f=>f.IsDelete == false);
+                var patients = await patientDB.FindAllAsync(patientFilter, new FindOptions<PatientEntity>() { Projection = Builders<PatientEntity>.Projection.Include(f=>f.Code).Include(f=>f.CreatedTeamCode).Include(f=>f.PatientName).Include(f=>f.CrowdLabels) });
+                var patientCount = patients.Count;
+
+                var getPatientCount = (List<PatientEntity> patients, string labelCode)=>{
+                    return patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains(labelCode));
+                };
+
+                var getRatio = (int count, int patientCount) => (patientCount==0 ? 0 : count*1.0/(patientCount==0?1:patientCount) * 100).ToString("0.00");
+
+                var getSimplePatientCount = (List<PatientEntity> patients)=>{
+                    return patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels==null || 
+                    (!f.CrowdLabels.Contains("RQFL_YF") && !f.CrowdLabels.Contains("RQFL_ET") && !f.CrowdLabels.Contains("RQFL_LNR")));
+                };
+
+                var findFollowUp = async (IEnumerable<string> patientCodes) =>
+                {
+                    var followUpFilter = Builders<FollowUpEntity>.Filter.Where(f => f.FollowUpState == FollowUpStateEnum.FollowUpVisit && f.IsDelete == false && patientCodes.Contains(f.PatientCode));
+                    var followUpData = await followUpDB.FindAllAsync(followUpFilter, new FindOptions<FollowUpEntity>{ Projection = Builders<FollowUpEntity>.Projection.Include(f=>f.PatientCode) });
+                    return followUpData.ToList();
+                };
+                var findExam = async (IEnumerable<string> patientCodes) =>
+                {
+                    var examFilter = Builders<ExamEntity>.Filter.Where(f => f.ExamState == ExamStateEnum.Inspected && f.IsDelete == false && patientCodes.Contains(f.PatientCode));
+                    var examData = await examDB.FindAllAsync(examFilter, new FindOptions<ExamEntity>{ Projection = Builders<ExamEntity>.Projection.Include(f=>f.PatientCode) });
+                    return examData.ToList();
+                };
+                var contractFilter = Builders<ContractRecordEntity>.Filter.Where(f=> f.IsDelete == false && f.ContractState == ContractStateEnum.Signed);
+                var contracts = await contractRecordDB.FindAllAsync(contractFilter);
+                var patientCodes = patients.Select(f=>f.Code);
+                var patientFollowUp = await findFollowUp(patientCodes);
+                var patientExam = await findExam(patientCodes);
+                var groupItems = patients.GroupBy(g => g.CreatedTeamCode).Select(s =>
+                {
+                    var patientCodes = s.Select(f => f.Code);
+                    var filterPatients = patients.Where(w => patientCodes.Contains(w.Code)).ToList();
+                    var filterContracts = contracts.Where(w => patientCodes.Contains(w.ContractedPatient));
+                    return new KeyValuePair<string, dynamic>
+                    (
+                        s.Key,
+                        new
+                        {
+                            ChildrenRatio = getRatio(getPatientCount(filterPatients, "RQFL_ET"), filterPatients.Count),
+                            PregnantRatio = getRatio(getPatientCount(filterPatients, "RQFL_YF"), filterPatients.Count),
+                            OldRatio = getRatio(getPatientCount(filterPatients, "RQFL_LNR"), filterPatients.Count),
+                            //LookAfterRatio = getRatio(getPatientCount(filterPatients, "TSZG_JHSYTSJT"), filterPatients.Count),
+                            SimplePatientRatio = getRatio(getSimplePatientCount(filterPatients), filterPatients.Count),
+                            FollowUpCount = patientFollowUp.Count(w => patientCodes.Contains(w.PatientCode)),
+                            ExamCount = patientExam.Count(w => patientCodes.Contains(w.PatientCode)),
+                            ContractedCount = filterContracts.Count(w => patientCodes.Contains(w.ContractedPatient)),
+                            DayContractCount = filterContracts.Count(w => patientCodes.Contains(w.ContractedPatient) && w.ContractedTime > DateTime.UtcNow.Date),
+                            ContractedWeekGroup = filterContracts.GroupBy(g => g.ContractedTime.DayOfWeek).Select(x => new
+                            {
+                                WeekDay = x.Key == DayOfWeek.Sunday ? 7 : (int)x.Key,
+                                Count = x.Count()
+                            }),
+                            FollowUpWeekGroup = patientFollowUp.GroupBy(g => g.FollowUpTime.DayOfWeek).Select(x => new
+                            {
+                                WeekDay = x.Key == DayOfWeek.Sunday ? 7 : (int)x.Key,
+                                Count = x.Count()
+                            }),
+                            ExamWeekGroup = patientExam.GroupBy(g => g.CreateTime.DayOfWeek).Select(x => new
+                            {
+                                WeekDay = x.Key == DayOfWeek.Sunday ? 7 : (int)x.Key,
+                                Count = x.Count()
+                            }),
+                            ContractedMonthGroup = filterContracts.GroupBy(g => g.ContractedTime.Month).Select(x => new
+                            {
+                                Month = x.Key,
+                                Count = x.Count()
+                            }),
+                            FollowUpMonthGroup = patientFollowUp.GroupBy(g => g.FollowUpTime.Month).Select(x => new
+                            {
+                                Month = x.Key,
+                                Count = x.Count()
+                            }),
+                            ExamMonthGroup = patientExam.GroupBy(g => g.CreateTime.Month).Select(x => new
+                            {
+                                Month = x.Key,
+                                Count = x.Count()
+                            })
+                        }
+                    );
+                });
+                var options = new JsonSerializerOptions
+                {
+                    Encoder = JavaScriptEncoder.Default
+                };
+                StringBuilder stringBuilder = new StringBuilder();
+                foreach(var item in groupItems)
+                {
+                    stringBuilder.Append($"\"{item.Key}\":\"{JsonSerializer.Serialize(item.Value).Replace("\"","\\\"")}\",");
+                }
+                statisticData = $"{{{stringBuilder.ToString().TrimEnd(',')}}}";
+            }
+            return await base.ExecuteAsync(statisticData, lastCreateTime);
+        }
+    }
+}

+ 67 - 0
src/VitalMixtureService/DBService/Job/StatisticJobs/KeyPopulationStatisticJob.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    /// <summary>
+    /// 重点人群
+    /// </summary>
+    public class KeyPopulationStatisticJob : StatisticJobBase
+    {
+        public KeyPopulationStatisticJob()
+        {
+            JobName = "KeyPopulationStatisticJob";
+            CronExpression = "0 0/5 * * * *";
+            StatisticType = StatisticTypeEnum.Customer;
+        }
+        public override async Task<bool> ExecuteAsync(string statisticData, DateTime lastCreateTime)
+        {
+            var teamDB = DBRepositoryFactory.GetRepository<TeamDBRepository>();
+            var patientDB = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+            lastCreateTime = await patientDB.GetLastCreateTime();
+            if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            {
+                var patientFilter = Builders<PatientEntity>.Filter.Where(f=>f.IsDelete == false);
+                var patients = await patientDB.FindAllAsync(patientFilter, new FindOptions<PatientEntity>() { Projection = Builders<PatientEntity>.Projection.Include(f=>f.PatientName).Include(f=>f.CrowdLabels) });
+                var patientCount = patients.Count;
+                var children = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("RQFL_ET"));
+                var pregnant = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("RQFL_YF"));
+                var olds = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("RQFL_LNR"));
+                var gxy = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("CJJB_GXY"));
+                var tnb = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("CJJB_TNB"));
+                var fjh = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("CJJB_FJH"));
+                var cjr = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("CJJB_CJR"));
+                var tszg = patients.Count==0 ? 0 : patients.Count(f=> f.CrowdLabels!=null && f.CrowdLabels.Contains("TSZG_JHSYTSJT"));
+                var getRatio = (int count) => (patients.Count==0 ? 0 : (count*1.0/(patientCount==0?1:patientCount))).ToString("P");
+                var data = new 
+                {
+                    Children = children,
+                    Pregnant = pregnant,
+                    Olds = olds,
+                    Gxy = gxy,
+                    Tnb = tnb,
+                    Fjh = fjh,
+                    Cjr = cjr,
+                    Tszg = tszg,
+                    ChildrenRatio = getRatio(children),
+                    PregnantRatio = getRatio(pregnant),
+                    OldsRatio = getRatio(olds),
+                    GxyRatio = getRatio(gxy),
+                    TnbRatio = getRatio(tnb),
+                    FjhRatio = getRatio(fjh),
+                    CjrRatio = getRatio(cjr),
+                    TszgRatio = getRatio(tszg),
+                };
+                statisticData = JsonSerializer.Serialize(data);
+            }
+            return await base.ExecuteAsync(statisticData, lastCreateTime);
+        }
+    }
+}

+ 47 - 0
src/VitalMixtureService/DBService/Job/StatisticJobs/ServiceRateAged65Job.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    public class ServiceRateAged65Job : StatisticJobBase
+    {
+        public ServiceRateAged65Job()
+        {
+            JobName = "ServiceRateAged65Job";
+            CronExpression = "0 0/5 * * * *";
+            StatisticType = StatisticTypeEnum.Customer;
+        }
+        public override async Task<bool> ExecuteAsync(string statisticData, DateTime lastCreateTime)
+        {
+            var followUpDB = DBRepositoryFactory.GetRepository<FollowUpDBRepository>();
+            var patientDB = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+            lastCreateTime = await followUpDB.GetLastCreateTime();
+            if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            {
+                var patientFilter = Builders<PatientEntity>.Filter.Where(f=>f.IsDelete == false);
+                var ageFilter = Builders<PatientEntity>.Filter.Gt(f=>f.Birthday, DateTime.Now.Date.AddYears(-65));
+                var patients = await patientDB.FindAllAsync(patientFilter & ageFilter, new FindOptions<PatientEntity>() { Projection = Builders<PatientEntity>.Projection.Include(f=>f.Code) });
+                var patientCount = patients.Count;
+                var patientCodes = patients.Select(s=>s.Code).Distinct().ToList();
+                var followUpFilter = Builders<FollowUpEntity>.Filter.Where(f=>f.IsDelete == false && f.FollowUpState == FollowUpStateEnum.FollowUpVisit && patientCodes.Contains(f.PatientCode));
+                var followUps = await followUpDB.FindAllAsync(followUpFilter, new FindOptions<FollowUpEntity>() { Projection = Builders<FollowUpEntity>.Projection.Include(f=>f.PatientCode) });
+                var followUpPatientCount = followUps.Select(f=>f.PatientCode).Distinct().Count();
+                var getRatio = (int count) => (count==0 ? 0 : (count*1.0/(patientCount==0?1:patientCount))).ToString("P");
+                var managerPatientRatio = getRatio(followUpPatientCount);
+                var data = new 
+                {
+                    ManagerPatientRatio = managerPatientRatio
+                };
+                statisticData = JsonSerializer.Serialize(data);
+            }
+            return await base.ExecuteAsync(statisticData, lastCreateTime);
+        }
+    }
+}

+ 54 - 0
src/VitalMixtureService/DBService/Job/StatisticJobs/StatisticJobBase.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingInterfaceLibrary.Enum.VitalEnum;
+
+namespace VitalService.Job
+{
+    public abstract class StatisticJobBase : IJob
+    {
+        public DateTime UpdateTime { get; set; }
+        public DateTime LastRunTime { get; set; } = DateTime.Now;
+        public string JobName { get; set; } = "StatisticJobBase";
+        public StatisticTypeEnum StatisticType { get; set; }
+        public string CronExpression { get; set; } = "0 5/10 * * * *";
+
+
+        public virtual async Task<bool> ExecuteAsync(string statisticData, DateTime lastCreateTime)
+        {
+            if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            {
+                var statisticDB = DBRepositoryFactory.GetRepository<StatisticDBRepository>();
+                var filter = Builders<StatisticEntity>.Filter.Where(x => x.StatisticKey == JobName && x.StatisticType == StatisticType && x.Time == DateTime.Now.Date.ToString("yyyyMMdd"));
+                var amountData = await statisticDB.FindOneAsync(filter);
+                if (amountData != null)
+                {
+                    var filterCode = Builders<StatisticEntity>.Filter.Eq(f => f.Code, amountData.Code);
+                    //更新内容
+                    var update = Builders<StatisticEntity>.Update
+                                    .Set(x => x.Time, DateTime.Now.Date.ToString("yyyyMMdd"))
+                                    .Set(x => x.UpdateTime, DateTime.UtcNow)
+                                    .Set(x => x.StatisticData, statisticData);
+                    await statisticDB.UpdateOneAsync(filterCode, update);
+                }
+                else
+                {
+                    var data = new StatisticEntity
+                    {
+                        StatisticKey = JobName,
+                        StatisticType = StatisticType,
+                        Time = DateTime.Now.Date.ToString("yyyyMMdd"),
+                        StatisticData = statisticData
+                    };
+                    await statisticDB.InsertOneAsync(data);
+                }
+                UpdateTime = lastCreateTime;
+            }
+            LastRunTime = DateTime.Now;
+            return await Task.FromResult(true);
+        }
+    }
+}

+ 41 - 0
src/VitalMixtureService/DBService/Job/ThirdLevelSoftwareJobs/PasswordExpiredJob.cs

@@ -0,0 +1,41 @@
+using VitalService.Common;
+using VitalService.Repositories;
+using WingServerCommon.Config.Parameters;
+using VitalService.Config;
+
+namespace VitalService.Job
+{
+    public class PasswordExpiredJob : ThirdLevelSoftwareJobBase
+    {
+        private string _serverHost => EnvironmentConfigManager.GetParammeter<StringParameter>("Gateway", "Host").Value;
+        public PasswordExpiredJob()
+        {
+            JobName = "PasswordExpiredJob";
+            CronExpression = "0 0/5 * * * *";
+        }
+
+        public override async Task<bool> ExecuteAsync(string data, DateTime lastCreateTime)
+        {
+            var tokenDB = DBRepositoryFactory.GetRepository<TokenDBRepository>();
+            lastCreateTime = DateTime.UtcNow;
+            // if(lastCreateTime > UpdateTime || LastRunTime.Date != DateTime.Now.Date)
+            // {
+            //     var filter = Builders<TokenEntity>.Filter.Lt(f=>f.Expiration, DateTime.UtcNow);
+            //     var expirationTokenInfo = await tokenDB.FindAllAsync(filter);
+            //     foreach(var info in expirationTokenInfo)
+            //     {
+            //         _ = LoginOutAsync(info.Code).ConfigureAwait(false);
+            //     }
+            // }
+            return await base.ExecuteAsync(data, lastCreateTime);
+        }
+
+        private async Task LoginOutAsync(string token)
+        {
+            using (var client = new HttpClient())
+            {
+                await client.PostAsync($"{_serverHost.Replace("*", "127.0.0.1")}IAuthenticationService", new StringContent($"{{\"jsonrpc\":\"2.0\",\"method\":\"LogOffAsync\",\"params\":[{{\"token\":\"{token}\"}}],\"id\":\"1\"}}"));
+            }
+        }
+    }
+}

+ 24 - 0
src/VitalMixtureService/DBService/Job/ThirdLevelSoftwareJobs/ThirdLevelSoftwareJobBase.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Threading.Tasks;
+
+namespace VitalService.Job
+{
+    public abstract class ThirdLevelSoftwareJobBase : IJob
+    {
+        public DateTime UpdateTime { get; set; }
+        public DateTime LastRunTime { get; set; } = DateTime.Now;
+        public string JobName { get; set; } = "ThirdLevelSoftwareJobBase";
+        public string CronExpression { get; set; } = "0 5/10 * * * *";
+
+        public virtual async Task<bool> ExecuteAsync(string data, DateTime lastCreateTime)
+        {
+            if(lastCreateTime > UpdateTime)
+            {
+                //三级等保Job逻辑
+                UpdateTime = lastCreateTime;
+            }
+            LastRunTime = DateTime.Now;
+            return await Task.FromResult(true);
+        }
+    }
+}

+ 35 - 0
src/VitalMixtureService/DBService/QueryAction/CompletionRecordQueryAction.cs

@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class CompletionRecordQueryAction : IQueryAction<CompletionRecordEntity>
+    {
+        public async Task<FilterDefinition<CompletionRecordEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<CompletionRecordEntity>> filters = new();
+            #region User name query
+            {
+                var userDBRepository = DBRepositoryFactory.GetRepository<UserDBRepository>();
+                var filter = Builders<UserEntity>.Filter.Regex(f=>f.UserName, bsonRegular);
+                var userCodes = await userDBRepository.FindCodesAsync(filter);
+                filters.Add(Builders<CompletionRecordEntity>.Filter.In(f=>f.CompletionDoctor, userCodes));
+            }
+            #endregion
+            #region Patient name query
+            {
+                var patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+                var filter = Builders<PatientEntity>.Filter.Regex(f=>f.PatientName, bsonRegular);
+                var patientCodes = await patientDBRepository.FindCodesAsync(filter);
+                filters.Add(Builders<CompletionRecordEntity>.Filter.In(f=>f.PatientCode, patientCodes));
+            }
+            #endregion
+            return Builders<CompletionRecordEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 47 - 0
src/VitalMixtureService/DBService/QueryAction/ContractRecordQueryAction.cs

@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class ContractRecordQueryAction : IQueryAction<ContractRecordEntity>
+    {
+        public async Task<FilterDefinition<ContractRecordEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<ContractRecordEntity>> filters = new();
+            #region ContractRecordNo
+            {
+                var contractRecordDBRepository = DBRepositoryFactory.GetRepository<ContractRecordDBRepository>();
+                var filterContractRecordNo = Builders<ContractRecordEntity>.Filter.Regex(f=>f.ContractRecordNo, bsonRegular);
+                var contractRecordCodes = await contractRecordDBRepository.FindCodesAsync(filterContractRecordNo);
+                filters.Add(Builders<ContractRecordEntity>.Filter.In(f=>f.Code, contractRecordCodes));
+            }
+            #endregion
+            #region User name query
+            {
+                var userDBRepository = DBRepositoryFactory.GetRepository<UserDBRepository>();
+                var filterUserName = Builders<UserEntity>.Filter.Regex(f=>f.UserName, bsonRegular);
+                var filterRealName = Builders<UserEntity>.Filter.Regex(f=>f.RealName, bsonRegular);
+                var orFilter = Builders<UserEntity>.Filter.Or(filterUserName, filterRealName);
+                var userCodes = await userDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<ContractRecordEntity>.Filter.In(f=>f.ContractedDoctor, userCodes));
+            }
+            #endregion
+            #region Patient name query
+            {
+                var patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+                var filterName = Builders<PatientEntity>.Filter.Regex(f=>f.PatientName, bsonRegular);
+                var filterNo = Builders<PatientEntity>.Filter.Regex(f=>f.CardNo, bsonRegular);
+                var orFilter = Builders<PatientEntity>.Filter.Or(filterName, filterNo);
+                var patientCodes = await patientDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<ContractRecordEntity>.Filter.In(f=>f.ContractedPatient, patientCodes));
+            }
+            #endregion
+            return Builders<ContractRecordEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 27 - 0
src/VitalMixtureService/DBService/QueryAction/ContractTemplateQueryAction.cs

@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class ContractTemplateQueryAction : IQueryAction<ContractTemplateEntity>
+    {
+        public async Task<FilterDefinition<ContractTemplateEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<ContractTemplateEntity>> filters = new();
+            #region Template name query
+            {
+                var templateDBRepository = DBRepositoryFactory.GetRepository<ContractTemplateDBRepository>();
+                var filterTemplateName = Builders<ContractTemplateEntity>.Filter.Regex(f=>f.TemplateName, bsonRegular);
+                var templateCodes = await templateDBRepository.FindCodesAsync(filterTemplateName);
+                filters.Add(Builders<ContractTemplateEntity>.Filter.In(f=>f.Code, templateCodes));
+            }
+            #endregion
+            return Builders<ContractTemplateEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 31 - 0
src/VitalMixtureService/DBService/QueryAction/DeviceQueryAction.cs

@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class DeviceQueryAction: IQueryAction<DeviceEntity>
+    {
+        public async Task<FilterDefinition<DeviceEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<DeviceEntity>> filters = new();
+            #region Device unique query
+            {
+                var DeviceDBRepository = DBRepositoryFactory.GetRepository<DeviceDBRepository>();
+                var filterUniqueCode = Builders<DeviceEntity>.Filter.Regex(f=>f.UniqueCode, bsonRegular);
+                var filterSerialNumber = Builders<DeviceEntity>.Filter.Regex(f=>f.SerialNumber, bsonRegular);
+                var filterDescription = Builders<DeviceEntity>.Filter.Regex(f=>f.Description, bsonRegular);
+                var filterModel = Builders<DeviceEntity>.Filter.Regex(f=>f.Model, bsonRegular);
+                var orFilter = Builders<DeviceEntity>.Filter.Or(filterUniqueCode, filterSerialNumber, filterDescription, filterModel);
+                var DeviceCodes = await DeviceDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<DeviceEntity>.Filter.In(f=>f.Code, DeviceCodes));
+            }
+            #endregion
+            return Builders<DeviceEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 33 - 0
src/VitalMixtureService/DBService/QueryAction/DiagnosisQueryAction.cs

@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+using WingServerCommon.Utilities;
+
+namespace VitalService.QueryAction
+{
+    public class DiagnosisQueryAction: IQueryAction<DiagnosisEntity>
+    {
+        private IEncrypt _base64EncryptInstance = new DBEncryptHelper();
+        public async Task<FilterDefinition<DiagnosisEntity>> GetQuery(string keyword)
+        {
+            var encryptKeyword = _base64EncryptInstance.Encrypt(keyword).Replace("+", "[+]").Replace("/", "[/]");
+            var encryptBsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{encryptKeyword}.*", "ig");
+            List<FilterDefinition<DiagnosisEntity>> filters = new();
+            #region Diagnosis name query
+            {
+                var patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+                var filterName = Builders<PatientEntity>.Filter.Regex(f=>f.PatientName, encryptBsonRegular);
+                var filterNo = Builders<PatientEntity>.Filter.Regex(f=>f.CardNo, encryptBsonRegular);
+                var Phone = Builders<PatientEntity>.Filter.Regex(f=>f.Phone, encryptBsonRegular);
+                var orFilter = Builders<PatientEntity>.Filter.Or(filterName, filterNo, Phone);
+                var patientCodes = await patientDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<DiagnosisEntity>.Filter.In(f=>f.PatientCode, patientCodes));
+            }
+            #endregion
+            return Builders<DiagnosisEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 30 - 0
src/VitalMixtureService/DBService/QueryAction/DictionaryQueryAction.cs

@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class DictionaryQueryAction: IQueryAction<DictionaryEntity>
+    {
+        public async Task<FilterDefinition<DictionaryEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<DictionaryEntity>> filters = new();
+            #region Dictionary name query
+            {
+                var dictionaryDBRepository = DBRepositoryFactory.GetRepository<DictionaryDBRepository>();
+                var filterDictionaryName = Builders<DictionaryEntity>.Filter.Regex(f=>f.Name, bsonRegular);
+                var filterDictionaryKey = Builders<DictionaryEntity>.Filter.Regex(f=>f.Key, bsonRegular);
+                var filterDictionaryDescription = Builders<DictionaryEntity>.Filter.Regex(f=>f.Description, bsonRegular);
+                var combine = Builders<DictionaryEntity>.Filter.Or(filterDictionaryName, filterDictionaryKey, filterDictionaryDescription);
+                var dictionaryCodes = await dictionaryDBRepository.FindCodesAsync(combine);
+                filters.Add(Builders<DictionaryEntity>.Filter.In(f=>f.Code, dictionaryCodes));
+            }
+            #endregion
+            return Builders<DictionaryEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 30 - 0
src/VitalMixtureService/DBService/QueryAction/DynamicTypeQueryAction.cs

@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class DynamicTypeQueryAction : IQueryAction<DynamicTypeEntity>
+    {
+        public async Task<FilterDefinition<DynamicTypeEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<DynamicTypeEntity>> filters = new();
+            #region DynamicType name query
+            {
+                var dynamicTypeDBRepository = DBRepositoryFactory.GetRepository<DynamicTypeDBRepository>();
+                var filterDynamicTypeCode = Builders<DynamicTypeEntity>.Filter.Regex(f=>f.Code, bsonRegular);
+                var filterDynamicTypeName = Builders<DynamicTypeEntity>.Filter.Regex(f=>f.TypeName, bsonRegular);
+                var filterDynamicTypeKey = Builders<DynamicTypeEntity>.Filter.Regex(f=>f.TypeKey, bsonRegular);
+                var combine = Builders<DynamicTypeEntity>.Filter.Or(filterDynamicTypeCode, filterDynamicTypeName, filterDynamicTypeKey);
+                var dynamicTypeCodes = await dynamicTypeDBRepository.FindCodesAsync(combine);
+                filters.Add(Builders<DynamicTypeEntity>.Filter.In(f=>f.Code, dynamicTypeCodes));
+            }
+            #endregion
+            return Builders<DynamicTypeEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 39 - 0
src/VitalMixtureService/DBService/QueryAction/ExamQueryAction.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class ExamQueryAction : IQueryAction<ExamEntity>
+    {
+        public async Task<FilterDefinition<ExamEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<ExamEntity>> filters = new();
+            #region User name query
+            {
+                var userDBRepository = DBRepositoryFactory.GetRepository<UserDBRepository>();
+                var filterUserName = Builders<UserEntity>.Filter.Regex(f=>f.UserName, bsonRegular);
+                var filterRealName = Builders<UserEntity>.Filter.Regex(f=>f.RealName, bsonRegular);
+                var orFilter = Builders<UserEntity>.Filter.Or(filterUserName, filterRealName);
+                var userCodes = await userDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<ExamEntity>.Filter.In(f=>f.ContractedDoctor, userCodes));
+            }
+            #endregion
+            #region Patient name query
+            {
+                var patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+                var filterName = Builders<PatientEntity>.Filter.Regex(f=>f.PatientName, bsonRegular);
+                var filterNo = Builders<PatientEntity>.Filter.Regex(f=>f.CardNo, bsonRegular);
+                var orFilter = Builders<PatientEntity>.Filter.Or(filterName, filterNo);
+                var patientCodes = await patientDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<ExamEntity>.Filter.In(f=>f.PatientCode, patientCodes));
+            }
+            #endregion
+            return Builders<ExamEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 39 - 0
src/VitalMixtureService/DBService/QueryAction/FollowUpQueryAction.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class FollowUpQueryAction : IQueryAction<FollowUpEntity>
+    {
+        public async Task<FilterDefinition<FollowUpEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<FollowUpEntity>> filters = new();
+            #region User name query
+            {
+                var userDBRepository = DBRepositoryFactory.GetRepository<UserDBRepository>();
+                var filterUserName = Builders<UserEntity>.Filter.Regex(f=>f.UserName, bsonRegular);
+                var filterRealName = Builders<UserEntity>.Filter.Regex(f=>f.RealName, bsonRegular);
+                var orFilter = Builders<UserEntity>.Filter.Or(filterUserName, filterRealName);
+                var userCodes = await userDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<FollowUpEntity>.Filter.In(f=>f.ContractedDoctor, userCodes));
+            }
+            #endregion
+            #region Patient name query
+            {
+                var patientDBRepository = DBRepositoryFactory.GetRepository<PatientDBRepository>();
+                var filterName = Builders<PatientEntity>.Filter.Regex(f=>f.PatientName, bsonRegular);
+                var filterNo = Builders<PatientEntity>.Filter.Regex(f=>f.CardNo, bsonRegular);
+                var orFilter = Builders<PatientEntity>.Filter.Or(filterName, filterNo);
+                var patientCodes = await patientDBRepository.FindCodesAsync(orFilter);
+                filters.Add(Builders<FollowUpEntity>.Filter.In(f=>f.PatientCode, patientCodes));
+            }
+            #endregion
+            return Builders<FollowUpEntity>.Filter.Or(filters);
+        }
+    }
+}

+ 10 - 0
src/VitalMixtureService/DBService/QueryAction/IQueryAction.cs

@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+using MongoDB.Driver;
+
+namespace VitalService.QueryAction
+{
+    public interface IQueryAction<T> where T: new()
+    {
+        Task<FilterDefinition<T>> GetQuery(string keyword);
+    }
+}

+ 27 - 0
src/VitalMixtureService/DBService/QueryAction/OrganizationQueryAction.cs

@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MongoDB.Driver;
+using VitalService.Common;
+using VitalService.Entities;
+using VitalService.Repositories;
+
+namespace VitalService.QueryAction
+{
+    public class OrganizationQueryAction : IQueryAction<OrganizationEntity>
+    {
+        public async Task<FilterDefinition<OrganizationEntity>> GetQuery(string keyword)
+        {
+            var bsonRegular = new MongoDB.Bson.BsonRegularExpression($".*{keyword}.*", "ig");
+            List<FilterDefinition<OrganizationEntity>> filters = new();
+            #region Organization name query
+            {
+                var orgDBRepository = DBRepositoryFactory.GetRepository<OrganizationDBRepository>();
+                var filterOrgName = Builders<OrganizationEntity>.Filter.Regex(f=>f.OrganizationName, bsonRegular);
+                var orgCodes = await orgDBRepository.FindCodesAsync(filterOrgName);
+                filters.Add(Builders<OrganizationEntity>.Filter.In(f=>f.Code, orgCodes));
+            }
+            #endregion
+            return Builders<OrganizationEntity>.Filter.Or(filters);
+        }
+    }
+}

Some files were not shown because too many files changed in this diff