李广 2 hónapja
szülő
commit
bbcbf5a51c
100 módosított fájl, 11708 hozzáadás és 29 törlés
  1. 283 29
      .gitignore
  2. 34 0
      JiaZhiQuan.Common.sln
  3. 95 0
      JiaZhiQuan.Common/AliOSS/FileOperator.cs
  4. 184 0
      JiaZhiQuan.Common/AliOSS/FileUpload.cs
  5. 17 0
      JiaZhiQuan.Common/AliOSS/OSSConfig.cs
  6. 17 0
      JiaZhiQuan.Common/AliOSS/OSSDirectory.cs
  7. 250 0
      JiaZhiQuan.Common/AliVod/AliVODHelper.cs
  8. 24 0
      JiaZhiQuan.Common/AliVod/VodConfig.cs
  9. 20 0
      JiaZhiQuan.Common/Attributes/CreatorSpaceTypeDescAttribute.cs
  10. 14 0
      JiaZhiQuan.Common/Attributes/DescriptionAttribute.cs
  11. 101 0
      JiaZhiQuan.Common/Cache/CacheKeys.Activity.cs
  12. 68 0
      JiaZhiQuan.Common/Cache/CacheKeys.App.cs
  13. 12 0
      JiaZhiQuan.Common/Cache/CacheKeys.Feedback.cs
  14. 25 0
      JiaZhiQuan.Common/Cache/CacheKeys.IM.cs
  15. 14 0
      JiaZhiQuan.Common/Cache/CacheKeys.MP.cs
  16. 64 0
      JiaZhiQuan.Common/Cache/CacheKeys.Mall.cs
  17. 139 0
      JiaZhiQuan.Common/Cache/CacheKeys.Post.cs
  18. 127 0
      JiaZhiQuan.Common/Cache/CacheKeys.PushMsg.cs
  19. 32 0
      JiaZhiQuan.Common/Cache/CacheKeys.QT.cs
  20. 15 0
      JiaZhiQuan.Common/Cache/CacheKeys.RCIM.cs
  21. 27 0
      JiaZhiQuan.Common/Cache/CacheKeys.Sms.cs
  22. 55 0
      JiaZhiQuan.Common/Cache/CacheKeys.Statistics.cs
  23. 17 0
      JiaZhiQuan.Common/Cache/CacheKeys.Topic.cs
  24. 124 0
      JiaZhiQuan.Common/Cache/CacheKeys.User.cs
  25. 17 0
      JiaZhiQuan.Common/Cache/CacheKeys.UserGrow.cs
  26. 14 0
      JiaZhiQuan.Common/Cache/CacheKeys.Vod.cs
  27. 16 0
      JiaZhiQuan.Common/Cache/CacheKeys.cs
  28. 722 0
      JiaZhiQuan.Common/Config/ConfigFromDb.cs
  29. 23 0
      JiaZhiQuan.Common/Config/ConfigFromDbConfig.cs
  30. 158 0
      JiaZhiQuan.Common/Config/ConfigFromDbModels.cs
  31. 31 0
      JiaZhiQuan.Common/Config/ConfigRefreshScheduleService.cs
  32. 78 0
      JiaZhiQuan.Common/ElasticSearch/ESConstants.cs
  33. 31 0
      JiaZhiQuan.Common/ElasticSearch/ESFieldAttribute.cs
  34. 252 0
      JiaZhiQuan.Common/ElasticSearch/ESHelper.cs
  35. 43 0
      JiaZhiQuan.Common/ElasticSearch/ESQuery.cs
  36. 19 0
      JiaZhiQuan.Common/ElasticSearch/ElasticSearchConfig.cs
  37. 36 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESIpAddress.cs
  38. 356 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESMallGoods.cs
  39. 35 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESMobileAddress.cs
  40. 38 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESNLog.cs
  41. 72 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESPersonalPageViewRecordModel.cs
  42. 212 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESPostModel.cs
  43. 84 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESPostReadRecordModel.cs
  44. 85 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESPostShareRecordModel.cs
  45. 18 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESResponseData.cs
  46. 32 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESSystemLog.cs
  47. 57 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESUserCollectRecord.cs
  48. 49 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESUserFansRecord.cs
  49. 68 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESUserModel.cs
  50. 55 0
      JiaZhiQuan.Common/ElasticSearch/Models/ESUserThumbsupRecord.cs
  51. 27 0
      JiaZhiQuan.Common/Enum/ActivityDaka.cs
  52. 50 0
      JiaZhiQuan.Common/Enum/ActivityTypes.cs
  53. 10 0
      JiaZhiQuan.Common/Enum/AppActionDataConstants.cs
  54. 71 0
      JiaZhiQuan.Common/Enum/AppPushMessageTypes.cs
  55. 32 0
      JiaZhiQuan.Common/Enum/BalanceBizCodes.cs
  56. 21 0
      JiaZhiQuan.Common/Enum/ClassEnum/AbstractEnum.cs
  57. 25 0
      JiaZhiQuan.Common/Enum/ClassEnum/AppIndexTabEnum.cs
  58. 514 0
      JiaZhiQuan.Common/Enum/Enums.cs
  59. 13 0
      JiaZhiQuan.Common/Enum/MallConstants.cs
  60. 21 0
      JiaZhiQuan.Common/Enum/RetationDateConstants.cs
  61. 89 0
      JiaZhiQuan.Common/Enum/UserMessageRecordType.cs
  62. 155 0
      JiaZhiQuan.Common/ErrorCodes/ErrorCodes.cs
  63. 24 0
      JiaZhiQuan.Common/Hubs/ClientConnectionInfo.cs
  64. 141 0
      JiaZhiQuan.Common/Hubs/ServerResultDTO.cs
  65. 15 0
      JiaZhiQuan.Common/IoC/AutofacInjection.cs
  66. 30 0
      JiaZhiQuan.Common/IoC/CommonModule.cs
  67. 35 0
      JiaZhiQuan.Common/JiaZhiQuan.Common.csproj
  68. 63 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiChash.cs
  69. 79 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiIndv.cs
  70. 418 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiJspay.cs
  71. 224 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiOpen.cs
  72. 222 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiOpenModify.cs
  73. 192 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiRefund.cs
  74. 43 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiRefundQuery.cs
  75. 130 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiYuEPay.cs
  76. 16 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuEnums.cs
  77. 2854 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuModel.cs
  78. 128 0
      JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuUtil.cs
  79. 60 0
      JiaZhiQuan.Common/JuheAPI/IpAddress/JuheIpAddressUtils.cs
  80. 20 0
      JiaZhiQuan.Common/JuheAPI/JuheResponseModel.cs
  81. 62 0
      JiaZhiQuan.Common/JuheAPI/MobileAddress/JuheMobileAddressUtils.cs
  82. 73 0
      JiaZhiQuan.Common/JuheAPI/SendSms/JuheSendSmsUtils.cs
  83. 126 0
      JiaZhiQuan.Common/KDNiao/KDNiaoHelper.cs
  84. 254 0
      JiaZhiQuan.Common/KDNiao/KDNiaoModel.cs
  85. 42 0
      JiaZhiQuan.Common/Mapster/BuildTypeAdapterConfig.cs
  86. 23 0
      JiaZhiQuan.Common/Mapster/GlobalSettings.cs
  87. 213 0
      JiaZhiQuan.Common/Messaging/BaseConsumer.cs
  88. 19 0
      JiaZhiQuan.Common/Messaging/IConsumer.cs
  89. 11 0
      JiaZhiQuan.Common/Messaging/MessageReceivedEventArgs.cs
  90. 24 0
      JiaZhiQuan.Common/Messaging/MessagingConfig.cs
  91. 63 0
      JiaZhiQuan.Common/Messaging/MessagingService.cs
  92. 25 0
      JiaZhiQuan.Common/Messaging/Models/CommentAuthModel.cs
  93. 28 0
      JiaZhiQuan.Common/Messaging/Models/IMMessageModel.cs
  94. 22 0
      JiaZhiQuan.Common/Messaging/Models/KDNaioTraceModel.cs
  95. 96 0
      JiaZhiQuan.Common/Messaging/Models/LogRecordModel.cs
  96. 24 0
      JiaZhiQuan.Common/Messaging/Models/MallGoodsSyncModel.cs
  97. 222 0
      JiaZhiQuan.Common/Messaging/Models/NotificationModel.cs
  98. 25 0
      JiaZhiQuan.Common/Messaging/Models/PostAuthModel.cs
  99. 51 0
      JiaZhiQuan.Common/Messaging/Models/SendMessageToClientModel.cs
  100. 224 0
      JiaZhiQuan.Common/Messaging/Models/StatisticActionModel.cs

+ 283 - 29
.gitignore

@@ -1,30 +1,84 @@
-# ---> C Sharp
-# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
-[Bb]in/
-[Oo]bj/
-
-# mstest test results
-TestResults
-
 ## Ignore Visual Studio temporary files, build results, and
 ## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
 
 # User-specific files
+*.rsuser
 *.suo
 *.user
+*.userosscache
 *.sln.docstates
 
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
 # Build results
 [Dd]ebug/
+[Dd]ebugPublic/
 [Rr]elease/
+[Rr]eleases/
 x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
 *_i.c
 *_p.c
+*_h.h
 *.ilk
 *.meta
 *.obj
+*.iobj
 *.pch
 *.pdb
+*.ipdb
 *.pgc
 *.pgd
 *.rsp
@@ -33,35 +87,83 @@ x64/
 *.tli
 *.tlh
 *.tmp
+*.tmp_proj
+*_wpftmp.csproj
 *.log
 *.vspscc
 *.vssscc
 .builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
 
 # Visual C++ cache files
 ipch/
 *.aps
 *.ncb
+*.opendb
 *.opensdf
 *.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
 
 # Visual Studio profiler
 *.psess
 *.vsp
 *.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
 
 # Guidance Automation Toolkit
 *.gpState
 
 # ReSharper is a .NET coding add-in
-_ReSharper*
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
 
 # NCrunch
-*.ncrunch*
+_NCrunch_*
 .*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
 
 # Installshield output folder
-[Ee]xpress
+[Ee]xpress/
 
 # DocProject is a documentation generator add-in
 DocProject/buildhelp/
@@ -74,37 +176,189 @@ DocProject/Help/Html2
 DocProject/Help/html
 
 # Click-Once directory
-publish
+publish/
 
 # Publish Web Output
-*.Publish.xml
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
 
-# NuGet Packages Directory
-packages
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
 
-# Windows Azure Build Output
-csx
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
 *.build.csdef
 
-# Windows Store app package directory
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
 AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
 
 # Others
-[Bb]in
-[Oo]bj
-sql
-TestResults
-[Tt]est[Rr]esult*
-*.Cache
-ClientBin
-[Ss]tyle[Cc]op.*
+ClientBin/
 ~$*
+*~
 *.dbmdl
-Generated_Code #added for RIA/Silverlight projects
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
 
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
 _UpgradeReport_Files/
 Backup*/
 UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
 
+*.DS_Store

+ 34 - 0
JiaZhiQuan.Common.sln

@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32210.238
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiaZhiQuan.Common", "JiaZhiQuan.Common\JiaZhiQuan.Common.csproj", "{9E4DA811-19A2-4A1F-BEB2-148873745953}"
+	ProjectSection(ProjectDependencies) = postProject
+		{19C8076E-8689-4131-A6F6-582C09470420} = {19C8076E-8689-4131-A6F6-582C09470420}
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wicture.DbRESTFul", "..\..\..\DbRESTFul-V3\src\Wicture.DbRESTFul\Wicture.DbRESTFul.csproj", "{19C8076E-8689-4131-A6F6-582C09470420}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9E4DA811-19A2-4A1F-BEB2-148873745953}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9E4DA811-19A2-4A1F-BEB2-148873745953}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9E4DA811-19A2-4A1F-BEB2-148873745953}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9E4DA811-19A2-4A1F-BEB2-148873745953}.Release|Any CPU.Build.0 = Release|Any CPU
+		{19C8076E-8689-4131-A6F6-582C09470420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{19C8076E-8689-4131-A6F6-582C09470420}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{19C8076E-8689-4131-A6F6-582C09470420}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{19C8076E-8689-4131-A6F6-582C09470420}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {4BCFF941-3000-4964-B0BC-D83DB7866D38}
+	EndGlobalSection
+EndGlobal

+ 95 - 0
JiaZhiQuan.Common/AliOSS/FileOperator.cs

@@ -0,0 +1,95 @@
+using Aliyun.OSS;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Threading.Tasks;
+using Org.BouncyCastle.Utilities.Collections;
+using Wicture.DbRESTFul.Configuration;
+using JiaZhiQuan.Common.Config;
+
+namespace JiaZhiQuan.Common.AliOSS
+{
+    public class FileOperator
+    {
+        public async static Task<string> GetFileContent(string key, string bucketName, string endPoint, string accessKeyId, string accessKeySecret)
+        {
+            OssClient ossClient = new OssClient(endPoint, accessKeyId, accessKeySecret);
+            return await GetFileContent(key, bucketName, ossClient);
+        }
+
+        public async static Task<string> GetFileContent(string key, string bucketName, OssClient ossClient)
+        {
+            GetObjectRequest request = new GetObjectRequest(bucketName, key);
+            var rst = await Task.Factory.FromAsync(ossClient.BeginGetObject, ossClient.EndGetObject, request, null);
+            if (rst.HttpStatusCode != System.Net.HttpStatusCode.OK) return string.Empty;
+            using StreamReader sr = new StreamReader(rst.ResponseStream);
+            return await sr.ReadToEndAsync();
+        }
+
+        public async static Task<Stream> GetFileStreamAsync(string key, bool isDev, string accessKeyId, string accessKeySecret)
+        {
+            var ossConfig = BuildOssConfig(isDev, accessKeyId, accessKeySecret);
+            var ossClient = BuildOssClient(ossConfig);
+            GetObjectRequest request = new GetObjectRequest(ossConfig.OSSBucket, key);
+            var rst = await Task.Factory.FromAsync(ossClient.BeginGetObject, ossClient.EndGetObject, request, null);
+            if (rst.HttpStatusCode != System.Net.HttpStatusCode.OK) return null;
+            return rst.ResponseStream;
+        }
+
+        public static void RemoveFile(List<string> keys, string bucketName, string endPoint, string accessKeyId, string accessKeySecret)
+        {
+            OssClient ossClient = new OssClient(endPoint, accessKeyId, accessKeySecret);
+            RemoveFile(keys, bucketName, ossClient);
+        }
+
+        public static void RemoveFile(List<string> keys, string bucketName, OssClient ossClient)
+        {
+            ossClient.DeleteObjects(new DeleteObjectsRequest(bucketName, keys));
+        }
+
+        /// <summary>
+        /// 构建OSS操作对象,返回OSSClient和OSSConfig
+        /// </summary>
+        /// <param name="isDev"></param>
+        /// <param name="accessKeyId"></param>
+        /// <param name="accessKeySecret"></param>
+        /// <returns></returns>
+        public static OssClient BuildOssClient(OSSConfig OSSConfig)
+        {
+            var OSSClient = new OssClient(OSSConfig.EndPoint, OSSConfig.AccessKeyId, OSSConfig.AccessKeySecret);
+            return OSSClient;
+        }
+
+        /// <summary>
+        /// 创建OSSConfig对象
+        /// </summary>
+        /// <param name="isDev"></param>
+        /// <param name="accessKeyId"></param>
+        /// <param name="accessKeySecret"></param>
+        /// <param name="bucket"></param>
+        /// <returns></returns>
+        public static OSSConfig BuildOssConfig(bool isDev, string accessKeyId, string accessKeySecret, string bucket = null)
+        {
+            var ossInternal = bool.Parse(ConfigurationManager.Settings.Variables["OSS.Internal"]);
+            var OSSConfig = new OSSConfig
+            {
+                DomainUrl = isDev ? "https://olscdndev.olssglobal.com/" : "https://olscdn.olssglobal.com/",
+                InternalDomainUrl = !ossInternal ? "" : isDev ? "https://olss-ols-cdn-dev.oss-cn-shanghai-internal.aliyuncs.com/" : "http://olss-ols-cdn.oss-cn-shanghai-internal.aliyuncs.com/",
+                AccessKeyId = accessKeyId,
+                AccessKeySecret = accessKeySecret,
+                EndPoint = !ossInternal ? "oss-cn-shanghai.aliyuncs.com" : "oss-cn-shanghai-internal.aliyuncs.com"
+            };
+            if (string.IsNullOrEmpty(bucket))
+            {
+                // 设置默认bucket
+                OSSConfig.OSSBucket = isDev ? "olss-ols-cdn-dev" : "olss-ols-cdn";
+            }
+            else
+            {
+                OSSConfig.OSSBucket = bucket;
+            }
+            return OSSConfig;
+        }
+    }
+}

+ 184 - 0
JiaZhiQuan.Common/AliOSS/FileUpload.cs

@@ -0,0 +1,184 @@
+using Aliyun.OSS;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.AliOSS
+{
+    public class FileUpload
+    {
+        private static readonly string[] ImageFileExtensions = new[] { "png", "jpg", "jpeg", "gif", "bmp" };
+
+        public async static Task<UploadResult> UploadFromRequest(IHttpClientFactory httpClientFactory, IFormFile file, string destFileName, string destDir, OSSConfig config, int maxSize = 2, bool isImage = true)
+        {
+            OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
+            return await UploadFromRequest(httpClientFactory, file, destFileName, destDir, config, ossClient, maxSize, isImage);
+        }
+
+        public class UploadResult
+        {
+            public int width { get; set; }
+            public int height { get; set; }
+            public string url { get; set; }
+        }
+
+        public async static Task<UploadResult> UploadFromRequest(IHttpClientFactory httpClientFactory, IFormFile file, string destFileName, string destDir, OSSConfig config, OssClient ossClient, int maxSize = 2, bool isImage = true)
+        {
+            var extension = Path.GetExtension(file.FileName);
+            if (isImage && ImageFileExtensions.All(e => !extension.ToLower().Equals("." + e)))
+            {
+                throw new LogicalException("仅支持上传图片格式", ErrorCodes.UploadFileFormatError);
+            }
+
+            if (file.Length > maxSize * 1024 * 1024)
+            {
+                throw new LogicalException("上传的" + (isImage ? "图片" : "文件") + "不能大于" + maxSize + "M", ErrorCodes.UploadFileSizeLimitError);
+            }
+
+            var dir = destDir.Trim(new char[] { '\\', '/' });
+            if (string.IsNullOrEmpty(dir))
+            {
+                destFileName = destFileName.Trim(new char[] { '\\', '/' }) + extension;
+            }
+            else
+            {
+                destFileName = dir + "/" + destFileName.Trim(new char[] { '\\', '/' }) + extension;
+            }
+
+            using Stream fileStream = file.OpenReadStream();
+
+            if (isImage)
+            {
+                int width = 0;
+                int height = 0;
+
+                string url = await UploadToAliyun(destFileName, fileStream, config, ossClient);
+
+                var reqUrl = string.IsNullOrEmpty(config.InternalDomainUrl) ? url : config.InternalDomainUrl + destFileName;
+
+                var client = httpClientFactory.CreateClient();
+                client.Timeout = new TimeSpan(0, 0, 2);
+                try
+                {
+                    var content = JToken.Parse(await client.GetStringAsync(reqUrl + "?x-oss-process=image/info"));
+                    width = content.Value<JToken>("ImageWidth").Value<int>("value");
+                    height = content.Value<JToken>("ImageHeight").Value<int>("value");
+                }
+                catch (Exception ex)
+                {
+                    LoggerManager.Logger.Error(ex, "获取图片属性出错 >>> " + reqUrl + "\r\n" + ex.Message);
+                }
+                return new UploadResult()
+                {
+                    url = url,
+                    width = width,
+                    height = height
+                };
+            }
+            else
+            {
+                var url = await UploadToAliyun(destFileName, fileStream, config, ossClient);
+                return new UploadResult()
+                {
+                    url = url
+                };
+            }
+
+        }
+
+        //public static string UploadToAliyun(string destFilePath, string localFilePath, OSSConfig config)
+        //{
+        //    OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
+        //    return UploadToAliyun(destFilePath, localFilePath, config.OSSBucket, config.DomainUrl, ossClient);
+        //}
+
+        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, OSSConfig config, ObjectMetadata metadata = null)
+        {
+            OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
+            return await UploadToAliyun(destFilePath, stream, config.OSSBucket, config.DomainUrl, ossClient, metadata);
+        }
+
+        //public static string UploadToAliyun(string destFilePath, string localFilePath, OSSConfig config, OssClient ossClient)
+        //{
+        //    return UploadToAliyun(destFilePath, localFilePath, config.OSSBucket, config.DomainUrl, ossClient);
+        //}
+
+        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, OSSConfig config, OssClient ossClient, ObjectMetadata metadata = null)
+        {
+            return await UploadToAliyun(destFilePath, stream, config.OSSBucket, config.DomainUrl, ossClient, metadata);
+        }
+
+        //public async static string UploadToAliyun(string destFilePath, string localFilePath, string ossBucket, string domainUrl, OssClient ossClient)
+        //{
+
+        //    var rst = await Task<PutObjectResult>.Factory.FromAsync(ossClient.BeginPutObject, ossClient.EndPutObject, ossBucket, localFilePath, null);
+
+        //    var result = ossClient.PutObject(ossBucket, destFilePath, localFilePath);
+        //    if (result.HttpStatusCode == System.Net.HttpStatusCode.OK)
+        //    {
+        //        return domainUrl + destFilePath;
+        //    }
+        //    else
+        //    {
+        //        throw new LogicalException("上传失败", ErrorCodes.UploadFileToOSSError);
+        //    }
+        //}
+
+        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, string ossBucket, string domainUrl, OssClient ossClient, ObjectMetadata metadata = null)
+        {
+            using (stream)
+            {
+                stream.Position = 0;
+                var tcs = new TaskCompletionSource<PutObjectResult>();
+                ossClient.BeginPutObject(ossBucket, destFilePath, stream, metadata, iar =>
+                {
+                    tcs.SetResult(ossClient.EndPutObject(iar));
+                }, null);
+                var result = await tcs.Task;
+                // var result = await Task<PutObjectResult>.Factory.FromAsync(ossClient.BeginPutObject, ossClient.EndPutObject, ossBucket, destFilePath, stream, null);
+                if (result.ResponseStream != null)
+                {
+                    result.ResponseStream.Close();
+                }
+                if (result.HttpStatusCode == System.Net.HttpStatusCode.OK)
+                {
+                    return domainUrl + destFilePath;
+                }
+                else
+                {
+                    throw new LogicalException("上传失败", ErrorCodes.UploadFileToOSSError);
+                }
+            }
+        }
+
+
+        public static string GetFileIdByUrl(string url)
+        {
+            if (string.IsNullOrEmpty(url))
+            {
+                return string.Empty;
+            }
+            url = url.Split(new char[] { '?' })[0];
+            var parts = url.Split(new string[] { "cdndev.olssglobal.com/", "olscdn.olssglobal.com/", "videodev.olssglobal.com/", "video.olssglobal.com/" }, StringSplitOptions.None);
+            if (parts.Length > 1)
+            {
+                return parts[parts.Length - 1];
+            }
+            return string.Empty;
+        }
+
+
+        public static void RemoveFile(List<string> keys, string bucketName, OssClient ossClient)
+        {
+            ossClient.DeleteObjects(new DeleteObjectsRequest(bucketName, keys));
+        }
+
+    }
+}

+ 17 - 0
JiaZhiQuan.Common/AliOSS/OSSConfig.cs

@@ -0,0 +1,17 @@
+namespace JiaZhiQuan.Common.AliOSS
+{
+    public class OSSConfig
+    {
+        public string OSSBucket { get; set; }
+
+        public string DomainUrl { get; set; }
+
+        public string InternalDomainUrl { get; set; }
+
+        public string AccessKeyId { get; set; }
+
+        public string AccessKeySecret { get; set; }
+
+        public string EndPoint { get; set; } = "oss-cn-shanghai-internal.aliyuncs.com";
+    }
+}

+ 17 - 0
JiaZhiQuan.Common/AliOSS/OSSDirectory.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace JiaZhiQuan.Common.AliOSS
+{
+    public static class OSSDirectory
+    {
+        /// <summary>
+        /// 用户邀请海报的目录
+        /// </summary>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        public static string GetUserInvitationPoster(string fileName)
+        {
+            return $"member/invite/{fileName}";
+        }
+    }
+}

+ 250 - 0
JiaZhiQuan.Common/AliVod/AliVODHelper.cs

@@ -0,0 +1,250 @@
+using Aliyun.Acs.Core;
+using Aliyun.Acs.Core.Profile;
+using Aliyun.Acs.vod.Model.V20170321;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JiaZhiQuan.Common.AliVod
+{
+    public class AliVODHelper
+    {
+        readonly VodConfig config;
+        DefaultAcsClient client;
+
+        public AliVODHelper(VodConfig config)
+        {
+            this.config = config;
+        }
+
+        public DefaultAcsClient GetVodClient()
+        {
+            //string regionId = "cn-shanghai";
+            //IClientProfile profile = DefaultProfile.GetProfile(regionId, config.AccessKeyId, config.AccessKeySecret);
+            //// DefaultProfile.AddEndpoint(regionId, regionId, "vod", "vod." + regionId + ".aliyuncs.com");
+            //return new DefaultAcsClient(profile);
+
+            if (client == null)
+            {
+                lock (this)
+                {
+                    if (client == null)
+                    {
+                        string regionId = "cn-shanghai";
+                        IClientProfile profile = DefaultProfile.GetProfile(regionId, config.AccessKeyId, config.AccessKeySecret);
+                        // DefaultProfile.AddEndpoint(regionId, regionId, "vod", "vod." + regionId + ".aliyuncs.com");
+                        client = new DefaultAcsClient(profile);
+                    }
+                    return client;
+                }
+            }
+            else
+            {
+                return client;
+            }
+        }
+
+        /// <summary>
+        /// 人工批量审核
+        /// </summary>
+        /// <param name="videoIds">最多20条</param>
+        /// <param name="pass">是否通过</param>
+        /// <param name="reason">如果未通过,给出理由</param>
+        /// <param name="comment">审核备注</param>
+        /// <returns></returns>
+        public CreateAuditResponse ManualAudit(List<string> videoIds, bool pass, string reason, string comment)
+        {
+            var req = new CreateAuditRequest();
+            JArray auditContents = new JArray();
+            foreach (var videoId in videoIds)
+            {
+                JObject auditContent = new JObject();
+                auditContent.Add("VideoId", videoId);
+                auditContent.Add("Status", pass ? "Normal" : "Blocked");
+                if (!pass && !string.IsNullOrEmpty(reason)) {
+                    auditContent.Add("Reason", reason);
+                }
+                if (!string.IsNullOrEmpty(comment))
+                {
+                    auditContent.Add("Comment", comment);
+                }
+                auditContents.Add(auditContent);
+            }
+            req.AuditContent = auditContents.ToString();
+            return GetVodClient().GetAcsResponse(req);
+        }
+
+        public CreateAuditResponse AutoManualAudit(string videoId)
+        {
+            var req = new CreateAuditRequest();
+            JArray auditContents = new JArray();
+            JObject auditContent = new JObject();
+            auditContent.Add("VideoId", videoId);
+            auditContent.Add("Status", "Normal");
+            auditContent.Add("Comment", "机审通过,人工自动通过");
+            auditContents.Add(auditContent);
+            req.AuditContent = auditContents.ToString();
+            return GetVodClient().GetAcsResponse(req);
+        }
+
+        /// <summary>
+        /// 获取视频上传地址和凭证
+        /// </summary>
+        /// <param name="title">长度不超过128个字符或汉字。</param>
+        /// <param name="fileName">必须带扩展名,且扩展名不区分大小写</param>
+        /// <param name="tags">
+        /// 最多不超过16个标签,多个用逗号分隔。单个标签不超过32个字符或汉字。
+        /// </param>
+        /// <param name="cateId">分类</param>
+        /// <returns></returns>
+        public CreateUploadVideoResponse GetUploadVideoInfo(string title, string fileName, string tags, long cateId)
+        {
+            CreateUploadVideoRequest request = new CreateUploadVideoRequest();
+            request.Title = title;
+            request.FileName = fileName;
+            request.Tags = tags;
+            request.CateId = cateId;
+            request.WorkflowId = config.AutofitDefaultWorkflow;
+            // 发起请求,并得到响应结果
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 刷新视频上传凭证
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <param name="client"></param>
+        public RefreshUploadVideoResponse RefreshUploadVideoInfo(string videoId)
+        {
+            RefreshUploadVideoRequest request = new RefreshUploadVideoRequest();
+            request.VideoId = videoId;
+            // 发起请求,并得到 response
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取图片上传地址和凭证
+        /// </summary>
+        /// <param name="imageType">
+        /// 图片类型。取值范围:default(默认)cover(封面)控制台暂时只支持default类型的图片管理。
+        /// </param>
+        /// <param name="imageExt">
+        /// 图片文件扩展名。取值范围:png jpg jpeg gif 默认值:png
+        /// </param>
+        public CreateUploadImageResponse GetUploadImageInfo(string imageType, string imageExt)
+        {
+            CreateUploadImageRequest request = new CreateUploadImageRequest();
+            request.ImageType = imageType;
+            request.ImageExt = imageExt;
+            // 发起请求,并得到 response
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取视频播放地址,8小时有效
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <returns></returns>
+        public GetPlayInfoResponse GetPlayInfo(string videoId)
+        {
+            GetPlayInfoRequest request = new GetPlayInfoRequest();
+            request.VideoId = videoId;
+            request.Definition = "AUTO,HD,SD,OD";
+            request.AuthTimeout = 3600 * 8; // 8小时
+            //request.Formats = "mp4";
+            //request.OutputType = "oss";
+            //request.PlayConfig = JsonConvert.SerializeObject(new { EncryptType = "Unencrypted" });
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取视频播放地址(试看)
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <param name="previewSeconds">试看多少秒</param>
+        /// <returns></returns>
+        public GetPlayInfoResponse GetPlayInfo(string videoId, int previewSeconds)
+        {
+            GetPlayInfoRequest request = new GetPlayInfoRequest();
+            request.VideoId = videoId;
+            request.Definition = "AUTO,HD,SD,OD";
+            request.AuthTimeout = 3600 * 2; // 两小时
+            request.PlayConfig = JsonConvert.SerializeObject(new
+            {
+                PreviewTime = previewSeconds
+            });
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取视频播放凭证
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <returns></returns>
+        public GetVideoPlayAuthResponse GetPlayAuth(string videoId)
+        {
+            GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
+            request.VideoId = videoId;
+            request.AuthInfoTimeout = 3000;
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取视频信息
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <returns></returns>
+        public GetVideoInfoResponse GetVideoInfo(string videoId)
+        {
+            GetVideoInfoRequest request = new GetVideoInfoRequest();
+            request.VideoId = videoId;
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 获取原始视频信息
+        /// </summary>
+        /// <param name="videoId"></param>
+        /// <returns></returns>
+        public GetMezzanineInfoResponse GetMezzanineInfo(string videoId)
+        {
+            var request = new GetMezzanineInfoRequest();
+            request.ActionName = "GetMezzanineInfo";
+            request.AuthTimeout = 60 * 60 * 24 * 15L;
+            request.VideoId = videoId;
+            request.OutputType = "cdn";
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 批量获取视频信息
+        /// </summary>
+        /// <param name="videoIds">
+        /// 逗号分隔,最多支持20个
+        /// </param>
+        /// <returns></returns>
+        public GetVideoInfosResponse GetVideoInfos(string videoIds)
+        {
+            GetVideoInfosRequest request = new GetVideoInfosRequest();
+            request.VideoIds = videoIds;
+            return GetVodClient().GetAcsResponse(request);
+        }
+
+        /// <summary>
+        /// 批量删除视频
+        /// </summary>
+        /// <param name="videoIds">
+        /// 逗号分隔,最多支持20个。
+        /// </param>
+        /// <returns></returns>
+        public DeleteVideoResponse DeleteVideos(string videoIds)
+        {
+            DeleteVideoRequest request = new DeleteVideoRequest();
+            request.VideoIds = videoIds;
+            return GetVodClient().GetAcsResponse(request);
+        }
+    }
+}

+ 24 - 0
JiaZhiQuan.Common/AliVod/VodConfig.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.AliVod
+{
+    public class VodConfig
+    {
+        public string AccessKeyId { get; set; }
+
+        public string AccessKeySecret { get; set; }
+
+        public long DiaryCategoryIdProd { get; set; } = 1000628461;
+        public long DiaryCategoryIdDev { get; set; } = 1000628460;
+
+        public long GoodsCategoryIdProd { get; set; } = 1000628793;
+
+        public long GoodsCategoryIdDev { get; set; } = 1000628792;
+
+        public string AutofitDefaultWorkflow { get; set; } = "8dbdc8a0cfba27a4eb02264b1ac7dbc9";
+
+        public string AutofitEncryptWorkflow { get; set; } = "689c43028cb8dc8a132a210cc9f12906";
+    }
+}

+ 20 - 0
JiaZhiQuan.Common/Attributes/CreatorSpaceTypeDescAttribute.cs

@@ -0,0 +1,20 @@
+using System;
+
+namespace JiaZhiQuan.Common.Attributes
+{
+    public class CreatorSpaceTypeDescAttribute : Attribute
+    {
+        public CreatorSpaceTypeDescAttribute(string name, int value, float order, bool defaultCreate)
+        {
+            Name = name;
+            Value = value;
+            Order = order;
+            DefaultCreate = defaultCreate;
+        }
+
+        public string Name { get; set; }
+        public int Value { get; set; }
+        public float Order { get; set; }
+        public bool DefaultCreate { get; set; }
+    }
+}

+ 14 - 0
JiaZhiQuan.Common/Attributes/DescriptionAttribute.cs

@@ -0,0 +1,14 @@
+using System;
+
+namespace JiaZhiQuan
+{
+    public class DescriptionAttribute : Attribute
+    {
+        public string Description { get; set; }
+
+        public DescriptionAttribute(string description)
+        {
+            Description = description;
+        }
+    }
+}

+ 101 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Activity.cs

@@ -0,0 +1,101 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public const int ActivityCzdPointListCacheSecs = 60;
+
+        public static string ActivityCzdPointList(int contractId)
+        {
+            return GenerateKey("activity_czd_pointlist:" + contractId);
+        }
+
+        public const int ActivityConfigCacheSecs = 60;
+
+        public static string ActivityConfigCache(int activityId)
+        {
+            return GenerateKey("activity_config:" + activityId);
+        }
+
+        /// <summary>
+        /// 阅读量大比拼预警邮件提醒,一个小时内最多发一次提醒邮件
+        /// </summary>
+        public const int ActivityYdldbpWarningCacheSecs = 60 * 60;
+
+        public static string ActivityYdldbpWarningCache()
+        {
+            return GenerateKey("activity_warning:ydldbp");
+        }
+
+        /// <summary>
+        /// 阅读量大比拼预警记录,同内容一小时内只提示一次
+        /// </summary>
+        public const int ActivityYdldbpWarningRecordCacheSecs = 60 * 60;
+
+        public static string ActivityYdldbpWarningRecordCache(long userId, long postId)
+        {
+            return GenerateKey($"activity_warning_record:ydldbp:{userId}_{postId}");
+        }
+
+        /// <summary>
+        /// 活动查看量
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        public static string ActivityQueryCount()
+        {
+            return GenerateKey($"activity_querycount");
+        }
+
+        /// <summary>
+        /// 打卡
+        /// </summary>
+        /// <returns></returns>
+        public static string ActivityDakaDeviceCache(int id, string time, bool isFinal = false)
+        {
+            string str = "";
+            if (isFinal) str = "final_";
+            return GenerateKey($"activity_daka:devicelist:{str}id_{id}_{time}");
+        }
+        /// <summary>
+        /// 用户打卡今天是否打过卡
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="time"></param>
+        /// <returns></returns>
+        public static string ActivityDakaRecordsCache(int id, string time)
+        {
+            return GenerateKey($"activity_daka:records:id_{id}_{time}");
+        }
+        /// <summary>
+        /// 用户用价值币购买次数
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="time"></param>
+        /// <returns></returns>
+        public static string ActivityDakaPointsCache(int id, string time)
+        {
+            return GenerateKey($"activity_daka:points:id_{id}_{time}");
+        }
+
+        /// <summary>
+        /// 用户普通抽奖剩余次数
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        public static string ActivityDakaNormalDrawLeftCount(int id)
+        {
+            return GenerateKey($"activity_daka:normal_drawleft_count:id_{id}");
+        }
+
+        /// <summary>
+        /// 用户终极抽奖剩余次数
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        public static string ActivityDakafinalDrawLeftCount(int id)
+        {
+            return GenerateKey($"activity_daka:final_drawleft_count:id_{id}");
+        }
+    }
+}

+ 68 - 0
JiaZhiQuan.Common/Cache/CacheKeys.App.cs

@@ -0,0 +1,68 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+
+        public const int AppVersionCacheSecs = 60 * 1;
+
+        public static string AppVersionAndroid()
+        {
+            return GenerateKey("app_version:android");
+        }
+
+        public static string AppVersionIOS()
+        {
+            return GenerateKey("app_version:ios");
+        }
+
+        public const int AppRecommendSettingCacheSecs = 60 * 1;
+
+        public static string AppRecommendSetting()
+        {
+            return GenerateKey("app_recommend_setting");
+        }
+
+
+        public const int AppNewsUsersCacheSecs = 60 * 1;
+
+        public static string AppNewsUsers()
+        {
+            return GenerateKey("app_news_users");
+        }
+
+
+        public const int AppIndexBannerCacheSecs = 60 * 1;
+        public static string AppIndexBanner()
+        {
+            return GenerateKey("app_index_banner");
+        }
+
+        public const int AppIndexBannerPostsCacheSecs = 60 * 1;
+        public static string AppIndexBannerPosts()
+        {
+            return GenerateKey("app_index_banner_posts");
+        }
+
+        public static string AppDeviceOnLine()
+        {
+            return GenerateKey("app_device_online");
+        }
+
+
+        public const int ApiInvocationLimitCacheSecs = 60 * 60;
+        /// <summary>
+        /// 接口访问限制,如果次数超过5次,则封禁1小时
+        /// </summary>
+        public static string ApiInvocationLimit(string ip)
+        {
+            return GenerateKey($"api_inv_limit:{ip}");
+        }
+
+        public const int AppMallIndexBannerCacheSecs = 60 * 1;
+        public static string AppMallIndexBanner()
+        {
+            return GenerateKey("app_mall_index_banner");
+        }
+    }
+}

+ 12 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Feedback.cs

@@ -0,0 +1,12 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        public const int FeedbackTypesCacheSecs = 60;
+
+        public static string FeedbackTypes (int type)
+        {
+            return GenerateKey("feedback:types:" + type);
+        }
+    }
+}

+ 25 - 0
JiaZhiQuan.Common/Cache/CacheKeys.IM.cs

@@ -0,0 +1,25 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        /// 用户在线状态判断,过期时间
+        /// </summary>
+        public static int UserClientOnlineExpirationTime = 30;
+        public static string UserClientOnline(long userId)
+        {
+            return GenerateKey($"im:online:{userId}");
+        }
+
+        /// <summary>
+        /// 会话最后一条消息的内容
+        /// </summary>
+        /// <param name="chatId"></param>
+        /// <returns></returns>
+        public static int ChatLastMessageInfoExpirationTime = 60 * 60;
+        public static string ChatLastMessageInfo(long chatId)
+        {
+            return GenerateKey($"im:chat:lastMessage:{chatId}");
+        }
+    }
+}

+ 14 - 0
JiaZhiQuan.Common/Cache/CacheKeys.MP.cs

@@ -0,0 +1,14 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public const int MPPostWarningCacheSecs = 60 * 60;  // 缓存1小时
+
+        public static string MPPostWarning(long postId)
+        {
+            return GenerateKey($"mp:postwarning:{postId}");
+        }
+
+    }
+}

+ 64 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Mall.cs

@@ -0,0 +1,64 @@
+using System;
+
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        /// 商品推荐列表
+        /// </summary>
+        /// <returns></returns>
+        public static string GoodsRecommendList(DateTime dateTime)
+        {
+            return GenerateKey($"mall:goods_recommend:{dateTime.ToString("yyyy-MM-dd")}");
+        }
+
+        /// <summary>
+        /// 用户推荐下标
+        /// </summary>
+        /// <param name="dateTime"></param>
+        /// <returns></returns>
+        public static string GoodsRecommendCacheCursor(string clientKey)
+        {
+            return GenerateKey($"mall:goods_rcml_cursor:{clientKey}");
+        }
+
+        /// <summary>
+        /// 缓存24小时
+        /// </summary>
+        public const int OrderMindSellerDeliveryCacheSecs = 60 * 60 * 24;
+        
+        /// <summary>
+        /// 提醒卖家发货行为记录
+        /// </summary>
+        /// <param name="orderId">买家的订单</param>
+        /// <param name="date">当前日期</param>
+        public static string OrderMindSellerDelivery(long orderId, DateTime date)
+        {
+            return GenerateKey($"mall:order_delivery_remind:{date:MMdd}:{orderId}");
+        }
+
+        /// <summary>
+        /// 缓存24小时
+        /// </summary>
+        public const int OrderMindBuyerReceiptCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 提醒买家收货行为记录
+        /// </summary>
+        /// <param name="orderId"></param>
+        /// <param name="date">当前日期</param>
+        public static string OrderMindBuyerReceipt(long orderId, DateTime date)
+        {
+            return GenerateKey($"mall:order_receipt_remind:{date:MMdd}:{orderId}");
+        }
+
+        /// <summary>
+        /// 货号自增序号缓存
+        /// </summary>
+        /// <param name="date">当前日期</param>
+        public static string GoodsNoSequence(DateTime date) {
+            return GenerateKey($"ue:goods_no_sequence:{date:yyyyMMdd}");
+        }
+    }
+}

+ 139 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Post.cs

@@ -0,0 +1,139 @@
+using System;
+
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        ///  文章缓存1分钟
+        /// </summary>
+        public const int PostDetailCacheSecs = 60;
+
+        /// <summary>
+        /// 文章详情缓存编号
+        /// </summary>
+        public static string PostDetail(long postId)
+        {
+            return GenerateKey($"post_detail:{postId}");
+        }
+
+        /// <summary>
+        /// 1天
+        /// </summary>
+        public const int PostRecommendListCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 文章推荐列表缓存的Key
+        /// </summary>
+        /// <param name="day">当天几号</param>
+        /// <param name="userId">非登录用户,传0</param>
+        /// <param name="categoryType">如果没有,则传null</param>
+        /// <param name="contentType">null表示所有,1为带图片的,2为带视频的</param>
+        /// <param name="hasTopic">如果没有,则传null</param>
+        public static string PostRecommendList(int day, long userId, int? categoryType, int? contentType, bool? hasTopic)
+        {
+            return GenerateKey($"post_rcml_{day}:{userId}:{categoryType?.ToString() ?? "null"}_{contentType?.ToString() ?? "null"}" + (hasTopic == null ? "" : hasTopic.Value ? "_t1" : "_t0"));
+        }
+
+        public const int PostRecommendCacheCursorSecs = 60 * 60 * 48;
+
+        /// <summary>
+        /// 文章推荐缓存用户端访问的游标,内容是已取得的最后一个`{postId}_{index}_{over}`
+        /// </summary>
+        /// <param name="clientKey">客户端编号</param>
+        /// <param name="categoryType">如果没有,则传null</param>
+        /// <param name="contentType">null表示所有,1为带图片的,2为带视频的</param>
+        /// <param name="hasTopic">如果没有,则传null</param>
+        public static string PostRecommendCacheCursor(string clientKey, int? categoryType, int? contentType, bool? hasTopic)
+        {
+            return GenerateKey($"post_rcml_cursor:{clientKey}:{categoryType?.ToString() ?? "null"}_{contentType?.ToString() ?? "null"}" + (hasTopic == null ? "" : hasTopic.Value ? "_t1" : "_t0"));
+        }
+
+        /// <summary>
+        /// 新文章推荐缓存
+        /// </summary>
+        /// <param name="categoryType">如果没有,则传null</param>
+        /// <param name="contentType">null表示所有,1为带图片的,2为带视频的</param>
+        /// <param name="hasTopic">如果没有,则传null</param>
+        public static string PostNewRecommendCache(string time, int? categoryType, int? contentType, bool? hasTopic)
+        {
+            return GenerateKey($"post_rcml_new:{time}:{categoryType?.ToString() ?? "null"}_{contentType?.ToString() ?? "null"}" + (hasTopic == null ? "" : hasTopic.Value ? "_t1" : "_t0"));
+        }
+
+
+        public const int PostContentCacheSecs = 20;
+
+        /// <summary>
+        /// 文章内容缓存,用于用户发布,在AI审核时优先从缓存获取
+        /// </summary>
+        /// <param name="postId"></param>
+        /// <returns></returns>
+        public static string PostContent(long postId)
+        {
+            return GenerateKey($"post_content:{postId}");
+        }
+
+
+        public const int PostNewNotificationCacheSecs = 6 * 60 * 60; // 6小时
+
+        /// <summary>
+        /// 发动态后,6小时内发的新动态不会通知,1个自然日最多1条
+        /// </summary>
+        /// <returns></returns>
+        public static int PostNewNotificationCacheTime()
+        {
+            // 获取当前时间
+            DateTime currentTime = DateTime.Now;
+            // 获取今天结束的时间(明天的凌晨)
+            DateTime endOfDay = currentTime.Date.AddDays(1);
+            // 计算时间差
+            TimeSpan timeRemaining = endOfDay - currentTime;
+            // 获取剩余秒数
+            int secondsRemaining = (int)timeRemaining.TotalSeconds;
+
+            // 如果剩余时间大于6小时,则返回距离今天结束剩余的秒数
+            if(secondsRemaining > PostNewNotificationCacheSecs)
+            {
+                return secondsRemaining;
+            }
+            // 如果剩余时间不足6小时,则返回6小时
+            else
+            {
+                return PostNewNotificationCacheSecs;
+            }
+        }
+
+        /// <summary>
+        /// 一个人发了动态之后,将状态缓存到Redis,判断是否需要通知
+        /// </summary>
+        public static string PostNewNotification(long userId)
+        {
+            return GenerateKey($"post_new:{userId}");
+        }
+
+
+        /// <summary>
+        /// 一个人发了商品之后,将状态缓存到Redis,判断是否需要通知
+        /// </summary>
+        public static string GoodsNewNotification(long userId)
+        {
+            return GenerateKey($"mall:goods_new:{userId}");
+        }
+
+        /// <summary>
+        /// 发商品后,1个自然日最多1条通知
+        /// </summary>
+        /// <returns></returns>
+        public static int GoodsNewNotificationCacheTime()
+        {
+            // 获取当前时间
+            DateTime currentTime = DateTime.Now;
+            // 获取今天结束的时间(明天的凌晨)
+            DateTime endOfDay = currentTime.Date.AddDays(1);
+            // 计算时间差
+            TimeSpan timeRemaining = endOfDay - currentTime;
+            // 获取剩余秒数
+            return (int)timeRemaining.TotalSeconds;
+        }
+    }
+}

+ 127 - 0
JiaZhiQuan.Common/Cache/CacheKeys.PushMsg.cs

@@ -0,0 +1,127 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public const int PushMsgThumbsupCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 点赞消息推送缓存,对于同一目标点赞,一天只收一次通知
+        /// </summary>
+        /// <param name="fromUserId">点赞的用户Id</param>
+        /// <param name="type">点赞目标类型</param>
+        /// <param name="targetId">目标编号</param>
+        /// <returns></returns>
+        public static string PushMsgThumbsupRepeatability(long fromUserId, ThumbsupTargetType type, long targetId)
+        {
+            return GenerateKey($"push_thumbsup:{fromUserId}:{(int)type}:{targetId}");
+        }
+
+
+
+        public const int PushMsgThumbsupReceivePerMinCacheSecs = 60;
+
+        /// <summary>
+        /// 同一用户一分钟内只收到1次点赞推送
+        /// </summary>
+        public static string PushMsgThumbsupReceivePerMin(long toUserId)
+        {
+            return GenerateKey($"push_thumbsup:m1:{toUserId}");
+        }
+
+
+        public const int PushMsgThumbsupReceivePerHourCacheSecs = 60 * 60;
+
+        /// <summary>
+        /// 同一用户一小时内只收到2次点赞推送
+        /// </summary>
+        public static string PushMsgThumbsupReceivePerHour(long toUserId)
+        {
+            return GenerateKey($"push_thumbsup:h1:{toUserId}");
+        }
+
+
+        public const int PushMsgThumbsupReceivePerDayCacheSecs = 24 * 60 * 60;
+
+        /// <summary>
+        /// 同一用户一天内只收到3次点赞推送
+        /// </summary>
+        public static string PushMsgThumbsupReceivePerDay(long toUserId)
+        {
+            return GenerateKey($"push_thumbsup:d1:{toUserId}");
+        }
+
+
+
+
+        public const int PushMsgFocusUserCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 关注消息推送缓存,对于同一目标关注,一天只收一次通知
+        /// </summary>
+        public static string PushMsgFocusRepeatability(long fromUserId, long toUserId)
+        {
+            return GenerateKey($"push_focus:{fromUserId}:{toUserId}");
+        }
+
+        /// <summary>
+        /// 用户一个小时内收到的关注通知数量
+        /// </summary>
+        public static string PushMsgFocusReceivePerHour(long toUserId)
+        {
+            return GenerateKey($"push_focus_count:h1:{toUserId}");
+        }
+
+
+        /// <summary>
+        /// 用户一天内收到的关注通知数量
+        /// </summary>
+        public static string PushMsgFocusReceivePerDay(long toUserId)
+        {
+            return GenerateKey($"push_focus_count:d1:{toUserId}");
+        }
+
+
+        public const int PushMsgCommentPerDayCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 同一ID对另一ID用户,一天最多3次评论,除非楼主回复了后,再进行提醒(清除逻辑放在了评论通知中)
+        /// </summary>
+        public static string PushMsgCommentPertDay(long fromUserId, long toUserId)
+        {
+            return GenerateKey($"push_comment:d1:{fromUserId}:{toUserId}");
+        }
+
+        public const int PushMsgCommentReceivePerHourCacheSecs = 60 * 60 * 24;
+
+        /// <summary>
+        /// 用户一个小时内收到的评论通知数量
+        /// </summary>
+        public static string PushMsgCommentReceivePerHour(long toUserId)
+        {
+            return GenerateKey($"push_comment_count:h1:{toUserId}");
+        }
+
+
+        public const int PushMsgCommentReceivePerDayCacheSecs = 24 * 60 * 60;
+
+        /// <summary>
+        /// 用户一天内收到的评论通知数量
+        /// </summary>
+        public static string PushMsgCommentReceivePerDay(long toUserId)
+        {
+            return GenerateKey($"push_comment_count:d1:{toUserId}");
+        }
+
+        public const int PushMsgUserConfigCacheSecs = 60 * 30;
+
+        /// <summary>
+        /// 推送用户配置
+        /// </summary>
+        public static string PushMsgUserConfig(long userId)
+        {
+            return GenerateKey($"push_userconfig:{userId}");
+        }
+
+    }
+}

+ 32 - 0
JiaZhiQuan.Common/Cache/CacheKeys.QT.cs

@@ -0,0 +1,32 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public const int QTRecentTradeDaysCacheSecs = 24 * 60 * 60;
+
+        public static string QTRecentTradeDaysBefore7(string date)
+        {
+            return GenerateKey("qt_recent_tradedays_before7:"  + date);
+        }
+
+        public static string QTRecentTradeDaysRound3(string date)
+        {
+            return GenerateKey("qt_recent_tradedays_round3:" + date);
+        }
+
+        public const int QTRealtimeSingleCacheSecs = 1;
+
+        public static string QTRealtimeSingle(string code)
+        {
+            return GenerateKey("qt_realtime_single:" + code);
+        }
+
+        public const int QTSuspensionDataListCacheSecs = 24 * 60 * 60;
+
+        public static string QTSuspensionDataList(string date)
+        {
+            return GenerateKey("qt_suspensions:" + date);
+        }
+    }
+}

+ 15 - 0
JiaZhiQuan.Common/Cache/CacheKeys.RCIM.cs

@@ -0,0 +1,15 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        /// 用户在线状态判断,过期时间
+        /// </summary>
+        public static int RCIMTokenKeyExpirationTime = 30 * 24 * 60 * 60;
+        public static string RCIMTokenKey(string rcUserId)
+        {
+            return GenerateKey($"rcim:token:{rcUserId}");
+        }
+
+    }
+}

+ 27 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Sms.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        /// 手机号每天发送短信次数限制
+        /// </summary>
+        /// <param name="mobile"></param>
+        /// <returns></returns>
+        public static string MobileDayLimit(string mobile)
+        {
+            return GenerateKey($"send_sms:day_limit:{mobile}");
+        }
+
+        /// <summary>
+        /// 连续发送的短信次数限制
+        /// </summary>
+        /// <param name="mobile"></param>
+        /// <returns></returns>
+        public static string ContinuousLimit(string mobile)
+        {
+            return GenerateKey($"send_sms:continous_limit:{mobile}");
+        }
+    }
+}

+ 55 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Statistics.cs

@@ -0,0 +1,55 @@
+using System;
+
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public static string StatisticPostReadMaxTimesPerUser(DateTime date, long userId)
+        {
+            return GenerateKey("stat_postread_mt_pu:" + date.ToString("MMdd") + ":" + userId);
+        }
+
+        public static string StatisticPostReadUserPost(DateTime date, long userId, long postId)
+        {
+            return GenerateKey("stat_postread_up:" + date.ToString("MMdd") + ":" + userId + ":" + postId);
+        }
+
+        public static string StatisticPostReadClientIdPost(DateTime date, string clientId, long postId)
+        {
+            return GenerateKey("stat_postread_cp:" + date.ToString("MMdd") + ":" + clientId + ":" + postId);
+        }
+
+        public static string StatisticPostReadMaxTimesPerIP(DateTime date, string ip, long postId)
+        {
+            return GenerateKey("stat_postread_mt_pi:" + date.ToString("MMdd") + ":" + ip + ":" + postId);
+        }
+
+        /// <summary>
+        /// 每天每个用户分享次数缓存
+        /// </summary>
+        public static string StatisticPostSahreMaxTimesPerUser(DateTime date, long userId)
+        {
+            return GenerateKey("stat_postshare_mt_pu:" + date.ToString("MMdd") + ":" + userId);
+        }
+        /// <summary>
+        /// 每天每个用户每篇文章分享次数缓存
+        /// </summary>
+        public static string StatisticPostSahreMaxTimesPerUserPerPost(DateTime date, long userId, long postId)
+        {
+            return GenerateKey("stat_postshare_mt_pupp:" + date.ToString("MMdd") + ":" + userId + ":" + postId);
+        }
+
+        /// <summary>
+        /// 每天每个人访问的用户主页缓存
+        /// </summary>
+        /// <param name="date">日期</param>
+        /// <param name="userId">访问者编号</param>
+        /// <param name="pageUserId">受访者编号</param>
+        public static string StatisticPersonalPageViewUser2User(DateTime date, long userId, long pageUserId)
+        {
+            return GenerateKey("stat_personalpage_uu:" + date.ToString("MMdd") + ":" + userId + ":" + pageUserId);
+        }
+
+    }
+}

+ 17 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Topic.cs

@@ -0,0 +1,17 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        
+        /// <summary>
+        /// 话题查看量
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        public static string TopicQueryCount()
+        {
+            return GenerateKey($"topic:querycount");
+        }
+
+    }
+}

+ 124 - 0
JiaZhiQuan.Common/Cache/CacheKeys.User.cs

@@ -0,0 +1,124 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        /// <summary>
+        /// 用户签到记录缓存
+        /// </summary>
+        public static string UserSign(long userId)
+        {
+            return GenerateKey($"sign:{userId}");
+        }
+
+        /// <summary>
+        /// 用于缓存用户登录记录,以天为单位,值类型为 UserStateCacheModel{id, state, date}
+        /// </summary>
+        public static string UserState(string userId)
+        {
+            return GenerateKey($"user_state:{userId}");
+        }
+
+        public const int UserStateValueCacheSecs = 60 * 1; // 一分钟
+        /// <summary>
+        /// 暂时用于验证用户是否已注销,值为 State 值。如果用户不存在,则为-1
+        /// </summary>
+        public static string UserStateValue(long userId)
+        {
+            return GenerateKey($"user_state_val:{userId}");
+        }
+
+        public const int UserTokenCacheSecs = 30 * 24 * 60 * 60;
+
+        public static string UserToken(string userId, string from)
+        {
+            return GenerateKey($"user_token:{userId}:{from ?? "default"}");
+        }
+
+
+        public static string WeixinLoginBackUrlCache(string guid)
+        {
+            return GenerateKey($"wx_login:{guid}");
+        }
+
+        public static string UserInitTags()
+        {
+            return GenerateKey("user_init_tags");
+        }
+
+        public const int UserPrivacySettingCacheSecs = 60;
+
+        public static string UserPrivacySetting(string userId)
+        {
+            return GenerateKey($"user_privacy_setting:{userId}");
+        }
+
+        public static string UserPrivacySetting(long userId)
+        {
+            return GenerateKey($"user_privacy_setting:{userId}");
+        }
+
+        public const int UserTagsCacheSecs = 60 * 10; // 10分钟
+        public static string UserTags(long userId)
+        {
+            return GenerateKey($"user_tags:{userId}");
+        }
+
+
+        /// <summary>
+        /// 用户邀请预警邮件提醒,一个小时内最多发一次提醒邮件
+        /// </summary>
+        public const int UserInvitationWarningCacheSecs = 60 * 60;
+
+        public static string UserInvitationWarningCache()
+        {
+            return GenerateKey("user_invite:warning");
+        }
+
+        /// <summary>
+        /// 用户邀请,同一用户一小时内只提示一次
+        /// </summary>
+        public const int UserInvitationWarningRecordCacheSecs = 60 * 60;
+
+        public static string UserInvitationWarningRecordCache(long userId)
+        {
+            return GenerateKey($"user_invite:warning:{userId}");
+        }
+
+        /// <summary>
+        /// 关注推荐用户列表过期时间,24x小时20分钟
+        /// </summary>
+        public const int FocusAndRecommendUserIdsCacheSecs = 60 * 60 * 24 + 60 * 20;
+        /// <summary>
+        /// 关注推荐用户列表
+        /// </summary>
+        public static string FocusAndRecommendUserIds()
+        {
+            return GenerateKey("focus_recommend_userids");
+        }
+
+        /// <summary>
+        /// 关注推荐用户列表用户游标过期时间,24小时
+        /// </summary>
+        public const int FocusUserCursorCacheSecs = 60 * 60 * 24;
+        /// <summary>
+        /// 关注推荐用户列表用户游标
+        /// </summary>
+        public static string FocusUserCursor(string userId)
+        {
+            return GenerateKey("focususer_cursor:" + userId);
+        }
+
+        /// <summary>
+        /// 关注推荐用户列表V2过期时间,24x小时20分钟
+        /// </summary>
+        public const int FocusAndRecommendPostIdsCacheSecs = 60 * 60 * 24 + 60 * 20;
+        /// <summary>
+        /// 关注推荐用户列表Vw
+        /// </summary>
+        public static string FocusAndRecommendPostIds()
+        {
+            return GenerateKey("focus_recommend_postids");
+        }
+    }
+}

+ 17 - 0
JiaZhiQuan.Common/Cache/CacheKeys.UserGrow.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+        /// <summary>
+        /// 当天用户完成任务情况
+        /// </summary>
+        /// <param name="mobile"></param>
+        /// <returns></returns>
+        public static string DailyUserTaskCompletion()
+        {
+            return GenerateKey($"user_grow:task_completion:{DateTime.Now.ToString("yyyy-MM-dd")}");
+        }
+    }
+}

+ 14 - 0
JiaZhiQuan.Common/Cache/CacheKeys.Vod.cs

@@ -0,0 +1,14 @@
+namespace JiaZhiQuan.Common
+{
+    public static partial class CacheKeys
+    {
+
+        public const int VideoPlayInfoCacheSecs = 60 * 10;  // 缓存10分钟
+
+        public static string VideoPlayInfo(string videoId)
+        {
+            return GenerateKey($"video_playinfo:{videoId}");
+        }
+
+    }
+}

+ 16 - 0
JiaZhiQuan.Common/Cache/CacheKeys.cs

@@ -0,0 +1,16 @@
+namespace JiaZhiQuan.Common
+{
+    /// <summary>
+    /// Redis中的Key值
+    /// </summary>
+    public static partial class CacheKeys
+    {
+        private const string PREFIX = "JZQ_";
+
+        private static string GenerateKey(string key)
+        {
+            return $"{PREFIX}{key}";
+        }
+
+    }
+}

+ 722 - 0
JiaZhiQuan.Common/Config/ConfigFromDb.cs

@@ -0,0 +1,722 @@
+using Dapper;
+using JiaZhiQuan.Common.ClassEnum;
+using MathNet.Numerics.Statistics.Mcmc;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Wicture.DbRESTFul.Infrastructure.Repository;
+
+namespace JiaZhiQuan.Common.Config
+{
+
+    public class ConfigFromDb
+    {
+        private readonly IConnectionManager _connectionManager;
+        private readonly ILogger _logger;
+
+        /// <summary>
+        /// 主分类
+        /// </summary>
+        public static List<KeyValuePair<int, string>> PrimaryTypes { get; set; } = new List<KeyValuePair<int, string>>();
+        /// <summary>
+        /// 在App展示的主分类
+        /// </summary>
+        public static List<KeyValuePair<int, string>> PrimaryTypesVisibleInApp { get; set; } = new List<KeyValuePair<int, string>>();
+        /// <summary>
+        /// 在App展示的主分类(仅用于审核)
+        /// </summary>
+        public static List<KeyValuePair<int, string>> PrimaryTypesVisibleInAppPreview { get; set; } = new List<KeyValuePair<int, string>>();
+
+        /// <summary>
+        /// APP 版本Preview配置,配置之后,接口会返回用于审核的测试数据。数据格式为“channel,os_version”
+        /// </summary>
+        public static List<string> AppPreviewTypeList { get; set; } = new List<string>();
+
+        /// <summary>
+        /// 资源所属的市场
+        /// </summary>
+        public static List<KeyValuePair<int, string>> ResourceMarkets { get; set; } = new List<KeyValuePair<int, string>>()
+        {
+            new KeyValuePair<int, string>(1, "A股"),
+            new KeyValuePair<int, string>(2, "港股"),
+            new KeyValuePair<int, string>(4, "美股")
+        };
+        /// <summary>
+        /// 社区
+        /// </summary>
+        public static List<AppIndexCusTabItem> AppIndexCusTabList = new List<AppIndexCusTabItem>();
+        /// <summary>
+        /// 商城
+        /// </summary>
+        public static List<AppIndexCusTabItem> MallAppIndexCusTabList = new List<AppIndexCusTabItem>();
+        /// <summary>
+        /// 不同天数的随机概率,2~15天
+        /// </summary>
+        public static List<List<int>> RandomProbabilities = new List<List<int>>
+        {
+            new List<int>{67, 33                                           },
+            new List<int>{50, 33, 17                                       },
+            new List<int>{40, 30, 20, 10                                   },
+            new List<int>{35, 26, 20, 13, 6                                },
+            new List<int>{31, 23, 19, 14, 9, 4                             },
+            new List<int>{28, 21, 17, 14, 10, 7, 3                         },
+            new List<int>{26, 19, 16, 13, 11, 8, 5, 2                      },
+            new List<int>{24, 17, 15, 13, 11, 8, 6, 4, 2                   },
+            new List<int>{23, 16, 14, 12, 10, 9, 7, 5, 3, 1                },
+            new List<int>{20, 15, 13, 12, 10, 9, 7, 6, 4, 3, 1             },
+            new List<int>{21, 14, 12, 11, 10, 8, 7, 6, 5, 3, 2, 1          },
+            new List<int>{20, 13, 12, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1        },
+            new List<int>{21, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1     },
+            new List<int>{18, 11, 10, 10, 9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1  },
+        };
+
+        public ConfigFromDb(IConnectionManager manager, ILoggerFactory loggerFactory)
+        {
+            _connectionManager = manager;
+            _logger = loggerFactory.CreateLogger("DbRESTFul");
+            try
+            {
+                Resolve();
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "ConfigFromDb 读取失败");
+            }
+
+        }
+
+        public ConfigFromDb Resolve()
+        {
+            using (var conn = _connectionManager.GetConnection())
+            {
+                conn.Open();
+                InitModel(SqlMapper.Query(conn, "select * from s_config"));
+
+                // 初始化主分类
+                var types = SqlMapper.Query(conn, "select id, name, hiddenInApp, previewable from s_types_main where state<>-1 order by displayOrder desc");
+                PrimaryTypes = types.Select(e => new KeyValuePair<int, string>(e.id, e.name)).ToList();
+                PrimaryTypesVisibleInApp = types.Where(e => e.hiddenInApp == 0).Select(e => new KeyValuePair<int, string>(e.id, e.name)).ToList();
+                PrimaryTypesVisibleInAppPreview = types.Where(e => e.hiddenInApp == 0 && e.previewable > 0).Select(e => new KeyValuePair<int, string>(e.id, e.name)).ToList();
+                AppPreviewTypeList = SqlMapper.Query(conn, "select channel, version from s_app_preview").Select(e => (e.channel + "," + e.version) as string).ToList();
+                var custab= SqlMapper.Query<AppIndexCusTabItem>(conn,
+                        "select category,type, label, activeImg, deactiveImg, data from n_app_index_custab where state=0")
+                    .ToList();
+                //社区
+                AppIndexCusTabList = custab.Where(x => x.category == AppIndexTabEnum.COMMUNITY.category).ToList();
+                //商品
+                MallAppIndexCusTabList = custab.Where(x => x.category == AppIndexTabEnum.MALL.category).ToList();
+            }
+            return this;
+        }
+
+        public string SMSignName { get; set; }
+        public string SMRsetMobileTemplateCode { get; set; }
+        public string SMNormalValidationTemplateCode { get; set; }
+        public string SMLoginTemplateCode { get; set; }
+
+        public string WXGZAppID { get; set; }
+        public string WXGZAppSecret { get; set; }
+
+        public string WXAppID { get; set; }
+        public string WXAppSecret { get; set; }
+
+
+        public string QQAppID { get; set; }
+        public string QQAppKey { get; set; }
+
+        public string WeiboAppID { get; set; }
+        public string WeiboAppSecret { get; set; }
+
+
+        public string AliVisionAccessKeyId { get; set; }
+        public string AliVisionAccessSecret { get; set; }
+        public string AliOssAccessKeyId { get; set; }
+        public string AliOssAccessSecret { get; set; }
+        public string AliSMAccessKeyId { get; set; }
+        public string AliSMAccessSecret { get; set; }
+
+        public string AliDytnsAccessKeyId { get; set; }
+        public string AliDytnsAccessSecret { get; set; }
+
+        public string AliVodAccessKeyId { get; set; }
+        public string AliVodAccessSecret { get; set; }
+
+        public string AliVodCallbackUrl { get; set; }
+        public string AliVodCallbackKey { get; set; }
+
+        public string AliFaceVerifyAccessKeyId { get; set; }
+        public string AliFaceVerifyAccessSecret { get; set; }
+
+        public string AliPhoneNumberAuthCode { get; set; }
+        public string AliPhoneNumberAccessKeyId { get; set; }
+        public string AliPhoneNumberAccessSecret { get; set; }
+
+        public string AliCaptchaAccessKeyId { get; set; }
+        public string AliCaptchaAccessKeySecret { get; set; }
+
+        public int PostPublishFirst { get; set; }
+
+        public string UmengAppKeyAndroid { get; set; }
+        public string UmengAppMasterSecretAndroid { get; set; }
+        public string UmengAppKeyIOS { get; set; }
+        public string UmengAppMasterSecretIOS { get; set; }
+
+        public string SystemAdministratorPassword { get; set; }
+
+        public string PointsName { get; set; }
+
+        /// <summary>
+        /// 用户签到赠送价值币数量列表,里面包含的即为一个周期
+        /// </summary>
+        public string UserSignInPointsCountList { get; set; }
+
+        /// <summary>
+        /// 用户发送请求时,参数MD5加密时的混淆串
+        /// </summary>
+        public string UserRequestParameterMD5Salt { get; set; }
+
+        /// <summary>
+        /// 用户默认头像地址,逗号分隔,路径为 olscdn.olssglobal.com/common/images/member/hdi/xxxxxx
+        /// </summary>
+        public string DefaultUserHeadImages { get; set; }
+        /// <summary>
+        /// 用户个人中心默认背景地址,逗号分隔,路径为 olscdn.olssglobal.com/common/images/member/hdi/xxxxxx
+        /// </summary>
+        public string DefaultUserHeadBackgroundImages { get; set; }
+
+        /// <summary>
+        /// Apple第三方登录私钥
+        /// </summary>
+        public string AppleSignInPrivateKey { get; set; }
+        public string AppleTeamID { get; set; }
+        public string AppleBundleID { get; set; }
+
+        /// <summary>
+        /// 短链地址
+        /// </summary>
+        public string ShorLinkPrefix { get; set; }
+        /// <summary>
+        /// H5 URL地址,无Http和/。如m.olssglobal.com
+        /// </summary>
+        public string H5UrlAddress { get; set; }
+        /// <summary>
+        /// 邀请好友注册短信模板
+        /// </summary>
+        public string ShareShortMessageTemplate { get; set; }
+
+        /// <summary>
+        /// 用户发动态任务获取的金币
+        /// </summary>
+        public int UserPointsPublishPost { get; set; }
+        /// <summary>
+        /// 发动态任务能够获取金币一天最多发放的数量
+        /// </summary>
+        public int UserPointsPublishPostMaxCount { get; set; }
+        /// <summary>
+        /// 用户评论任务获取的金币
+        /// </summary>
+        public int UserPointsComment { get; set; }
+        /// <summary>
+        /// 评论任务能够获取金币一天最多发放的数量
+        /// </summary>
+        public int UserPointsCommentMaxCount { get; set; }
+        /// <summary>
+        /// 用户点赞任务获取的金币
+        /// </summary>
+        public int UserPointsThumbsup { get; set; }
+        /// <summary>
+        /// 点赞任务能够获取金币需要达到的数量
+        /// </summary>
+        public int UserPointsThumbsupCount { get; set; }
+        /// <summary>
+        /// 用户分享任务获取的金币
+        /// </summary>
+        public int UserPointsShare { get; set; }
+        /// <summary>
+        /// 分享任务能够获取金币需要达到的数量
+        /// </summary>
+        public int UserPointsShareCount { get; set; }
+        /// <summary>
+        /// 用户被评论任务获取的金币
+        /// </summary>
+        public int UserPointsPassiveComment { get; set; }
+        /// <summary>
+        /// 被评论任务能够获取金币需要达到的数量
+        /// </summary>
+        public int UserPointsPassiveCommentCount { get; set; }
+        /// <summary>
+        /// 用户被点赞任务获取的金币
+        /// </summary>
+        public int UserPointsPassiveThumbsup { get; set; }
+        /// <summary>
+        /// 被点赞任务能够获取金币需要达到的数量
+        /// </summary>
+        public int UserPointsPassiveThumbsupCount { get; set; }
+        /// <summary>
+        /// 用户被分享任务获取的金币
+        /// </summary>
+        public int UserPointsPassiveShare { get; set; }
+        /// <summary>
+        /// 被分享任务能够获取金币需要达到的数量
+        /// </summary>
+        public int UserPointsPassiveShareCount { get; set; }
+
+
+        /// <summary>
+        /// 用户评级时,动态质量最小要达到的值,1-5
+        /// </summary>
+        public int UserLevelPostMinQuality { get; set; }
+
+        /// <summary>
+        /// 客服电话
+        /// </summary>
+        public string ConfigCSPhone { get; set; }
+        /// <summary>
+        /// 客服邮箱
+        /// </summary>
+        public string ConfigCSEmail { get; set; }
+
+        /// <summary>
+        /// QQ邮件发送邮件账户
+        /// </summary>
+        public string MailAccount { get; set; }
+        /// <summary>
+        /// QQ邮件发送邮件的授权码
+        /// </summary>
+        public string MailAuthCode { get; set; }
+
+        /// <summary>
+        /// 模拟文章用户列表
+        /// </summary>
+        public string MockPostUser { get; set; }
+        /// <summary>
+        /// 模拟评论用户列表
+        /// </summary>
+        public string MockCommentUser { get; set; }
+
+        /// <summary>
+        /// 是否禁用模拟评论文本AI审核,默认未禁用
+        /// </summary>
+        public int MockCommentDisableTextAiAuth { get; set; }
+
+        /// <summary>
+        /// 是否关闭文章自动点赞
+        /// </summary>
+        public int MockPostAutoThumbsupDisabled { get; set; }
+        /// <summary>
+        /// 是否关闭用户的自动关注
+        /// </summary>
+        public int MockUserAutoFocusDisabled { get; set; }
+
+        /// <summary>
+        /// 文章是否启用文本AI审核,大于0表示true, 等于0表示false
+        /// </summary>
+        public int EnablePostTextAiAuth { get; set; }
+
+
+
+        /// <summary>
+        /// 文章阅读统计同一用户每天最大有效阅读数量(有效阅读)
+        /// </summary>
+        public int PostReadStatisticMaxCountPerDayPerUser { get; set; }
+
+        /// <summary>
+        /// 文章阅读最小有效秒数
+        /// </summary>
+        public int PostReadStatisticMinSecs { get; set; }
+
+        /// <summary>
+        /// 文章阅读统计同一IP针对同一笔记(未登录),最多可统计的有效次数(有效阅读)
+        /// </summary>
+        public int PostReadStatisticMaxCountPerDayPerIP { get; set; }
+        /// <summary>
+        /// 文章阅读统计同一IP针对同一笔记(未登录),最多可统计的有效次数(非有效阅读)
+        /// </summary>
+        public int PostReadStatisticMaxCountPerDayPerIP_Normal { get; set; }
+
+        /// <summary>
+        /// 文章分享统计同一用户每天最大有效分享数量(有效分享)
+        /// </summary>
+        public int PostShareStatisticMaxCountPerDayPerUser { get; set; }
+        /// <summary>
+        /// 文章分享统计同一用户每天最大有效分享数量(非有效分享)
+        /// </summary>
+        public int PostShareStatisticMaxCountPerDayPerUser_Normal { get; set; }
+        /// <summary>
+        /// 同一用户同一文章最大有效分享数量(有效分享)
+        /// </summary>
+        public int PostShareStatisticMaxCountPerDayPerUserPerPost { get; set; }
+        /// <summary>
+        /// 同一用户同一文章最大有效分享数量(非有效分享)
+        /// </summary>
+        public int PostShareStatisticMaxCountPerDayPerUserPerPost_Normal { get; set; }
+
+
+        /// <summary>
+        /// 每天同一用户同一作者主页访问次数(非有效次数)
+        /// </summary>
+        public int PersonalPageVisitMaxCountPerDayPerUser2User_Normal { get; set; }
+
+
+        /// <summary>
+        /// 研报百次有效阅读单价(分为单位)
+        /// </summary>
+        public int PostStandpointSettlementPrice { get; set; }
+        /// <summary>
+        /// 价格变动提醒
+        /// </summary>
+        public string PostStandpointPriceChangeTip { get; set; }
+        /// <summary>
+        /// 视频笔记百次有效阅读单价(分为单位)
+        /// </summary>
+        public int PostDiaryHasVideoSettlementPrice { get; set; }
+        /// <summary>
+        /// 图文笔记百次有效阅读单价(分为单位)
+        /// </summary>
+        public int PostDiaryNoVideoSettlementPrice { get; set; }
+        /// <summary>
+        /// 价格变动提醒
+        /// </summary>
+        public string PostDiaryPriceChangeTip { get; set; }
+
+        /// <summary>
+        /// 创作者平台统计预警发送邮箱,多个用逗号分隔
+        /// </summary>
+        public string MPPostStatWarningMailTo { get; set; }
+
+        /// <summary>
+        /// 创作者平台统计预警配置,如{ diary: { read: { hours: 1, max: 5 }, thumbsup: { hours: 1, max: 5 }, share: { hours: 1, max: 5 }, totalRead: { hours: 1, max: 5 } }, standpoint: { ... } }
+        /// </summary>
+        public MPStatisticWarningConfig MPStatisticWarningConfig { get; set; }
+
+        /// <summary>
+        /// 文章最大推荐的天数,超过后,热度置0
+        /// </summary>
+        public int PostMaxRecommendDays { get; set; }
+        /// <summary>
+        /// 如果配置了此日期值,文章推荐则优先使用此值,而非PostMaxRecommendDays
+        /// </summary>
+        public string PostStartRecommendDate { get; set; }
+        /// <summary>
+        /// 文章距离当前时间多少小时内忽略热度值
+        /// </summary>
+        public int PostIgnoreHotRecentHours { get; set; }
+        /// <summary>
+        /// 文章冷却小时数,即在文章发布多久内计算冷却系数
+        /// </summary>
+        public int PostCoolingPeriodHours { get; set; }
+        /// <summary>
+        /// 文章在冷却周期内,小于等于此值时,冷却系数为1
+        /// </summary>
+        public int PostIgnoreCoolingMaxCountPerPeriod { get; set; }
+
+
+
+        /// <summary>
+        /// 用户主页默认背景图片地址
+        /// </summary>
+        public string UserPersonalPageBGImage { get; set; }
+
+        /// <summary>
+        /// 提现最小金额(含),单位为分
+        /// </summary>
+        public int CashoutMinAmount { get; set; }
+        /// <summary>
+        /// 提现最大金额(含),单位为分
+        /// </summary>
+        public int CashoutMaxAmount { get; set; }
+        /// <summary>
+        /// 提现每个自然月提现最大次数(含)
+        /// </summary>
+        public int CashoutMaxTimesPerMonth { get; set; }
+
+        /// <summary>
+        /// 用户邀请海报版本
+        /// </summary>
+        public int LastestInvitationPosterVersion { get; set; }
+
+        /// <summary>
+        /// 用户邀请海报生成参数
+        /// </summary>
+        public InvitationPosterParams InvitationPosterParams { get; set; }
+
+        /// <summary>
+        /// 邀请激活报警参数
+        /// </summary>
+        public InvitationAlarm InvitationAlarm { get; set; }
+
+        /// <summary>
+        /// 活动任务奖励兑换过期天数
+        /// </summary>
+        public int ActivityRewardExchangeExpireDays { get; set; }
+
+        /// <summary>
+        /// 价值币图标URL
+        /// </summary>
+        public string PointsIconUrl { get; set; }
+
+        /// <summary>
+        /// 平台微信客服二维码URL
+        /// </summary>
+        public string WXCSQRCodeUrl { get; set; }
+
+        /// <summary>
+        /// App社区Tab顺序及默认显示配置, 如:FOCUS,RECOMMEND,IMGPOST,VIDEOPOST|RECOMMEND
+        /// </summary>
+        public string AppIndexPageTabConfig { get; set; }
+        /// <summary>
+        /// App商城Tab顺序及默认显示配置, 如:FOCUS,RECOMMEND,IMGPOST,VIDEOPOST|RECOMMEND
+        /// </summary>
+        public string MallAppIndexPageTabConfig { get; set; } = "FOCUS,RECOMMEND,VIDEOPOST|RECOMMEND";
+
+        /// <summary>
+        /// App活动板块的火图标是否显示
+        /// </summary>
+        public int ActivityHotIconInAppVisible { get; set; }
+
+        /// <summary>
+        /// 内容推荐中每页包含的研报数量
+        /// </summary>
+        public int StandPointCountPerPageInRecommendation { get; set; }
+
+        /// <summary>
+        /// App中置顶资讯编号
+        /// </summary>
+        public long AppTopNewsId { get; set; }
+
+        /// <summary>
+        /// App中热门讨论出现的位置
+        /// </summary>
+        public int AppHotDiscussPosition { get; set; }
+
+        /// <summary>
+        /// App中推荐列表热门活动出现的位置,如果配置为-1表示不显示
+        /// </summary>
+        public int AppHotActivityPosition { get; set; }
+
+        /// <summary>
+        /// App活跃Tick接口调用间隔(秒)
+        /// </summary>
+        public int AppAliveTickInterval { get; set; } = 5;
+
+        /// <summary>
+        /// App同步行为数据时间间隔(秒)
+        /// </summary>
+        public int AppSyncActionDataInterval { get; set; } = 30;
+
+        /// <summary>
+        /// App一次同步行为数据量最大值
+        /// </summary>
+        public int AppSyncActionDataMaxSize { get; set; } = 100;
+
+        /// <summary>
+        /// VIVO商业开放平台AccessToken
+        /// </summary>
+        public string AdVivoAccessToken { get; set; }
+
+        /// <summary>
+        /// VIVO商业开放平台AccessToken过期时间
+        /// </summary>
+        public DateTime? AdVivoAccessTokenExpireAt { get; set; }
+
+        /// <summary>
+        /// VIVO商业开放平台refreshToken
+        /// </summary>
+        public string AdVivoRefreshToken { get; set; }
+
+        /// <summary>
+        /// 模拟评论时间随机因子1
+        /// </summary>
+        public int MockCommentRandomTimeFactor01 { get; set; } = 45;
+        /// <summary>
+        /// 模拟评论时间随机因子2
+        /// </summary>
+        public int MockCommentRandomTimeFactor02 { get; set; } = 120;
+
+        /// <summary>
+        /// 是否显示活动历史的按钮, 0 显示, 1 不显示
+        /// </summary>
+        public int AppActivityHistoryRecordsBtnVisible { get; set; }
+
+        /// <summary>
+        /// 商务邮箱
+        /// </summary>
+        public string CompanyEmail { get; set; }
+
+        /// <summary>
+        /// 无效评论关键词配置,正则表达式
+        /// </summary>
+        public string InvalidCommentReg { get; set; }
+
+        /// <summary>
+        /// Api中Sign检查是否禁用
+        /// </summary>
+        public int ApiSignCheckingDisabled { get; set; }
+
+        /// <summary>
+        /// Api中Sign每分钟最大验证错误次数,超过此次数,则禁止访问1个小时,如果配置0,则无最大错误次数
+        /// </summary>
+        public int ApiSignCheckingFailedMaxCountPerMin { get; set; }
+
+        /// <summary>
+        /// Api验签URL忽略正规
+        /// </summary>
+        public string ApiSignCheckingUrlIgnoreReg { get; set; }
+
+        /// <summary>
+        /// Api验签密钥
+        /// </summary>
+        public string ApiSignKey { get; set; }
+
+        /// <summary>
+        /// api加密白名单ip
+        /// </summary>
+        public string EncryptWhiteIPList { get; set; }
+
+        /// <summary>
+        /// 第元人民币相当于多少价值币
+        /// </summary>
+        public int PointsCountPerYuan { get; set; } = 500;
+
+        /// <summary>
+        /// 支付超时时间(分钟)
+        /// </summary>
+        public int PaymentTimeoutMinutes { get; set; } = 10;
+
+        /// <summary>
+        /// 卖家发货超时时间(小时)
+        /// </summary>
+        public int MallDeliveryTimeoutHours { get; set; } = 72;
+
+        /// <summary>
+        /// 买卖双方订单评论超时时间(小时)
+        /// </summary>
+        public int MallOrderRatingTimeoutHours { get; set; } = 15 * 24;
+
+        /// <summary>
+        /// 买家确认收货超时间(小时)
+        /// </summary>
+        public int MallReceiptTimeoutHours { get; set; } = 24 * 10;
+
+        /// <summary>
+        /// 买家操作延长确认收货时间的天数
+        /// </summary>
+        public int MallOrderConfirmReceiptExtendDays { get; set; } = 3;
+
+        /// <summary>
+        /// 快递鸟用户id
+        /// </summary>
+        public string KDNiaoEBusinessID { get; set; }
+
+        /// <summary>
+        /// 快递鸟用户apikey
+        /// </summary>
+        public string KDNiaoApiKey { get; set; }
+
+        /// <summary>
+        /// 于初科技代理商id
+        /// </summary>
+        public string YCTechAgentId { get; set; }
+
+        /// <summary>
+        /// 于初科技代理商key
+        /// </summary>
+        public string YCTechSignKey { get; set; }
+        /// <summary>
+        /// 于初科技接口host
+        /// </summary>
+        public string YCTechHost { get; set; }
+        /// <summary>
+        /// 于初科技订单结果回调接口url
+        /// </summary>
+        public string YCTechOrderCallBackUrl { get; set; }
+        /// <summary>
+        /// 于初科技平台id
+        /// </summary>
+        public int YCTechSupplierId { get; set; }
+
+        /// <summary>
+        /// 商品免责声明
+        /// </summary>
+        public string MallGoodsDisclaimer { get; set; }
+
+        public double UEActivityDisplayOrder { get; set; }
+        /// <summary>
+        /// 卖家超过多少天未上架,超时上架天数
+        /// </summary>
+        public int UEShelveTimeout { get; set; }
+        /// <summary>
+        /// 平台退货,卖家自动确认收货超时时间
+        /// </summary>
+        public int UESellerReceiveTimeout { get; set; }
+
+        public PlatformShopConfig PlatformShopConfig { get; set; }
+
+        public HuiFuCommonConfig HuiFuConfig { get; set; }
+
+        public string HuiFuJspayCallbackUrl { get; set; }
+        public string HuiFuChashCallbackUrl { get; set; }
+        public string HuiFuOpenCallbackUrl  { get; set; }
+        public string HuiFuRefundCallbackUrl { get; set; }
+        public string HuiFuYuEPayCallbackUrl { get; set; }
+
+        public string RongYunIMAppKey { get; set; }
+        public string RongYunIMAppSecret { get; set; }
+        
+        /// <summary>
+        /// 融云IM分配的客服编号列表,逗号分隔
+        /// </summary>
+        public string RongCloudIMCSIdList { get; set; }
+        
+        /// <summary>
+        /// config 为从数据库查询出来的数据集合
+        /// </summary>
+        /// <param name="configs"></param>
+        public void InitModel(dynamic configs)
+        {
+            var props = GetType().GetProperties();
+            foreach (var config in configs)
+            {
+                if (string.IsNullOrEmpty(config.value)) continue;
+                var prop = props.FirstOrDefault(e => e.Name.Equals(config.key));
+                if (prop != null)
+                {
+                    if (prop.PropertyType == typeof(int))
+                    {
+                        prop.SetValue(this, int.Parse(config.value));
+                    }
+                    if (prop.PropertyType == typeof(long))
+                    {
+                        prop.SetValue(this, long.Parse(config.value));
+                    }
+                    else if (prop.PropertyType == typeof(string))
+                    {
+                        prop.SetValue(this, config.value);
+                    }
+                    else if (prop.PropertyType == typeof(float))
+                    {
+                        prop.SetValue(this, float.Parse(config.value));
+                    }
+                    else if (prop.PropertyType == typeof(double))
+                    {
+                        prop.SetValue(this, double.Parse(config.value));
+                    }
+                    else if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
+                    {
+                        prop.SetValue(this, DateTime.Parse(config.value));
+                    }
+                    else if (typeof(IConfigFromDbJsonModel).IsAssignableFrom(prop.PropertyType))
+                    {
+                        var value = (string)config.value;
+                        if (!string.IsNullOrEmpty(value))
+                        {
+                            prop.SetValue(this, JsonConvert.DeserializeObject(value, prop.PropertyType));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 23 - 0
JiaZhiQuan.Common/Config/ConfigFromDbConfig.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Wicture.DbRESTFul.Configuration;
+
+namespace JiaZhiQuan.Common.Config
+{
+    public class ConfigFromDbConfig
+    {
+        public const string ConfigSectionName = "ConfigFromDbConfig";
+
+        public bool Disabled { get; set; } = false;
+
+        public static ConfigFromDbConfig GetFromConfig()
+        {
+            if (!ConfigurationManager.Settings.Document.ContainsKey(ConfigSectionName))
+            {
+                return new ConfigFromDbConfig();
+            }
+            return ConfigurationManager.Settings.GetConfig<ConfigFromDbConfig>(ConfigSectionName);
+        }
+    }
+}

+ 158 - 0
JiaZhiQuan.Common/Config/ConfigFromDbModels.cs

@@ -0,0 +1,158 @@
+using Dapper;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Senparc.Weixin.Annotations;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Wicture.DbRESTFul.Infrastructure.Repository;
+
+namespace JiaZhiQuan.Common.Config
+{
+    public interface IConfigFromDbJsonModel
+    {
+    }
+
+    public class MPStatisticWarningConfigItemValue
+    {
+        /// <summary>
+        /// 多少小时内
+        /// </summary>
+        public int hours { get; set; }
+        /// <summary>
+        /// 达到多大值需要预警
+        /// </summary>
+        public int max { get; set; }
+    }
+
+    public class MPStatisticWarningConfigItem
+    {
+        /// <summary>
+        /// 有效阅读
+        /// </summary>
+        public MPStatisticWarningConfigItemValue read { get; set; }
+        /// <summary>
+        /// 点赞
+        /// </summary>
+        public MPStatisticWarningConfigItemValue thumbsup { get; set; }
+        /// <summary>
+        /// 收藏
+        /// </summary>
+        public MPStatisticWarningConfigItemValue collection { get; set; }
+        /// <summary>
+        /// 评论
+        /// </summary>
+        public MPStatisticWarningConfigItemValue comment { get; set; }
+        /// <summary>
+        /// 分享
+        /// </summary>
+        public MPStatisticWarningConfigItemValue share { get; set; }
+        /// <summary>
+        /// 有效总计阅读量
+        /// </summary>
+        public MPStatisticWarningConfigItemValue totalRead { get; set; }
+    }
+
+    public class MPStatisticWarningConfig : IConfigFromDbJsonModel
+    {
+        public MPStatisticWarningConfigItem diary { get; set; }
+        public MPStatisticWarningConfigItem standpoint { get; set; }
+    }
+
+    public class PlatformShopConfig : IConfigFromDbJsonModel
+    {
+        public string shopId { get; set; }
+        public long userId { get; set; }
+    }
+
+    public class HuiFuCommonConfig: IConfigFromDbJsonModel {
+        //商户号
+        public string sys_id { get; set; }
+        //产品号
+        public string product_id { get; set; }
+        //私钥
+        public string app_secret_key { get; set;}
+        //商户公钥
+        public string app_pub_key { get; set;}
+        //汇付公钥
+        public string huifu_pub_key { get; set; }
+
+        public bool isDev { get; set; }
+    }
+
+    public class InvitationAlarm : IConfigFromDbJsonModel
+    {
+        /// <summary>
+        /// 分钟数,合作方多少分钟内,邀请达到多少人
+        /// </summary>
+        public int PartnerTime { get; set; }
+        /// <summary>
+        /// 人数,合作方多少分钟内,邀请达到多少人
+        /// </summary>
+        public int PartnerCount { get; set; }
+
+        /// <summary>
+        /// 分钟数,普通用户多少分钟内,邀请达到多少人
+        /// </summary>
+        public int UserTime { get; set; }
+        /// <summary>
+        /// 人数,普通用户多少分钟内,邀请达到多少人
+        /// </summary>
+        public int UserCount { get; set; }
+    }
+
+    public class InvitationPosterParams : IConfigFromDbJsonModel
+    {
+        public InvitationPosterParamsBackgroundImage BackgroundImage { get; set; }
+        public InvitationPosterParamsHeadImage HeadImage { get; set; }
+        public InvitationPosterParamsHeadImage QRImage { get; set; }
+        public List<InvitationPosterParamsText> Texts { get; set; }
+    }
+    public class InvitationPosterParamsBackgroundImage
+    {
+        public string FileName { get; set; }
+    }
+
+    public class InvitationPosterParamsHeadImage
+    {
+        public int X { get; set; }
+
+        public int Y { get; set; }
+
+        public bool Fillet { get; set; }
+
+        public int Width { get; set; }
+
+        public int Height { get; set; }
+    }
+
+    public class InvitationPosterParamsText
+    {
+        public string Key { get; set; }
+
+        public string Text { get; set; }
+
+        public int X { get; set; }
+
+        public int Y { get; set; }
+
+        public int FontSize { get; set; }
+
+        public string FamilyName { get; set; }
+
+        public string Color { get; set; }
+    }
+
+    /// <summary>
+    /// App首页自定义Tab项
+    /// </summary>
+    public class AppIndexCusTabItem
+    {
+        public int category { get; set; }
+        public string type { get; set; }
+        public string label { get; set; }
+        public string activeImg { get; set; }
+        public string deactiveImg { get; set; }
+        public string data { get; set; }
+    }
+}

+ 31 - 0
JiaZhiQuan.Common/Config/ConfigRefreshScheduleService.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.Config
+{
+    public class ConfigRefreshScheduleService : AbstractControlledScheduleService
+    {
+        ConfigFromDb configFromDb;
+
+        public ConfigRefreshScheduleService(ConfigFromDb configFromDb) : base(30 * 1000, false)
+        {
+            this.configFromDb = configFromDb;
+            IgnoreStateConfig = true;
+        }
+
+        override public async Task Run()
+        {
+            try
+            {
+                configFromDb.Resolve();
+            }
+            catch (Exception ex)
+            {
+                LoggerManager.Logger.Error(ex, "刷新ConfigFromDB配置失败" + "\r\n" + ex.Message);
+            }
+            await Task.CompletedTask;
+        }
+
+    }
+}

+ 78 - 0
JiaZhiQuan.Common/ElasticSearch/ESConstants.cs

@@ -0,0 +1,78 @@
+namespace JiaZhiQuan.Common.ElasticSearch
+{
+    public static class ESConstants
+    {
+        public static string DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+        public static class ESIndexName
+        {
+            // ES文章表
+            public static string Post = "post_alias";
+
+            // ES Log表
+            public static string NLog = "n_log";
+
+            // ES IP地址映射表
+            public static string IpAddress = "ip_addr";
+
+            // ES 手机号地址映射表
+            public static string MobileAddress = "mobile_addr";
+
+            // ES 用户关注记录表
+            public static string UserFansRecords = "user_fans_record";
+
+            // ES 用户收藏记录表
+            public static string UserCollectRecords = "user_collect_record";
+
+            // ES 用户点赞记录表
+            public static string UserThumbsupRecords = "user_thumbsup_record";
+
+            // ES 商品数据
+            public static string MallGoods = "mall_goods";
+        }
+
+        public static class ResponseKey
+        {
+            /// <summary>
+            /// 最外层的aggregations对象
+            /// </summary>
+            public static string AGGREGATIONS = "aggregations";
+
+            /// <summary>
+            /// aggregations统计结果对象的key
+            /// </summary>
+            public static string AGGREGATIONS_COUNT = "doc_count";
+
+            /// <summary>
+            /// 最外层的hits对象
+            /// </summary>
+            public static string HITS = "hits";
+
+            /// <summary>
+            /// ES返回的数据结构中有两层hits,这个是第二层的
+            /// 这个对象包含index的基础信息以及返回的数据
+            /// </summary>
+            public static string HITS_HITS = "hits";
+
+            /// <summary>
+            /// 行数据的ID
+            /// </summary>
+            public static string HITS_HITS_SOURCE = "_source";
+
+            /// <summary>
+            /// 返回的查询结果数据
+            /// </summary>
+            public static string HITS_HITS_ID = "_id";
+
+            /// <summary>
+            /// 查询结果total对象
+            /// </summary>
+            public static string HITS_TOTAL = "total";
+
+            /// <summary>
+            /// 数据条数
+            /// </summary>
+            public static string HITS_TOTAL_VALUE = "value";
+        }
+    }
+}

+ 31 - 0
JiaZhiQuan.Common/ElasticSearch/ESFieldAttribute.cs

@@ -0,0 +1,31 @@
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch
+{
+    /// <summary>
+    /// ES中字段和C# class属性的名称映射
+    /// 当ES的字段名和class名不匹配时,怎么映射
+    /// </summary>
+    public class ESFieldAttribute : Attribute
+    {
+        public string ESFieldName;
+
+        public ESFieldAttribute(string eSFieldName)
+        {
+            ESFieldName = eSFieldName;
+        }
+    }
+
+    /// <summary>
+    /// Es中的Id字段
+    /// </summary>
+    public class ESIdAttribute : Attribute
+    {
+        public string ESIdName;
+
+        public ESIdAttribute(string name)
+        {
+            ESIdName = name;
+        }
+    }
+}

+ 252 - 0
JiaZhiQuan.Common/ElasticSearch/ESHelper.cs

@@ -0,0 +1,252 @@
+using Elasticsearch.Net;
+using JiaZhiQuan.Common.ElasticSearch.Models;
+using JiaZhiQuan.Common.Utils;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+using Wicture.DbRESTFul.Configuration;
+
+namespace JiaZhiQuan.Common.ElasticSearch
+{
+    public class ESHelper
+    {
+        #region models
+        public class PaginationResult<T>
+        {
+
+            public List<T> Items { get; set; }
+
+            public PaginationModel Pagination { get; set; }
+        }
+
+        public class PaginationModel
+        {
+            public int TotalCount { get; set; }
+            public int PageIndex { get; set; }
+            public int PageSize { get; set; }
+        }
+        #endregion
+
+        private static object syncObj = new object();
+        private static ElasticLowLevelClient _client = null;
+        public static ElasticLowLevelClient Client
+        {
+            get
+            {
+                if (_client == null)
+                {
+                    lock (syncObj)
+                    {
+                        if (_client == null)
+                        {
+                            var config = ConfigurationManager.Settings.GetConfig<ElasticSearchConfig>(ElasticSearchConfig.ConfigSectionName);
+                            var settings = new ConnectionConfiguration(new Uri(config.Url))
+                                .BasicAuthentication(config.User, config.Password)
+                                .RequestTimeout(TimeSpan.FromMinutes(1));
+                            _client = new ElasticLowLevelClient(settings);
+                        }
+                    }
+                }
+                return _client;
+            }
+        }
+
+        /// <summary>
+        /// pageSize > 0时,页码才起作用
+        /// </summary>
+        /// <returns></returns>
+        public async static Task<PaginationResult<T>> Query<T>(string index, object postData, int pageIndex = 0, int pageSize = 0)
+        {
+            SearchRequestParameters parameters = new SearchRequestParameters();
+            if (pageSize > 0)
+            {
+                parameters.SetQueryString("size", pageSize);
+                if (pageIndex > 0)
+                {
+                    parameters.SetQueryString("from", (pageIndex - 1) * pageSize);
+                }
+            }
+            try
+            {
+                var resp = await Client.SearchAsync<StringResponse>(index, PostData.Serializable(postData), parameters);
+                if (resp.Success)
+                {
+                    var obj = JsonConvert.DeserializeObject<JToken>(resp.Body);
+                    var j = new List<dynamic>();
+                    var totalCount = obj.Value<JObject>("hits")?.Value<JToken>("total")?.Value<int>("value") ?? 0;
+                    var hits = obj.Value<JObject>("hits")?.Value<JArray>("hits")?.Select(e => JsonConvert.DeserializeObject<T>(e.Value<JToken>("_source").ToString()))?.ToList();
+                    return new PaginationResult<T>
+                    {
+                        Items = hits,
+                        Pagination = new PaginationModel
+                        {
+                            PageIndex = pageIndex,
+                            PageSize = pageSize,
+                            TotalCount = totalCount
+                        }
+                    };
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+                throw ex;
+            }
+
+            return null;
+        }
+
+        public async static Task<JToken> Get(string index, string id, GetRequestParameters param = null)
+        {
+            var resp = await Client.GetAsync<StringResponse>(index, id, param);
+            if (resp.Success)
+            {
+                var obj = JsonConvert.DeserializeObject<JToken>(resp.Body);
+                return obj.Value<JToken>("_source");
+            }
+            return null;
+        }
+
+        public async static Task<bool> CheckExist(string index, string id)
+        {
+            var resp = await Client.DocumentExistsAsync<StringResponse>(index, id);
+            return resp.Success;
+        }
+
+        /// <summary>
+        /// 解析ES返回的对象,提取数据和数据条数
+        /// </summary>
+        /// <typeparam name="T">需要序列化成的对象,属性名需要和ES的字段名一样,如果不一样需要设置特性</typeparam>
+        /// <param name="response">ES返回的对象</param>
+        /// <param name="methodName">调用本方法的方法名称,用来记录异常日志,如果解析失败可以通过名称定位到具体是哪个方法调用的</param>
+        /// <returns></returns>
+        public static ESResponseData<T> GetResponseData<T>(StringResponse response)
+        {
+            ESResponseData<T> res = new ESResponseData<T>();
+            if (response is null)
+            {
+                res.errorMsg = "response is null";
+                return res;
+            }
+            var stacktrace = new StackTrace();
+            var method = stacktrace.GetFrame(1).GetMethod();
+            string methodName = stacktrace.GetFrame(1).GetMethod().DeclaringType.FullName;
+            if (response.Success)
+            {
+                try
+                {
+                    var jsonData = JsonConvert.DeserializeObject<JToken>(response.Body);
+                    res.total = jsonData.Value<JObject>(ESConstants.ResponseKey.HITS)
+                                        ?.Value<JObject>(ESConstants.ResponseKey.HITS_TOTAL)
+                                        ?.Value<int?>(ESConstants.ResponseKey.HITS_TOTAL_VALUE)
+                                        ?? 0;
+                    PropertyInfo[] properties = typeof(T).GetProperties();
+                    res.data = jsonData.Value<JObject>(ESConstants.ResponseKey.HITS)
+                                       ?.Value<JArray>(ESConstants.ResponseKey.HITS_HITS)
+                                       ?.Select(e =>
+                                       {
+                                           var source = e.Value<JToken>(ESConstants.ResponseKey.HITS_HITS_SOURCE);
+                                           T itemData = Activator.CreateInstance<T>();
+                                           foreach (PropertyInfo property in properties)
+                                           {
+                                               object newValue = null;
+                                               ESIdAttribute idAttribute = property.GetCustomAttribute<ESIdAttribute>();
+                                               if (idAttribute != null)
+                                               {
+                                                   // 主键
+                                                   newValue = e.Value<JToken>(ESConstants.ResponseKey.HITS_HITS_ID).Value<string>();
+                                               }
+                                               else
+                                               {
+                                                   // 业务字段
+                                                   ESFieldAttribute attribute = property.GetCustomAttribute<ESFieldAttribute>();
+                                                   // 如果没有设置特性,或者特性没有设置映射的名称,那么就用属性名作为ES的字段名查询数据
+                                                   if (attribute is null || string.IsNullOrWhiteSpace(attribute.ESFieldName))
+                                                   {
+                                                       var value = (source[property.Name] as JValue)?.Value;
+                                                       newValue = ObjectUtils.ConvertObjectToType(value, property.PropertyType);
+                                                   }
+                                                   // 如果设置了特性,而且ESFieldName不为空,那么就用ESFieldName作为ES的字段名查询数据
+                                                   else if (attribute != null && !string.IsNullOrWhiteSpace(attribute.ESFieldName))
+                                                   {
+                                                       var value = (source[attribute.ESFieldName] as JValue)?.Value;
+                                                       newValue = ObjectUtils.ConvertObjectToType(value, property.PropertyType);
+                                                   }
+                                               }
+                                               property.SetValue(itemData, newValue, null);
+                                           }
+                                           return itemData;
+
+                                       })
+                                       ?.ToList();
+                    res.success = true;
+                }
+                catch (Exception ex)
+                {
+                    res.errorMsg = ex.Message;
+                    LoggerManager.Logger.Error($"【{methodName}】ES解析数据报错: {ex}");
+                }
+            }
+            else
+            {
+                res.errorMsg = response.OriginalException.ToString();
+                LoggerManager.Logger.Error($"【{methodName}】ES解析数据失败: {response?.ToString()}");
+            }
+            return res;
+        }
+
+        /// <summary>
+        /// 解析ES返回的对象,提取统计结果
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="response"></param>
+        /// <returns></returns>
+        public static ESResponseAggregations GetResponseAggregations(StringResponse response)
+        {
+            ESResponseAggregations res = new ESResponseAggregations();
+            if (response is null)
+            {
+                res.errorMsg = "response is null";
+                return res;
+            }
+            var stacktrace = new StackTrace();
+            var method = stacktrace.GetFrame(1).GetMethod();
+            string methodName = stacktrace.GetFrame(1).GetMethod().DeclaringType.FullName;
+            if (response.Success)
+            {
+                try
+                {
+                    var dic = new Dictionary<string, int>();
+                    var jsonData = JsonConvert.DeserializeObject<JToken>(response.Body);
+                    var aggs = jsonData.Value<JObject>(ESConstants.ResponseKey.AGGREGATIONS);
+                    foreach (var item in aggs)
+                    {
+                        dic.Add(item.Key, item.Value.Value<int>(ESConstants.ResponseKey.AGGREGATIONS_COUNT));
+                    }
+                    res.data = dic;
+                    res.success = true;
+                }
+                catch (Exception ex)
+                {
+                    res.errorMsg = ex.Message;
+                    LoggerManager.Logger.Error($"【{methodName}】ES解析数据报错: {ex}");
+                }
+            }
+            else
+            {
+                res.errorMsg = response.OriginalException.ToString();
+                LoggerManager.Logger.Error($"【{methodName}】ES解析聚合结果失败: {response?.ToString()}");
+            }
+            return res;
+        }
+    }
+
+}

+ 43 - 0
JiaZhiQuan.Common/ElasticSearch/ESQuery.cs

@@ -0,0 +1,43 @@
+using Elasticsearch.Net;
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch
+{
+    public static class ESQuery
+    {
+        /// <summary>
+        /// 统计某个帖子的真实操作数量和模拟操作数量(适用于统计文章的阅读量和分享量)
+        /// </summary>
+        /// <param name="id">文章id</param>
+        /// <returns></returns>
+        public static PostData StatRealAndMockPostNumberCount(long id)
+        {
+            var query = new
+            {
+                size = 0,
+                query = new
+                {
+                    @bool = new
+                    {
+                        must = new object[]
+                        {
+                            new { term = new { postId = id } },
+                            new { range = new { createAt = new { lt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} } }
+                        },
+                        must_not = new object[]
+                        {
+                             new{ term = new { notValidRecord = true } }
+                        }
+                    }
+                },
+                aggs = new
+                {
+                    mockCount = new { filter = new { term = new { isMock = new { value = true } } } },
+                    realCount = new { filter = new { term = new { isMock = new { value = false } } } }
+                }
+            };
+            return PostData.Serializable(query);
+        }
+
+    }
+}

+ 19 - 0
JiaZhiQuan.Common/ElasticSearch/ElasticSearchConfig.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Wicture.DbRESTFul.Configuration;
+
+namespace JiaZhiQuan.Common.ElasticSearch
+{
+    public class ElasticSearchConfig
+    {
+        public const string ConfigSectionName = "ES";
+
+        public string Url { get; set; }
+
+        public string User { get; set; }
+
+        public string Password { get; set; }
+
+    }
+}

+ 36 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESIpAddress.cs

@@ -0,0 +1,36 @@
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /**
+     * 
+PUT /ip_addr
+{
+  "mappings": {
+    "properties": {
+      "ip": {
+        "type": "keyword"
+      },
+      "addr": {
+        "type": "keyword"
+      },
+      "province": {
+        "type": "keyword"
+      },
+      "city": {
+        "type": "keyword"
+      }
+    }
+  }
+}
+     */
+    /// <summary>
+    /// ip地址/地址映射
+    /// ip_addr
+    /// </summary>
+    public class ESIpAddress
+    {
+        public string ip { get; set; }
+        public string addr { get; set; }
+        public string province { get; set; }
+        public string city { get; set; }
+    }
+}

+ 356 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESMallGoods.cs

@@ -0,0 +1,356 @@
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+     PUT / mall_goods
+{
+    "mappings": {
+        "properties": {
+            "goodsId": {
+                "type": "long"
+            },
+            "goodsName": {
+                "type": "text",
+                "analyzer": "ik_max_word"
+            },
+            "goodsDesc": {
+                "type": "text",
+                "analyzer": "ik_max_word"
+            },
+            "parentCatId": {
+                "type": "integer"
+            },
+            "parentCatName": {
+                "type": "text",
+                "analyzer": "ik_smart"
+            },
+            "catId": {
+                "type": "integer"
+            },
+            "catName": {
+                "type": "text",
+                "analyzer": "ik_smart"
+            },
+            "chainCodes": {
+                "type": "keyword"
+            },
+            "specPath": {
+                "type": "text",
+                "analyzer": "ik_smart",
+                "fields": {
+                    "keyword": {
+                        "type": "keyword",
+                        "ignore_above": 256
+                    }
+                }
+            },
+            "specIds": {
+                "type": "integer"
+            },
+            "specNames": {
+                "type": "text",
+                "analyzer": "ik_smart",
+                "fields": {
+                    "keyword": {
+                        "type": "keyword",
+                        "ignore_above": 256
+                    }
+                }
+            },
+            "specValuesIds": {
+                "type": "integer"
+            },
+            "specValuesNames": {
+                "type": "text",
+                "analyzer": "ik_smart",
+                "fields": {
+                    "keyword": {
+                        "type": "keyword",
+                        "ignore_above": 256
+                    }
+                }
+            },
+            "specJson": {
+                "type": "keyword"
+            },
+            "goodsLevel": {
+                "type": "integer"
+            },
+            "sellerId": {
+                "type": "long"
+            },
+            "sellerName": {
+                "type": "text",
+                "analyzer": "ik_smart"
+            },
+            "coverImg": {
+                "type": "keyword",
+                "index": false
+            },
+            "coverWidth": {
+                "type": "integer",
+                "index": false
+            },
+            "coverHeight": {
+                "type": "integer",
+                "index": false
+            },
+            "hasVideo": {
+                "type": "boolean",
+                "index": false
+            },
+            "videoId": {
+                "type": "keyword",
+                "index": false
+            },
+            "videoReady": {
+                "type": "boolean",
+                "index": false
+            },
+            "duration": {
+                "type": "keyword",
+                "index": false
+            },
+            "originalPrice": {
+                "type": "integer"
+            },
+            "salePrice": {
+                "type": "integer"
+            },
+            "stock": {
+                "type": "integer"
+            },
+            "sourceType": {
+                "type": "short",
+                "index": false
+            },
+            "disabled": {
+                "type": "boolean"
+            },
+            "disabledReason": {
+                "type": "keyword",
+                 "index": false
+            },
+            "auditState": {
+                "type": "short",
+                "index": false
+            },
+            "onsaleState": {
+                "type": "short"
+            },
+            "offsaleReasonType": {
+                "type": "short",
+                "index": false
+            },
+            "version": {
+                "type": "integer",
+                "index": false
+            },
+            "createAt": {
+                "type": "date",
+                "format": "yyyy-MM-dd HH:mm:ss"
+            },
+            "updateAt": {
+                "type": "date",
+                "format": "yyyy-MM-dd HH:mm:ss"
+            },
+            "saleState": {
+                "type": "short"
+            },
+            "viewCnt": {
+                "type": "integer",
+                "index": false
+            },
+            "collectCnt": {
+                "type": "integer",
+                "index": false
+            },
+            "shareCnt": {
+                "type": "integer",
+                "index": false
+            },
+            "province": {
+                "type": "text",
+                "analyzer": "ik_smart"
+            },
+            "city": {
+                "type": "text",
+                "analyzer": "ik_smart"
+            }
+        }
+    }
+}
+     */
+    public class ESMallGoods
+    {
+        /// <summary>
+        /// 商品id
+        /// </summary>
+        [ESId("_id")]
+        public long goodsId { get; set; }
+        /// <summary>
+        /// 商品名称
+        /// </summary>
+        public string goodsName { get; set; }
+        /// <summary>
+        /// 商品描述
+        /// </summary>
+        public string goodsDesc { get; set; }
+        /// <summary>
+        /// 类目父类别编码,父类别为0,表示根节点
+        /// </summary>
+        public int parentCatId { get; set; }
+        /// <summary>
+        /// 父级类目名称
+        /// </summary>
+
+        public string parentCatName { get; set; }
+        /// <summary>
+        /// 类目id(最底层的类目)
+        /// </summary>
+        public int catId { get; set; }
+        /// <summary>
+        /// 类目名称
+        /// </summary>
+        public string catName { get; set; }
+        /// <summary>
+        /// 链路code
+        /// </summary>
+        public string chainCodes { get; set; }
+        /// <summary>
+        /// 属性全链路
+        /// </summary>
+        public string[] specPath { get; set; }
+        /// <summary>
+        /// 属性id,多个用,分割,前后都需加,
+        /// </summary>
+        public int[] specIds { get; set; }
+        /// <summary>
+        /// 属性名称
+        /// </summary>
+        public string[] specNames { get; set; }
+        /// <summary>
+        /// 属性值id,多个用,分割,前后都需加,
+        /// </summary>
+        public int[] specValuesIds { get; set; }
+        /// <summary>
+        /// 属性值名称
+        /// </summary>
+        public string[] specValuesNames { get; set; }
+        /// <summary>
+        /// 完整的属性信息
+        /// </summary>
+        public string specJson { get; set; }
+        /// <summary>
+        /// 商品等级
+        /// </summary>
+        public int? goodsLevel { get; set; }
+        /// <summary>
+        /// 卖家id
+        /// </summary>
+        public long sellerId { get; set; }
+        /// <summary>
+        /// 卖家名称
+        /// </summary>
+        public string sellerAlias { get; set; }
+        /// <summary>
+        /// 主图
+        /// </summary>
+        public string coverImg { get; set; }
+        /// <summary>
+        /// 主图宽
+        /// </summary>
+        public int coverWidth { get; set; }
+        /// <summary>
+        /// 主图高
+        /// </summary>
+        public int coverHeight { get; set; }
+        /// <summary>
+        /// 是否视频
+        /// </summary>
+        public bool hasVideo { get; set; }
+        /// <summary>
+        /// 视频编号
+        /// </summary>
+        public string videoId { get; set; }
+        /// <summary>
+        /// 视频是否可用,默认为false
+        /// </summary>
+        public bool videoReady { get; set; }
+        /// <summary>
+        /// 视频时长
+        /// </summary>
+        public string duration { get; set; }
+        /// <summary>
+        /// 原价
+        /// </summary>
+        public int originalPrice { get; set; }
+        /// <summary>
+        /// 销售价格
+        /// </summary>
+        public int salePrice { get; set; }
+        /// <summary>
+        /// 库存
+        /// </summary>
+        public int stock { get; set; }
+        /// <summary>
+        /// 商品来源(1,c2c商品)
+        /// </summary>
+        public short sourceType { get; set; }
+        /// <summary>
+        /// 是否禁用(1:禁用,0:启用)
+        /// </summary>
+        public bool disabled { get; set; }
+        /// <summary>
+        /// 禁用原因
+        /// </summary>
+        public string disabledReason { get; set; }
+        /// <summary>
+        /// 审核状态(0:未通过1,通过)
+        /// </summary>
+        public short auditState { get; set; }
+        /// <summary>
+        /// 刊登状态(0,下架,1,上架)
+        /// </summary>
+        public short onsaleState { get; set; }
+        /// <summary>
+        /// 下架原因类型(1,主动下架,2,售出下架)
+        /// </summary>
+        public short offsaleReasonType { get; set; }
+        /// <summary>
+        /// 商品版本(默认0,每次编辑加1,-1 为存在草稿箱)
+        /// </summary>
+        public int version { get; set; }
+        /// <summary>
+        /// 创建时间-录入时间
+        /// </summary>
+        public string createAt { get; set; }
+        /// <summary>
+        /// 修改时间
+        /// </summary>
+        public string updateAt { get; set; }
+        /// <summary>
+        /// 销售状态(0:未售,1,已售)
+        /// </summary>
+        public short saleState { get; set; }
+        /// <summary>
+        /// 浏览数
+        /// </summary>
+        public int viewCnt { get; set; }
+        /// <summary>
+        /// 收藏数
+        /// </summary>
+        public int collectCnt { get; set; }
+        /// <summary>
+        /// 分享数
+        /// </summary>
+        public int shareCnt { get; set; }
+        /// <summary>
+        /// 省份
+        /// </summary>
+        public string province { get; set; }
+        /// <summary>
+        /// 城市
+        /// </summary>
+        public string city { get; set; }
+    }
+}

+ 35 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESMobileAddress.cs

@@ -0,0 +1,35 @@
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /**
+     * 
+PUT /mobile_addr
+{
+  "mappings": {
+    "properties": {
+      "mobile": {
+        "type": "keyword"
+      },
+      "addr": {
+        "type": "keyword"
+      },
+      "province": {
+        "type": "keyword"
+      },
+      "city": {
+        "type": "keyword"
+      }
+    }
+  }
+}
+     */
+    /// <summary>
+    /// mobile_addr
+    /// </summary>
+    public class ESMobileAddress
+    {
+        public string mobile { get; set; }
+        public string addr { get; set; }
+        public string province { get; set; }
+        public string city { get; set; }
+    }
+}

+ 38 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESNLog.cs

@@ -0,0 +1,38 @@
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /// <summary>
+    /// n_log
+    /// </summary>
+    public class ESNLog
+    {
+        [ESId("_id")]
+        public string id { get; set; }
+        public int milliseconds { get; set; }
+
+        public string url { get; set; }
+
+        public string param { get; set; }
+
+        public int statusCode { get; set; }
+
+        public string errorMessage { get; set; }
+
+        public long userId { get; set; }
+
+        public string system { get; set; }
+
+        public DateTime logTime { get; set; }
+
+        public string ip { get; set; }
+
+        public string ipAddr { get; set; }
+
+        public string deviceId { get; set; }
+
+        public string deviceInfo { get; set; }
+
+        public string channel { get; set; }
+    }
+}

+ 72 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESPersonalPageViewRecordModel.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+DELETE /personalpageviewrecord
+
+PUT /personalpageviewrecord
+{
+  "mappings": {
+    "properties": {
+      "notValidRecord": {
+        "type": "boolean"
+      },
+      "isMock": {
+        "type": "boolean"
+      },
+      "pageUserId": {
+        "type": "long"
+      },
+      "isSelf": {
+        "type": "boolean"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "ip": {
+        "type": "keyword"
+      },
+      "clientId": {
+        "type": "keyword"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+    */
+    /// <summary>
+    /// 有效的主页访问记录
+    /// </summary>
+    public class ESPersonalPageViewRecordModel
+    {
+        /// <summary>
+        /// 是否不是有效阅读
+        /// </summary>
+        public bool notValidRecord { get; set; }
+        /// <summary>
+        /// 是否是模拟数据
+        /// </summary>
+        public bool isMock { get; set; }
+        /// <summary>
+        /// 主页用户的编号
+        /// </summary>
+        public long pageUserId { get; set; }
+        public bool isSelf { get; set; }
+        /// <summary>
+        /// 当匿名访问时,为0
+        /// </summary>
+        public long userId { get; set; }
+        public string ip { get; set; }
+        /// <summary>
+        /// 用户客户端的编号,如果是H5,则为生成的GUID
+        /// </summary>
+        public string clientId { get; set; }
+        public string createAt { get; set; }
+    }
+}

+ 212 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESPostModel.cs

@@ -0,0 +1,212 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+ DELETE /post
+
+
+PUT /post
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "long"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "userAlias": {
+        "type": "text",
+        "analyzer": "ik_smart"
+      },
+      "title": {
+        "type": "text",
+        "analyzer": "ik_smart"
+      },
+      "type": {
+        "type": "integer"
+      },
+      "categoryType": {
+        "type": "integer"
+      },
+      "onlyInTopic": {
+        "type": "integer"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      },
+      "state": {
+        "type": "integer"
+      },
+      "primaryType": {
+        "type": "integer"
+      },
+      "primaryTypes": {
+        "type": "keyword"
+      },
+	  "resourceCodes": {
+        "type": "keyword"
+      },
+	  "resourceNames": {
+        "type": "keyword"
+      },
+      "topicId": {
+        "type": "integer"
+      },
+      "topicName": {
+        "type": "text",
+        "analyzer": "ik_smart"
+      },
+      "topicIds": {
+        "type": "integer"
+      },
+      "topicNames": {
+        "type" : "text",
+        "analyzer": "ik_smart",
+        "fields" : {
+          "keyword" : {
+            "type" : "keyword",
+            "ignore_above" : 256
+          }
+        }
+      },
+      "validTopicIds": {
+        "type": "integer"
+      },
+      "validTopicNames": {
+        "type" : "text",
+        "analyzer": "ik_smart",
+        "fields" : {
+          "keyword" : {
+            "type" : "keyword",
+            "ignore_above" : 256
+          }
+        }
+      },
+      "summary": {
+        "type": "text",
+        "analyzer": "ik_smart"
+      },
+      "noMoreCont": {
+        "type": "integer"
+      },
+      "thumbnails": {
+        "type": "text",
+        "index": false
+      },
+      "contentState": {
+        "type": "integer"
+      },
+      "videoId": {
+        "type": "keyword"
+      },
+      "content": {
+        "type": "text",
+        "index": false
+      },
+      "coverWidth": {
+        "type": "integer"
+      },
+      "coverHeight": {
+        "type": "integer"
+      },
+      "tags": {
+        "type": "keyword"
+      },
+      "isBest": {
+        "type": "integer"
+      },
+      "subjectiveScore": {
+        "type": "float"
+      },
+      "hot": {
+        "type": "float"
+      },
+      "previewable": {
+        "type": "boolean"
+      },
+      "reprintSource": {
+        "type": "text",
+        "index": false
+      },
+      "reprintLink": {
+        "type": "text",
+        "index": false
+      }
+    }
+  }
+}
+     */
+    /// <summary>
+    /// ES中只记录通过审核的
+    /// </summary>
+    public class ESPostModel
+    {
+
+        public long id { get; set; }
+        public long userId { get; set; }
+        public string userAlias { get; set; }
+        public string title { get; set; }
+        public int type { get; set; }
+        public int categoryType { get; set; }
+        public int onlyInTopic { get; set; }
+        public string createAt { get; set; }
+        /// <summary>
+        /// 状态:0 待审核 1 通过 2 未通过 -1 删除
+        /// </summary>
+        public int state { get; set; }
+        /// <summary>
+        /// 文章所属主一级分类的值:如A股=1 港股=2 美股=4 英股=8
+        /// </summary>
+        public int primaryType { get; set; }
+        /// <summary>
+        /// 文章所属所有一级分类的值
+        /// </summary>
+        public string[] primaryTypes { get; set; }
+
+        public string[] resourceCodes { get; set; }
+        public string[] resourceNames { get; set; }
+
+        public int topicId { get; set; }
+        public string topicName { get; set; }
+
+        /// <summary>
+        /// 此文章关联的所有话题编号, 编号与名称一一对应
+        /// </summary>
+        public int[] topicIds { get; set; }
+        public string[] topicNames { get; set; }
+        /// <summary>
+        /// 此文章关联的所有有效的话题编号, 编号与名称一一对应
+        /// </summary>
+        public int[] validTopicIds { get; set; }
+        public string[] validTopicNames { get; set; }
+
+
+        public string summary { get; set; }
+        public int noMoreCont { get; set; }
+        public string thumbnails { get; set; }
+        public int contentState { get; set; }
+        public string videoId { get; set; }
+        public string content { get; set; }
+
+        public int coverWidth { get; set; }
+        public int coverHeight { get; set; }
+
+        public string[] tags { get; set; }
+        public int isBest { get; set; }
+        /// <summary>
+        /// 平台主观策略分
+        /// </summary>
+        public float subjectiveScore { get; set; }
+        public double hot { get; set; } = 0;
+
+        public bool previewable { get; set; }
+
+        public string reprintSource { get; set; }
+        public string reprintLink { get; set; }
+    }
+}

+ 84 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESPostReadRecordModel.cs

@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+DELETE /postreadrecord
+
+PUT /postreadrecord
+{
+  "mappings": {
+    "properties": {
+      "notValidRecord": {
+        "type": "boolean"
+      },
+      "isMock": {
+        "type": "boolean"
+      },
+      "postId": {
+        "type": "long"
+      },
+      "authorId": {
+        "type": "long"
+      },
+      "categoryType": {
+        "type": "integer"
+      },
+      "isAuthor": {
+        "type": "boolean"
+      },
+      "isFan": {
+        "type": "boolean"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "ip": {
+        "type": "keyword"
+      },
+      "clientId": {
+        "type": "keyword"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+    */
+    /// <summary>
+    /// 有效的阅读记录
+    /// </summary>
+    public class ESPostReadRecordModel
+    {
+        /// <summary>
+        /// 是否不是有效阅读
+        /// </summary>
+        public bool notValidRecord { get; set; }
+        /// <summary>
+        /// 是否是模拟数据
+        /// </summary>
+        public bool isMock { get; set; }
+        public long postId { get; set; }
+        public long authorId { get; set; }
+        public int categoryType { get; set; }
+        public bool isAuthor { get; set; }
+        /// <summary>
+        /// 阅读时,当前用户是否是粉丝
+        /// </summary>
+        public bool isFan { get; set; }
+        /// <summary>
+        /// 当前阅读的用户编号,未登录则为0
+        /// </summary>
+        public long userId { get; set; }
+        public string ip { get; set; }
+        /// <summary>
+        /// 用户客户端的编号,如果是H5,则为生成的GUID
+        /// </summary>
+        public string clientId { get; set; }
+        public string createAt { get; set; }
+    }
+}

+ 85 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESPostShareRecordModel.cs

@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+DELETE /postsharerecord
+
+PUT /postsharerecord
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "keyword"
+      },
+      "notValidRecord": {
+        "type": "boolean"
+      },
+      "isMock": {
+        "type": "boolean"
+      },
+      "postId": {
+        "type": "long"
+      },
+      "authorId": {
+        "type": "long"
+      },
+      "categoryType": {
+        "type": "integer"
+      },
+      "isAuthor": {
+        "type": "boolean"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "ip": {
+        "type": "keyword"
+      },
+      "clientId": {
+        "type": "keyword"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+    */
+    /// <summary>
+    /// 分享记录
+    /// </summary>
+    public class ESPostShareRecordModel
+    {
+        /// <summary>
+        /// 如果是已登录的,则为 postId_userId,其他为 guid
+        /// 这里将记录所有分享记录,id变为guid,不再存postId_userId形式
+        /// </summary>
+        public string id { get; set; }
+        /// <summary>
+        /// 是否不是有效分享
+        /// </summary>
+        public bool notValidRecord { get; set; }
+        /// <summary>
+        /// 是否是模拟数据
+        /// </summary>
+        public bool isMock { get; set; }
+        public long postId { get; set; }
+        public long authorId { get; set; }
+        public int categoryType { get; set; }
+        public bool isAuthor { get; set; }
+        /// <summary>
+        /// 当前分享的用户编号,未登录则为0
+        /// </summary>
+        public long userId { get; set; }
+        public string ip { get; set; }
+        /// <summary>
+        /// 用户客户端的编号,如果是H5,则为生成的GUID
+        /// </summary>
+        public string clientId { get; set; }
+        public string createAt { get; set; }
+    }
+}

+ 18 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESResponseData.cs

@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    public class ESResponseData<T>
+    {
+        public bool success = false;
+        public string errorMsg;
+        public int total = 0;
+        public List<T> data;
+    }
+    public class ESResponseAggregations
+    {
+        public bool success = false;
+        public string errorMsg;
+        public Dictionary<string,int> data;
+    }
+}

+ 32 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESSystemLog.cs

@@ -0,0 +1,32 @@
+using Elasticsearch.Net;
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    public class ESSystemLog
+    {
+        [ESField("time")]
+        public DateTime Time { get; set; }
+
+        [ESField("stacktrace")]
+        public string Stacktrace { get; set; }
+
+        [ESField("machineName")]
+        public string MachineName { get; set; }
+
+        [ESField("level")]
+        public string Level { get; set; }
+
+        [ESField("logger")]
+        public string Logger { get; set; }
+
+        [ESField("message")]
+        public string Message { get; set; }
+
+        [ESField("applicationName")]
+        public string ApplicationName { get; set; }
+
+        [ESField("processid")]
+        public int Processid { get; set; }
+    }
+}

+ 57 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESUserCollectRecord.cs

@@ -0,0 +1,57 @@
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    
+    /*
+PUT /user_collect_record
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "keyword"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "postId": {
+        "type": "long"
+      },
+      "authorId": {
+        "type": "long"
+      },
+      "categoryType": {
+        "type": "integer"
+      },
+      "enabled": {
+        "type": "integer"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      },
+      "updateAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+     */
+    /// <summary>
+    /// user_collect_record
+    /// </summary>
+    public class ESUserCollectRecord
+    {
+        [ESId("_id")]
+        public string id { get; set; }
+        public long userId { get; set; }
+        public long postId { get; set; }
+        public long authorId { get; set; }
+        public int categoryType { get; set; }
+        public int enabled { get; set; }
+        public DateTime createAt { get; set; }
+        public DateTime updateAt { get; set; }
+
+    }
+}

+ 49 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESUserFansRecord.cs

@@ -0,0 +1,49 @@
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+
+    /*
+PUT /user_fans_record
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "keyword"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "fansId": {
+        "type": "long"
+      },
+      "enabled": {
+        "type": "integer"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      },
+      "updateAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+     */
+    /// <summary>
+    /// user_fans_record
+    /// </summary>
+    public class ESUserFansRecord
+    {
+        [ESId("_id")]
+        public string id { get; set; }
+        public long userId { get; set; }
+        public long fansId { get; set; }
+        public int enabled { get; set; }
+        public DateTime createAt { get; set; }
+        public DateTime updateAt { get; set; }
+
+    }
+}

+ 68 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESUserModel.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+    /*
+DELETE /user
+
+PUT /user
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "long"
+      },
+      "alias": {
+        "type": "text",
+        "analyzer": "ik_max_word"
+      },
+      "username": {
+        "type": "keyword"
+      },
+      "sex": {
+        "type": "short"
+      },
+      "authType": {
+        "type": "short"
+      },
+      "authName": {
+        "type": "keyword"
+      },
+      "domainTalent": {
+        "type": "keyword"
+      },
+      "headImage": {
+        "type": "text",
+        "index": false
+      },
+      "description": {
+        "type": "text",
+        "analyzer": "ik_max_word"
+      },
+      "fansCount": {
+        "type": "integer"
+      }
+    }
+  }
+}
+    */
+    /// <summary>
+    /// ES中记录未禁用的用户
+    /// </summary>
+    public class ESUserModel
+    {
+        public long id { get; set; }
+        public string alias { get; set; }
+        public string username { get; set; }
+        public short sex { get; set; }
+        public short authType { get; set; }
+        public string[] authName { get; set; }
+        public string[] domainTalent { get; set; }
+        public short vip { get; set; }
+        public string headImage { get; set; }
+        public string description { get; set; }
+        public int fansCount { get; set; }
+    }
+}

+ 55 - 0
JiaZhiQuan.Common/ElasticSearch/Models/ESUserThumbsupRecord.cs

@@ -0,0 +1,55 @@
+using System;
+
+namespace JiaZhiQuan.Common.ElasticSearch.Models
+{
+
+ /*
+PUT /user_thumbsup_record
+{
+  "mappings": {
+    "properties": {
+      "id": {
+        "type": "keyword"
+      },
+      "userId": {
+        "type": "long"
+      },
+      "postId": {
+        "type": "long"
+      },
+      "authorId": {
+        "type": "long"
+      },
+      "categoryType": {
+        "type": "integer"
+      },
+      "enabled": {
+        "type": "integer"
+      },
+      "createAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      },
+      "updateAt": {
+        "type": "date",
+        "format": "yyyy-MM-dd HH:mm:ss"
+      }
+    }
+  }
+}
+  */
+    /// <summary>
+    /// user_thumbsup_record
+    /// </summary>
+    public class ESUserThumbsupRecord {
+        [ESId("_id")]
+        public string id { get; set; }
+        public long userId { get; set; }
+        public long postId { get; set; }
+        public long authorId { get; set; }
+        public int categoryType { get; set; }
+        public int enabled { get; set; }
+        public DateTime createAt { get; set; }
+        public DateTime updateAt { get; set; }
+    }
+}

+ 27 - 0
JiaZhiQuan.Common/Enum/ActivityDaka.cs

@@ -0,0 +1,27 @@
+namespace JiaZhiQuan.Common
+{
+    public class ActivityDaka
+    {
+
+        //机会来源 0 打卡 1 价值币购买
+        public enum DakaDrawGainSource
+        {
+            打卡 = 0,
+            价值币购买 = 1
+        }
+        //抽奖类型 0 普通抽奖 1 终极抽奖
+        public enum DakaDrawGainType
+        {
+            普通抽奖 = 0,
+            终极抽奖 = 1
+        }
+        //抽奖商品类型
+        public enum DakaDrawGoodsType
+        {
+            谢谢参与 = -1,
+            价值币 = 0,
+            虚拟商品 = 1,
+            实体商品 = 2,
+        }
+    }
+}

+ 50 - 0
JiaZhiQuan.Common/Enum/ActivityTypes.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common
+{
+    /// <summary>
+    /// 活动分类
+    /// </summary>
+    public static class ActivityTypes
+    {
+
+        public static Dictionary<string, string> CodeDescriptionMapping { get; } = new Dictionary<string, string>();
+
+        static ActivityTypes()
+        {
+            var members = typeof(ActivityTypes).GetFields();
+            members.ForEach(e =>
+            {
+                var attr = Attribute.GetCustomAttribute(e, typeof(DescriptionAttribute)) as DescriptionAttribute;
+                if (attr != null)
+                {
+                    CodeDescriptionMapping.Add((string)e.GetRawConstantValue(), attr.Description);
+                }
+            });
+        }
+        
+        
+        [Description("猜涨跌")]
+        public const string 猜涨跌 = "czd";
+
+        [Description("答题")]
+        public const string 答题 = "dt";
+
+        [Description("晒笔记")]
+        public const string 晒笔记 = "sbj";
+
+        [Description("邀请好友")]
+        public const string 邀请好友 = "yqhy";
+
+        [Description("每日话题")]
+        public const string 每日话题 = "mrht";
+        
+        [Description("阅读量大比拼")]
+        public const string 阅读量大比拼 = "ydldbp";
+        
+        [Description("打卡")]
+        public const string 打卡 = "daka";
+    }
+}

+ 10 - 0
JiaZhiQuan.Common/Enum/AppActionDataConstants.cs

@@ -0,0 +1,10 @@
+namespace JiaZhiQuan.Common
+{
+    public class AppActionDataConstants
+    {
+        /// <summary>
+        /// 用户注册后距离第一次发布比较的间隔时间
+        /// </summary>
+        public static string FactUserFirstPublishPost = "fact_user_first_publish_post";
+    }
+}

+ 71 - 0
JiaZhiQuan.Common/Enum/AppPushMessageTypes.cs

@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common
+{
+    public static class AppPushMessageTypes
+    {
+        /// <summary>
+        /// 点击消息无反应
+        /// </summary>
+        public static string 无行为 => "NONE";
+
+        /// <summary>
+        /// 链接
+        /// </summary>
+        public static string 链接 => "LINK";
+
+        #region 后续会移除
+        
+        /// <summary>
+        /// XXX评论了你的资讯/笔记
+        /// content = { id(评论的Id), postId(动态/笔记的Id), type(0 图文 1 视频), categoryType(0 资讯 1 笔记 2 研报) }
+        /// </summary>
+        [Obsolete]
+        public static string 评论 => "COMMENT";
+
+        /// <summary>
+        /// XXX回复了你的评论
+        /// content = { id(回复的Id), postId(动态/笔记的Id), type(0 图文 1 视频), categoryType(0 资讯 1 笔记 2 研报) }
+        /// </summary>
+        [Obsolete]
+        public static string 评论的回复 => "COMMENT_REPLY";
+
+        /// <summary>
+        /// XXX回复了你的评论
+        /// content = { id(回复的Id), postId(动态/笔记的Id), type(0 图文 1 视频), categoryType(0 资讯 1 笔记 2 研报) }
+        /// </summary>
+        [Obsolete]
+        public static string 回复的回复 => "REPLY_REPLY";
+
+        /// <summary>
+        /// XXX赞了你的资讯/笔记
+        /// content = { id(资讯/笔记的Id), type(0 图文 1 视频), categoryType(0 资讯 1 笔记 2 研报) }
+        /// </summary>
+        [Obsolete]
+        public static string 动态的点赞 => "POST_THUMBSUP";
+
+        /// <summary>
+        /// XXX关注了你
+        /// content = { id(主动关注用户的Id) }
+        /// </summary>
+        [Obsolete]
+        public static string 关注了你 => "FOCUS";
+
+        /// <summary>
+        /// XXX发布了新动态,快来看看吧!(暂时只有笔记)
+        /// content = { id(动态的Id), type(0 图文 1 视频), categoryType(1 笔记 2 研报) }
+        /// </summary>
+        [Obsolete]
+        public static string 某人新动态通知 => "POST_NEW";
+
+        /// <summary>
+        /// XXX圈子有新动态了
+        /// </summary>
+        [Obsolete]
+        public static string 话题新动态通知 => "TOPIC_NEW_POST";
+        
+        #endregion 后续会移除
+    }
+}

+ 32 - 0
JiaZhiQuan.Common/Enum/BalanceBizCodes.cs

@@ -0,0 +1,32 @@
+using System;
+namespace JiaZhiQuan.Common
+{
+    public static class BalanceBizCodes
+    {
+        /// <summary>
+        /// 某一天的创作收益,对应的BizData为 yyyy-MM-dd
+        /// </summary>
+        public const string CREATION = "CREATION";
+
+        /// <summary>
+        /// 创作收益修正,对应BizData为 n_stat_settlement记录编号
+        /// </summary>
+        public const string CREATIONFIX = "CREATIONFIX";
+
+        /// <summary>
+        /// 内容奖励,对应BizData为 n_balance_reward记录编号
+        /// </summary>
+        public const string REWARD = "REWARD";
+
+        /// <summary>
+        /// 取现,对应BizData为 n_balance_cashout_apply记录编号
+        /// </summary>
+        public const string CASHOUT = "CASHOUT";
+
+        /// <summary>
+        /// 取现失败,对应BizData为 n_balance_cashout_apply记录编号
+        /// </summary>
+        public const string CASHOUTFAILED = "CASHOUTFAILED";
+    }
+}
+

+ 21 - 0
JiaZhiQuan.Common/Enum/ClassEnum/AbstractEnum.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.ClassEnum {
+    public abstract class AbstractEnum<TEnum> where TEnum : notnull, AbstractEnum<TEnum> {
+        protected static readonly Type enumType = typeof(TEnum);
+
+        protected readonly static List<TEnum> Values = ListEnumProperties();
+        private static List<TEnum> ListEnumProperties() {
+            List<TEnum> values = new List<TEnum>();
+            var members = enumType.GetProperties();
+            foreach (var item in members) {
+                if (item.PropertyType == enumType) {
+                    TEnum? value = (TEnum?)item.GetValue(enumType);
+                    if (value != null) { values.Add(value); }
+                }
+            }
+            return values;
+        }
+    }
+}

+ 25 - 0
JiaZhiQuan.Common/Enum/ClassEnum/AppIndexTabEnum.cs

@@ -0,0 +1,25 @@
+using System.Linq;
+
+namespace JiaZhiQuan.Common.ClassEnum {
+    public sealed class AppIndexTabEnum : AbstractEnum<AppIndexTabEnum> {
+        public static AppIndexTabEnum COMMUNITY => new AppIndexTabEnum(0, "AppIndexPageTabConfig","社区");
+        public static AppIndexTabEnum MALL => new AppIndexTabEnum(1, "MallAppIndexPageTabConfig","商城");
+
+        public readonly string configKeyName;
+        public readonly int category;
+        public readonly string desc;
+
+        private AppIndexTabEnum(int category, string configKeyName,string desc) {
+            this.category = category;
+            this.configKeyName = configKeyName;
+            this.desc = desc;
+        }
+
+        public static AppIndexTabEnum GetEnumByName(string configKeyName) {
+            return Values.FirstOrDefault(item => item.configKeyName == configKeyName);
+        }
+        public static AppIndexTabEnum GetEnumByCategory(int? category) {
+            return Values.FirstOrDefault(item => item.category == category);
+        }
+    }
+}

+ 514 - 0
JiaZhiQuan.Common/Enum/Enums.cs

@@ -0,0 +1,514 @@
+using JiaZhiQuan.Common.Attributes;
+
+namespace JiaZhiQuan.Common
+{
+    public enum PostState
+    {
+        待审核 = 0,
+        通过 = 1,
+        未通过 = 2,
+        删除 = -1,
+    }
+
+    public enum ThumbsupTargetType
+    {
+        文章 = 0,
+        评论 = 1,
+        回复 = 2,
+    }
+
+    public enum PostCategoryType
+    {
+        资讯 = 0,
+        笔记 = 1,
+        研报 = 2,
+    }
+
+    public enum EnableStatus
+    {
+        禁用 = 0,
+        启用 = 1
+    }
+
+    public enum DisabledStatus
+    {
+        禁用 = 1,
+        启用 = 0
+    }
+
+    public class Post
+    {
+        public enum PostState
+        {
+            待审核 = 0,
+            通过 = 1,
+            未通过 = 2,
+            删除 = -1,
+        }
+    }
+
+    /// <summary>
+    /// 成长体系
+    /// </summary>
+    public class UserGrow
+    {
+        public enum TaskEvent
+        {
+
+            /// <summary>
+            /// 首次完善资料至100%
+            /// </summary>
+            CompleteSelfData = 1,
+
+            /// <summary>
+            /// 首次完成实名认证
+            /// </summary>
+            RealNameAuth = 2,
+
+            /// <summary>
+            /// 首次通过创作者认证或优质创作者认证
+            /// </summary>
+            AuthorAuth = 3,
+
+            /// <summary>
+            /// 申请提现一次
+            /// </summary>
+            Withdrawal = 4,
+
+            /// <summary>
+            /// 每日阅读过X篇笔记
+            /// </summary>
+            DayRead = 5,
+            /// <summary>
+            /// 每日点赞过X篇笔记
+            /// </summary>
+            DayThumbsup = 6,
+
+            /// <summary>
+            /// 收藏
+            /// </summary>
+            Collect = 7,
+
+            /// <summary>
+            /// 分享
+            /// </summary>
+            Share = 8,
+
+            /// <summary>
+            /// 发布评论或回复
+            /// </summary>
+            PublishCommentOrReply = 9,
+
+            /// <summary>
+            /// 关注用户
+            /// </summary>
+            FocusUser = 10,
+
+            /// <summary>
+            /// 用户发布笔记
+            /// </summary>
+            PublishPost = 11,
+
+            /// <summary>
+            /// 审核笔记通过
+            /// </summary>
+            CheckPost = 12
+        }
+
+        public enum ExperienceSource
+        {
+            任务 = 0
+        }
+    }
+
+    public class IM
+    {
+        public enum MessageState
+        {
+            未读 = 0,
+            已读 = 1,
+            撤回 = 2
+        }
+    }
+
+    public class Balance
+    {
+        public enum CashoutApplyStatus
+        {
+            待审核 = 0,
+            审核通过 = 1,
+            审核未通过 = 2
+        }
+
+        public enum CashoutTaskStatus
+        {
+            待打款 = 0,
+            已打款 = 1,
+            /// <summary>
+            /// 打款失败未确认
+            /// </summary>
+            打款中 = 2,
+            打款失败 = 3
+        }
+
+        public enum CashoutTaskSourceType
+        {
+            提现 = 0,
+            支付宝红包 = 1,
+            C2C订单分账 = 2
+        }
+    }
+
+    public class Active
+    {
+        public enum RewardReceiveState
+        {
+            待兑换 = 0,
+            已兑换 = 1,
+            已过期 = 2,
+            兑换中 = 3
+        }
+    }
+
+    public class CreatorSpace
+    {
+        public enum CreatorSpaceType
+        {
+            [CreatorSpaceTypeDesc("近七日数据总览", 0, 6, true)]
+            数据中心 = 0,
+            [CreatorSpaceTypeDesc("创作服务", 1, 5, true)]
+            创作服务 = 1,
+            [CreatorSpaceTypeDesc("活动卡片", 2, 4, false)]
+            活动卡片 = 2,
+            [CreatorSpaceTypeDesc("活动专区", 3, 3, false)]
+            活动专区 = 3,
+            [CreatorSpaceTypeDesc("我的作品", 4, 2, true)]
+            我的作品 = 4,
+            [CreatorSpaceTypeDesc("", 5, 1, true)]
+            Banner = 5
+        }
+
+        /// <summary>
+        /// 活动专题,Style类型
+        /// </summary>
+        public enum ActivityRegionStyleType
+        {
+            长方形小图 = 0,
+            正方形小图 = 1,
+            大图 = 2
+        }
+
+        public enum ActivityCardVisual
+        {
+            非创作者 = 1,
+            创作者 = 2,
+            所有人 = 3
+        }
+    }
+    public class UserInvite
+    {
+        public enum InviterRole
+        {
+            普通用户 = 0,
+            合作方 = 1
+        }
+        public enum RegisterChannel
+        {
+            H5 = 0
+        }
+        public enum State
+        {
+            已注册未激活 = 0,
+            已激活 = 1
+        }
+        public enum ActiveChannel
+        {
+            Android = 0,
+            iOS = 1
+        }
+
+        public enum SettlementState
+        {
+            已结算 = 0,
+            撤销 = -1
+        }
+
+        public enum PartenrEventDetails
+        {
+            启用合作方 = 0,
+            禁用合作方 = 1,
+            修改邀请单价为 = 2,
+            添加合作方邀请单价为 = 3,
+            邀请无效的非首次注册用户 = 4,
+            邀请无效的非新设备首登用户 = 5
+        }
+    }
+    public class DeviceChannel
+    {
+        public enum DeviceState
+        {
+            新设备 = 0,
+            非新设备 = 1
+        }
+        public enum PhoneState
+        {
+            首次注册 = 0,
+            非首次注册 = 1,
+            新设备登录 = 2
+        }
+    }
+
+    /// <summary>
+    /// 用户完善资料类型 1昵称、2简介、3性别、4生日、5地区、6学校、7兴趣标签、8背景图
+    /// </summary>
+    public enum UserProfileType
+    {
+        Alias = 1,
+        Description = 2,
+        Sex = 3,
+        Birthday = 4,
+        Region = 5,
+        School = 6,
+        InterestTag = 7,
+        BgImage = 8
+    }
+
+    public class NotifyRecord
+    {
+        public enum NotifyRecordType
+        {
+            生日祝福提醒 = 1,
+            每日打卡提醒打卡 = 2,
+            每日打卡提醒终极抽奖 = 3
+        }
+    }
+
+    /// <summary>
+    /// 商品来源(1,c2c商品)
+    /// </summary>
+    public enum MallGoodsSourceType
+    {
+        c2c商品 = 1
+    }
+    /// <summary>
+    /// 删除状态
+    /// </summary>
+    public enum DeletedState
+    {
+        正常 = 0,
+        已删 = 1
+    }
+
+    /// <summary>
+    /// 提现来源类型
+    /// </summary>
+    public enum BalanceCashoutTaskSourceType
+    {
+        提现 = 0,
+        支付宝红包打款 = 1,
+        C2C订单分账打款 = 2
+    }
+
+    /// <summary>
+    /// 流水记录流水类型
+    /// </summary>
+    public enum MallBillRecordBillType
+    {
+        支付流水 = 1,
+        分账流水 = 2,
+        退单流水 = 3
+    }
+
+    /// <summary>
+    /// 流水记录状态
+    /// </summary>
+    public enum MallBillRecordBillState
+    {
+        待支付 = 1,
+        已支付 = 2,
+        失败 = 3
+    }
+    
+    /// <summary>
+    /// 商品审核状态
+    /// </summary>
+    public enum MallGoodsAuditState
+    {
+        未通过 = 0,
+        通过 = 1
+    }
+    /// <summary>
+    /// 刊登状态
+    /// </summary>
+    public enum MallGoodsOnsaleState
+    {
+        下架 = 0,
+        上架 = 1
+    }
+
+    /// <summary>
+    /// 销售状态
+    /// </summary>
+    public enum MallGoodsSaleState
+    {
+        未售 = 0,
+        已售 = 1
+    }
+
+    /// <summary>
+    /// 下架原因类型
+    /// </summary>
+    public enum MallGoodsOffsaleReasonType
+    {
+        主动下架 = 1,
+        售出下架 = 2
+    }
+
+    /// <summary>
+    /// 商品变更类型枚举
+    /// </summary>
+    public enum MallGoodsChangeEventType
+    {
+        创建编辑 = 1,
+        审核 = 2,
+        刊登 = 3,
+        删除 = 4,
+        启用禁用 = 5,
+        销售 = 6
+    }
+
+    /// <summary>
+    /// C2C订单状态
+    /// </summary>
+    public enum MallOrderState
+    {
+        订单关闭 = -9,
+        卖家取消 = -2,
+        买家取消 = -1,
+        待支付 = 1,
+        待发货 = 2,
+        待收货 = 3,
+        交易成功 = 4
+    }
+
+    /// <summary>
+    /// C2C订单退款状态
+    /// </summary>
+    public enum MallOrderRefundState
+    {
+        待退款 = 0,
+        退款中 = 1,
+        已退款 = 2,
+        退款失败 = -1
+    }
+
+    /// <summary>
+    /// C2C订单评价状态
+    /// </summary>
+    public enum MallOrderRatingState
+    {
+        订单未成功交易 = 0,
+        待评 = 1,
+        已评 = 2,
+        超时未评 = 3
+    }
+
+    /// <summary>
+    /// C2C订单评价类型
+    /// </summary>
+    public enum MallOrderRatingType
+    {
+        差评 = 0,
+        中评 = 1,
+        好评 = 2
+    }
+
+    /// <summary>
+    /// C2C商城中用户身份类型(买家或卖家)
+    /// </summary>
+    public enum MallUserType
+    {
+        买家 = 1,
+        卖家 = 2
+    }
+    
+    /// <summary>
+    /// 商品变更事件操作人类型
+    /// </summary>
+    public enum MallGoodsChangeOperatorType
+    {
+        平台 = 0,
+        买家 = 1,
+        卖家 = 2,
+        运营人员 = 3
+    }
+
+    /// <summary>
+    /// C2C订单变更事件操作人类型
+    /// </summary>
+    public enum MallOrderChangeOperatorType
+    {
+        平台 = 0,
+        买家 = 1,
+        卖家 = 2,
+        运营人员 = 3
+    }
+
+    /// <summary>
+    /// C2C支付订单支付状态
+    /// </summary>
+    public enum MallPayOrderState
+    {
+        待支付 = 0,
+        已支付 = 1,
+        支付失败 = 2,
+        支付订单关闭 = 3
+    }
+
+    /// 商品等级
+    /// </summary>
+    public enum MallGoodsLevel
+    {
+        S = 0,
+        A = 1,
+        B = 2,
+        C = 3,
+        D = 4,
+        R = 5
+    }
+
+    public enum UEBillEventType {
+        /// <summary>
+        /// 无
+        /// </summary>
+        None=0,
+        /// <summary>
+        /// 订单支付
+        /// </summary>
+        OrderPay = 1,
+        /// <summary>
+        /// 仓储费支付
+        /// </summary>
+        StoragePay = 2,
+        /// <summary>
+        /// 买家订单取消退款
+        /// </summary>
+        OrderRefund = 3,
+        /// <summary>
+        /// 后台订单取消退款
+        /// </summary>
+        OrderRefundBySys = 4,
+        /// <summary>
+        /// 下单抵扣
+        /// </summary>
+        OrderDiKou = 5,
+        /// <summary>
+        /// 提现
+        /// </summary>
+        Chash = 6,
+        /// <summary>
+        /// 退回保证金
+        /// </summary>
+        DepositRefund= 7,
+    }
+}

+ 13 - 0
JiaZhiQuan.Common/Enum/MallConstants.cs

@@ -0,0 +1,13 @@
+namespace JiaZhiQuan.Common
+{
+    /// <summary>
+    /// 商城相关的常量
+    /// </summary>
+    public class MallConstants
+    {
+        /// <summary>
+        /// 每天商品的推荐数量
+        /// </summary>
+        public static int DayGoodsRecommendSumCount = 1000;
+    }
+}

+ 21 - 0
JiaZhiQuan.Common/Enum/RetationDateConstants.cs

@@ -0,0 +1,21 @@
+namespace JiaZhiQuan.Common
+{
+    public static class RetationDateConstants
+    {
+
+        /// <summary>
+        /// 留存的天数统计,不是以下天数的不记录
+        /// </summary>
+        public static int[] RetainDay = new[] { 1, 2, 3, 4, 5, 6, 7, 14, 30 };
+
+        /// <summary>
+        /// 留存的周数统计,不是以下周数的不记录
+        /// </summary>
+        public static int[] RetainWeek = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        /// <summary>
+        /// 留存的月数统计,不是以下月数的不记录
+        /// </summary>
+        public static int[] RetainMonth = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    }
+}

+ 89 - 0
JiaZhiQuan.Common/Enum/UserMessageRecordType.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common
+{
+    public static class UserMessageRecordType
+    {
+        /// <summary>
+        /// JSON内容定义见 UserMessageSystemCntType
+        /// </summary>
+        public static int 系统通知 => -1;
+
+        /// <summary>
+        /// JSON内容定义:{ commentId, type, refId, refType, postId, categoryType } // type/refType 0为评论 1为回复
+        /// </summary>
+        public static int 评论我的 => 0;
+
+        /// <summary>
+        /// JSON内容定义:{ postId, categoryType }
+        /// </summary>
+        public static int 赞我的 => 1;
+
+        /// <summary>
+        /// 无JSON内容
+        /// </summary>
+        public static int 被关注 => 2;
+    }
+
+    public static class UserMessageSystemCntType
+    {
+        /// <summary>
+        /// content = { title, content, image, actionLink }
+        /// </summary>
+        public static string 默认 => "DEFAULT";
+
+        /// <summary>
+        /// content = { title, content, postId, image, actionLink }
+        /// </summary>
+        public static string 动态相关通知 => "POST";
+
+        /// <summary>
+        /// content = { title,content, afterSaleId, image, actionLink }
+        /// </summary>
+        public static string 售后单通知 => "AFTER_SALE";
+
+        /// <summary>
+        /// 订单详情
+        /// content = { title, content, orderId, image, actionLink }
+        /// </summary>
+        public static string 订单 => "MALL_ORDER";
+
+        /// <summary>
+        /// 商品详情
+        /// content = { title, content, goodsId, image, actionLink }
+        /// </summary>
+        public static string 商品 => "MALL_GOODS";
+
+        /// <summary>
+        /// 商城订单分账流水详情
+        /// content = { title, content, billId, orderId, image, actionLink }
+        /// </summary>
+        public static string 订单分账流水详情 => "MALL_CASH_OUT_BILL";
+        
+        /// <summary>
+        /// 商城订单退单流水详情
+        /// content = { title, content, billId, orderId, image, actionLink }
+        /// </summary>
+        public static string 订单退单流水详情 => "MALL_REFUND_BILL";
+
+        /// <summary>
+        /// 二手商城寄售订单
+        /// content = { title, content, orderId, image, actionLink }
+        /// </summary>
+        public static string 二手商城寄售订单 => "UE_POST_ORDER";
+        
+        /// <summary>
+        /// 二手商城寄售销售订单
+        /// content = { title, content, orderId, saleOrderId, image, actionLink }
+        /// </summary>
+        public static string 二手商城寄售销售订单 => "UE_POST_SALE_ORDER";
+        
+        /// <summary>
+        /// 二手商城挂售销售订单
+        /// content = { title, content, orderId, image, actionLink }
+        /// </summary>
+        public static string 二手商城挂售销售订单 => "UE_HANG_SALE_ORDER";
+    }
+}

+ 155 - 0
JiaZhiQuan.Common/ErrorCodes/ErrorCodes.cs

@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace JiaZhiQuan.Common
+{
+    public static class ErrorCodes
+    {
+        private static Dictionary<int, string> codeDescriptionMapping = new Dictionary<int, string>();
+
+        static ErrorCodes()
+        {
+            var members = typeof(ErrorCodes).GetFields();
+            members.ForEach(e =>
+            {
+                var attr = Attribute.GetCustomAttribute(e, typeof(DescriptionAttribute)) as DescriptionAttribute;
+                if (attr != null)
+                {
+                    codeDescriptionMapping.Add((int)e.GetRawConstantValue(), attr.Description);
+                }
+            });
+        }
+
+        public const int Success = 200;
+
+        [Description("需要登录")]
+        public const int NeedLogin = 401;
+
+        [Description("无权限")]
+        public const int PermissionDenied = 403;
+
+        [Description("不存在")]
+        public const int NotExist = 404;
+
+
+        [Description("程序处理错误")]
+        public const int Exception = 500;
+
+        [Description("参数错误")]
+        public const int ParameterError = 501;
+
+
+        [Description("用户注册时,用户已存在")]
+        public const int UserRegisterAlreadyExistError = 601;
+
+        [Description("用户登录时用户名或密码不正确")]
+        public const int UserLoginUserNameOrPasswordError = 602;
+
+        [Description("用户被禁用,无法登录")]
+        public const int UserDisabledError = 603;
+        [Description("用户不存在")]
+        public const int UserNotExistError = 604;
+
+        [Description("微信授权失败")]
+        public const int WXAuthorizationError = 605;
+        [Description("新浪微博授权失败")]
+        public const int WeiboAuthorizationError = 606;
+
+        [Description("账号在其他设备登录")]
+        public const int LogoutByMultiLogin = 607;
+
+
+        [Description("上传文件格式不正确")]
+        public const int UploadFileFormatError = 611;
+
+        [Description("上传文件太大")]
+        public const int UploadFileSizeLimitError = 612;
+
+        [Description("上传到OSS失败")]
+        public const int UploadFileToOSSError = 613;
+
+        [Description("上传时未选择图片")]
+        public const int UploadFileNoFileError = 614;
+
+        [Description("已经签到了,不能重复签到")]
+        public const int AlreadySignOn = 615;
+
+        [Description("粉钻不足")]
+        public const int PointsNotEnough = 631;
+        [Description("商品库存不足")]
+        public const int StockNotEnough = 632;
+        [Description("锂币不足")]
+        public const int CoinNotEnough = 633;
+
+
+        [Description("购买商品过期")]
+        public const int OrderProductionDisasbled = 640;
+        [Description("苹果内购验证失败")]
+        public const int OrderApplePayValidationError = 641;
+        [Description("PayNo已使用")]
+        public const int OrderPayNoHasBeenUsed = 642;
+        [Description("订单已支付,不能重复支付")]
+        public const int OrderPaied = 643;
+        [Description("支付失败(其他错误)")]
+        public const int OrderPayFailed = 644;
+        [Description("订单不支持此操作")]
+        public const int OrderOperationNotAllowed = 645;
+        [Description("订单退单金额超限")]
+        public const int OrderRefundAmountLimit = 646;
+        [Description("订单退单金额超限")]
+        public const int InvoiceTitleLimit = 647;
+
+
+        [Description("短信发送太频繁(未达到当日最大发送量)")]
+        public const int SMSendBusinessLimitError = 681;
+
+        [Description("短信当天发送太频繁(已达到当日最大发送量)")]
+        public const int SMSendDayLimitError = 682;
+
+        [Description("短信手机号不正确")]
+        public const int SMSendPhoneNumberError = 683;
+
+
+        [Description("活动已报过名")]
+        public const int ActivityEnrolled = 700;
+        [Description("活动报名未开始")]
+        public const int ActivityEnrollNotStarted = 701;
+        [Description("活动报名已结束")]
+        public const int ActivityEnrollEnded = 702;
+        [Description("活动类型为4的组已满员")]
+        public const int ActivityT4GroupIsFull = 703;
+
+
+        [Description("购物车已满")]
+        public const int ShoppingCartIsFull = 801;
+        [Description("购物车是空的,不能购买")]
+        public const int ShoppingCartIsEmpty = 802;
+        [Description("商品暂时不能购买")]
+        public const int GoodsNotAvailable = 803;
+        [Description("预订单中的商品价格发生变更")]
+        public const int PreorderGoodsInfoChanged = 804;
+
+        [Description("商品类目不存在")]
+        public const int CategoryNotExist = 805;
+
+        [Description("商品属性值需要刷新")]
+        public const int CategoryRefresh = 806;
+
+        [Description("由于隐私导致无权限访问")]
+        public const int PrivacyDenied = 900;
+
+        /// <summary>
+        /// 通过Code值,获取对应的描述
+        /// </summary>
+        public static string GetDescription(int code)
+        {
+            if (codeDescriptionMapping.ContainsKey(code))
+            {
+                return codeDescriptionMapping[code];
+            }
+            return string.Empty;
+        }
+    }
+}

+ 24 - 0
JiaZhiQuan.Common/Hubs/ClientConnectionInfo.cs

@@ -0,0 +1,24 @@
+namespace JiaZhiQuan.Common.Hubs
+{
+    /// <summary>
+    /// 客户端连接信息
+    /// </summary>
+    public class ClientConnectionInfo
+    {
+        /// <summary>
+        /// 客户端连接Id
+        /// </summary>
+        public string ClientConnectionId { get; set; }
+        
+        /// <summary>
+        /// 用户Id
+        /// </summary>
+        public long? UserId { get; set; }
+
+        /// <summary>
+        /// 是否登录
+        /// </summary>
+        public bool isLogin { get; set; }
+
+    }
+}

+ 141 - 0
JiaZhiQuan.Common/Hubs/ServerResultDTO.cs

@@ -0,0 +1,141 @@
+namespace JiaZhiQuan.Common.Hubs
+{
+    /// <summary>
+    /// 服务端返回的格式
+    /// </summary>
+    public class ServerResultDTO
+    {
+        public ServerResultDTO(ResultMessageEvent messageEvent, ResultMessageStatus messageStatus, string message)
+        {
+            Event = messageEvent;
+            MessageStatus = messageStatus;
+            Message = message;
+        }
+
+        public ServerResultDTO(ResultMessageEvent messageEvent, ResultMessageStatus messageStatus, string message, object data)
+        {
+            Event = messageEvent;
+            MessageStatus = messageStatus;
+            Message = message;
+            Data = data;
+        }
+
+        /// <summary>
+        /// 执行结果
+        /// </summary>
+        public ResultMessageStatus MessageStatus { get; set; }
+
+        /// <summary>
+        /// 内容
+        /// </summary>
+        public string Message { get; set; }
+
+        /// <summary>
+        /// 数据
+        /// </summary>
+        public object Data { get; set; }
+
+        /// <summary>
+        /// 消息事件类型
+        /// </summary>
+        public ResultMessageEvent Event { get; set; }
+
+        public static ServerResultDTO Success(ResultMessageEvent messageEvent, string message)
+        {
+            return new ServerResultDTO(messageEvent, ResultMessageStatus.Success, message);
+        }
+
+        public static ServerResultDTO Success(ResultMessageEvent messageEvent, string message, object data)
+        {
+            return new ServerResultDTO(messageEvent, ResultMessageStatus.Success, message, data);
+        }
+
+        public static ServerResultDTO Error(ResultMessageEvent messageEvent, string message)
+        {
+            return new ServerResultDTO(messageEvent, ResultMessageStatus.Error, message);
+        }
+
+        public static ServerResultDTO Error(ResultMessageEvent messageEvent, string message, object data)
+        {
+            return new ServerResultDTO(messageEvent, ResultMessageStatus.Error, message, data);
+        }
+    }
+
+    public enum ResultMessageStatus
+    {
+        Success,
+        Error
+    }
+    public enum ResultMessageEvent
+    {
+        /// <summary>
+        /// 连接SignalR
+        /// </summary>
+        Connection = 0,
+
+        /// <summary>
+        /// 创建聊天
+        /// </summary>
+        CreateChat = 1,
+
+        /// <summary>
+        /// 发送消息
+        /// </summary>
+        SendMessage = 2,
+
+        /// <summary>
+        /// 接收消息
+        /// </summary>
+        ReceiveMessage = 3,
+
+        /// <summary>
+        /// 用户聊天列表
+        /// </summary>
+        UserChatList = 4,
+
+        /// <summary>
+        /// 聊天记录
+        /// </summary>
+        ChatHistory = 5,
+
+        /// <summary>
+        /// 已读
+        /// </summary>
+        Read = 6,
+
+        /// <summary>
+        /// 撤回
+        /// </summary>
+        Withdraw = 7,
+
+        /// <summary>
+        /// 置顶
+        /// </summary>
+        TopChat = 8,
+
+        /// <summary>
+        /// 隐藏聊天
+        /// </summary>
+        HiddenChat = 9,
+
+        /// <summary>
+        /// 免打扰聊天
+        /// </summary>
+        MuteChat = 10,
+
+        /// <summary>
+        /// 系统通知
+        /// </summary>
+        SystemNotice = 11,
+
+        /// <summary>
+        /// 用户的商品
+        /// </summary>
+        ChatUserGoods = 12,
+
+        /// <summary>
+        /// 用户的订单
+        /// </summary>
+        ChatUserOrder = 13,
+    }
+}

+ 15 - 0
JiaZhiQuan.Common/IoC/AutofacInjection.cs

@@ -0,0 +1,15 @@
+using Autofac;
+using JiaZhiQuan.Common.Config;
+
+namespace JiaZhiQuan.Common.IoC
+{
+    public static class AutofacInjection
+    {
+        public static void RegisterCommon(this ContainerBuilder containerBuilder)
+        {
+            containerBuilder.RegisterAssemblyTypes(typeof(AutofacInjection).Assembly).AsImplementedInterfaces();
+
+            containerBuilder.RegisterModule<CommonModule>();
+        }
+    }
+}

+ 30 - 0
JiaZhiQuan.Common/IoC/CommonModule.cs

@@ -0,0 +1,30 @@
+using Autofac;
+using JiaZhiQuan.Common.Config;
+using JiaZhiQuan.Common.Messaging;
+using JiaZhiQuan.Common.Region;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.IoC
+{
+    public class CommonModule : Module
+    {
+        protected override void Load(ContainerBuilder builder)
+        {
+            if (!ConfigFromDbConfig.GetFromConfig().Disabled)
+            {
+                builder.RegisterType<ConfigRefreshScheduleService>().AsSelf().SingleInstance();
+            }
+            if (!string.IsNullOrEmpty(KafkaClientConfig.GetFromConfig().BootstrapServers))
+            {
+                builder.RegisterType<Producer>().AsSelf().SingleInstance();
+            }
+            
+            builder.RegisterType<ConfigFromDb>().AsSelf().SingleInstance();
+            builder.RegisterType<RegionHelper>().AsSelf().SingleInstance();
+
+            base.Load(builder);
+        }
+    }
+}

+ 35 - 0
JiaZhiQuan.Common/JiaZhiQuan.Common.csproj

@@ -0,0 +1,35 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <OutputType>Library</OutputType>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="aliyun-net-sdk-core" Version="1.5.11" />
+    <PackageReference Include="aliyun-net-sdk-vod" Version="2.16.10" />
+    <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
+    <PackageReference Include="Confluent.Kafka" Version="2.0.2" />
+    <PackageReference Include="Elasticsearch.Net" Version="7.17.0" />
+    <PackageReference Include="MailKit" Version="3.1.1" />
+    <PackageReference Include="Mapster" Version="7.3.0" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
+    <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
+    <PackageReference Include="NPOI" Version="2.6.2" />
+    <PackageReference Include="Npoi.Mapper" Version="6.1.0" />
+    <PackageReference Include="QRCoder" Version="1.4.3" />
+	<PackageReference Include="SkiaSharp" Version="2.88.3" />
+    <PackageReference Include="Senparc.Weixin.MP" Version="16.17.7" />
+    <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.3" />
+    <PackageReference Include="System.Collections" Version="4.3.0" />
+	  <PackageReference Include="System.Drawing.Common" Version="6.0.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\DbRESTFul-V3\src\Wicture.DbRESTFul\Wicture.DbRESTFul.csproj" />
+    <ProjectReference Include="..\..\..\HuiFuBasePaySDk\csharp-sdk-v1.0.13\BasePaySdk\BasePaySdk.csproj" />
+  </ItemGroup>
+
+
+</Project>

+ 63 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiChash.cs

@@ -0,0 +1,63 @@
+using BasePaySdk.Request;
+using BasePaySdk;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiChash {
+        /// <summary>
+        /// 汇付天下-提现
+        /// </summary>
+        /// <param name="huifuConf"></param>
+        /// <param name="info"></param>
+        /// <returns></returns>
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuChashInfo info) {
+            // 2.组装请求参数
+            V2TradeSettlementEnchashmentRequest request = new V2TradeSettlementEnchashmentRequest();
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 取现金额
+            request.setCashAmt(CommonUtils.DivideAndRound(info.cash_amt, 100).ToString("0.00"));
+            if (huifuConf.isDev) {
+                request.setCashAmt("0.01");//测试
+            }
+            
+            // 取现方ID号
+            request.setHuifuId(info.huifu_id);
+            // 到账日期类型
+            request.setIntoAcctDateType("T1");
+            // 取现卡序列号
+            request.setTokenNo(info.token_no);
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, info);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+        * 取现-非必填字段
+        * @return
+        */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuChashInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 账户号
+            // extendInfoMap.Add("acct_id", "");
+            // 取现渠道
+            extendInfoMap.Add("enchashment_channel", "00");
+            // 备注
+            extendInfoMap.Add("remark", JsonConvert.SerializeObject(info.Remark));
+            // 异步通知地址
+            extendInfoMap.Add("notify_url", info.notifyUrl);
+            return extendInfoMap;
+        }
+    }
+}

+ 79 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiIndv.cs

@@ -0,0 +1,79 @@
+using BasePaySdk.Request;
+using BasePaySdk;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using Newtonsoft.Json.Linq;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiIndv {
+        //基本开户
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuIndvInfo info) {
+            // 2.组装请求参数
+            V2UserBasicdataIndvRequest request = new V2UserBasicdataIndvRequest();
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 个人姓名
+            request.setName(info.name);
+            // 个人证件类型
+            request.setCertType("00");
+            // 个人证件号码
+            request.setCertNo(info.cert_no);
+            // 个人证件有效期类型
+            request.setCertValidityType(info.cert_validity_type);
+            // 个人证件有效期开始日期
+            request.setCertBeginDate(info.cert_begin_date);
+            // 手机号
+            request.setMobileNo(info.mobile_no);
+            // 地址开通中信E管家必填
+            // request.setAddress("test");
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, info);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuIndvInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 个人证件有效期截止日期
+            //extendInfoMap.Add("cert_end_date", info.cert_end_date);
+            // 电子邮箱
+            //extendInfoMap.Add("email", "jeff.peng@huifu.com");
+            // 管理员账号
+            //extendInfoMap.Add("login_name", "Lg2022022201394910571");
+            // 是否发送短信标识
+            //extendInfoMap.Add("sms_send_flag", "1");
+            // 拓展方字段
+            //extendInfoMap.Add("expand_id", "");
+            // 文件列表
+            //extendInfoMap.Add("file_list", getFileList());
+            return extendInfoMap;
+        }
+
+        private static string getFileList() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 文件类型
+            obj.Add("file_type", "F04");
+            // 文件jfileID
+            obj.Add("file_id", "2022022201394949297117211");
+            // 文件名称
+            obj.Add("file_name", "企业营业执照1.jpg");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+    }
+}

+ 418 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiJspay.cs

@@ -0,0 +1,418 @@
+using BasePaySdk;
+using BasePaySdk.Request;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using static JiaZhiQuan.Common.Models.CommonConst;
+using Newtonsoft.Json.Linq;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiJspay {
+        /// <summary>
+        /// 汇付天下-聚合支付-支付宝正扫
+        /// </summary>
+        /// <param name="huifuConf"></param>
+        /// <returns></returns>
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuPayInfo payInfo) {
+            // 
+            V2TradePaymentJspayRequest request = new V2TradePaymentJspayRequest();
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 请求流水号
+            request.setReqSeqId(payInfo.reqId);
+            // 商户号
+            request.setHuifuId(huifuConf.sys_id);
+            // 商品描述
+            request.setGoodsDesc(payInfo.title);
+            // 交易类型
+            request.setTradeType("A_NATIVE");
+            // 交易金额
+            request.setTransAmt(CommonUtils.DivideAndRound(
+                payInfo.payAmount, UNIT).ToString("0.00"));
+            if(huifuConf.isDev) {
+                request.setTransAmt("0.01");
+            }
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, payInfo);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+         * jspay-非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuPayInfo payInfo) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 账户号
+            // extendInfoMap.Add("acct_id", "");
+            // 交易有效期
+            extendInfoMap.Add("time_expire", payInfo.payExpireAt.ToString("yyyyMMddHHmmss"));
+            // 微信参数集合
+            //extendInfoMap.Add("wx_data", getWxData());
+            // 支付宝参数集合
+            //extendInfoMap.Add("alipay_data", getAlipayData(payInfo));
+            // 银联参数集合
+            //extendInfoMap.Add("unionpay_data", getUnionpayData());
+            // 数字人民币参数集合
+            // extendInfoMap.Add("dc_data", getDcData());
+            // 是否延迟交易
+            extendInfoMap.Add("delay_acct_flag", "N");
+            // 手续费扣款标志
+            // extendInfoMap.Add("fee_flag", "");
+            // 分账对象
+            //extendInfoMap.Add("acct_split_bunch", getAcctSplitBunch());
+            // 传入分账遇到优惠的处理规则
+            extendInfoMap.Add("term_div_coupon_type", "0");
+            // 补贴支付信息
+            // extendInfoMap.Add("combinedpay_data", getCombinedpayData());
+            // 禁用信用卡标记,//todo 待确认,暂啥都不禁用。
+            //extendInfoMap.Add("limit_pay_type", "NO_CREDIT");
+            // 商户贴息标记
+            extendInfoMap.Add("fq_mer_discount_flag", "N");
+            // 渠道号
+            extendInfoMap.Add("channel_no", "");
+            // 场景类型
+            extendInfoMap.Add("pay_scene", "02");
+            // 备注
+            extendInfoMap.Add("remark", JsonConvert.SerializeObject(payInfo.Remark));
+            // 安全信息
+            //extendInfoMap.Add("risk_check_data", getRiskCheckData());
+            // 设备信息
+            //extendInfoMap.Add("terminal_device_data", getTerminalDeviceData());
+            // 异步通知地址
+            extendInfoMap.Add("notify_url", payInfo.notifyUrl);
+            return extendInfoMap;
+        }
+       
+        private static object getGoodsDetailWxRucan() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商品编码
+            obj.Add("goods_id", "6934572310301");
+            // 商品名称
+            obj.Add("goods_name", "太龙双黄连口服液");
+            // 商品单价(元)
+            obj.Add("price", "43.00");
+            // 商品数量
+            obj.Add("quantity", "1");
+            // 微信侧商品编码
+            obj.Add("wxpay_goods_id", "12235413214070356458058");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static object getDetail() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 单品列表
+            obj.Add("goods_detail", getGoodsDetailWxRucan());
+            // 订单原价(元)
+            obj.Add("cost_price", "43.00");
+            // 商品小票ID
+            obj.Add("receipt_id", "20220628132043853798");
+
+            return obj;
+        }
+        private static object getStoreInfo() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 门店id
+            // obj.Add("id", "");
+            // 门店名称
+            // obj.Add("name", "");
+            // 门店行政区划码
+            // obj.Add("area_code", "");
+            // 门店详细地址
+            // obj.Add("ass", "");
+
+            return obj;
+        }
+        private static object getSceneInfo() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 门店信息
+            // obj.Add("store_info", getStoreInfo());
+
+            return obj;
+        }
+        private static string getWxData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 子商户应用ID
+            obj.Add("sub_appid", "wxdfe9a5d141f96685");
+            // 子商户用户标识
+            obj.Add("sub_openid", "o8jhotzittQSetZ-N0Yj4Hz91Rqc");
+            // 附加数据
+            // obj.Add("attach", "");
+            // 商品描述
+            // obj.Add("body", "");
+            // 商品详情
+            obj.Add("detail", getDetail());
+            // 设备号
+            // obj.Add("device_info", "");
+            // 订单优惠标记
+            // obj.Add("goods_tag", "");
+            // 实名支付
+            // obj.Add("identity", "");
+            // 开发票入口开放标识
+            // obj.Add("receipt", "");
+            // 场景信息
+            obj.Add("scene_info", getSceneInfo());
+            // 终端ip
+            // obj.Add("spbill_create_ip", "");
+            // 单品优惠标识
+            // obj.Add("promotion_flag", "");
+            // 新增商品ID
+            // obj.Add("product_id", "");
+            // 指定支付者
+            // obj.Add("limit_payer", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static object getExtendParams() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 卡类型
+            obj.Add("card_type", "");
+            // 支付宝点餐场景类型
+            obj.Add("food_order_type", "qr_order");
+            // 花呗分期数
+            obj.Add("hb_fq_num", "");
+            // 花呗卖家手续费百分比
+            obj.Add("hb_fq_seller_percent", "");
+            // 行业数据回流信息
+            obj.Add("industry_reflux_info", "string");
+            // 信用卡分期资产方式
+            // obj.Add("fq_channels", "");
+            // 停车场id
+            obj.Add("parking_id", "123wsx");
+            // 系统商编号
+            obj.Add("sys_service_provider_id", "1111111");
+
+            return obj;
+        }
+        private static object getGoodsDetail() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商品的编号
+            obj.Add("goods_id", "12312321");
+            // 商品名称
+            obj.Add("goods_name", "汇付");
+            // 商品单价(元)
+            obj.Add("price", "43.00");
+            // 商品数量
+            obj.Add("quantity", "20");
+            // 商品描述信息
+            obj.Add("body", "");
+            // 商品类目树
+            obj.Add("categories_tree", "string");
+            // 商品类目
+            obj.Add("goods_category", "");
+            // 商品的展示地址
+            obj.Add("show_url", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static object getExtUserInfo() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 姓名
+            // obj.Add("name", "");
+            // 手机号
+            // obj.Add("mobile", "");
+            // 证件类型
+            // obj.Add("cert_type", "");
+            // 证件号
+            // obj.Add("cert_no", "");
+            // 允许的最小买家年龄
+            // obj.Add("min_age", "");
+            // 是否强制校验付款人身份信息
+            // obj.Add("fix_buyer", "");
+            // 是否强制校验身份信息
+            // obj.Add("need_check_info", "");
+
+            return obj;
+        }
+        private static string getAlipayData(HuiFuPayInfo payInfo) {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 买家的支付宝唯一用户号
+            obj.Add("buyer_id", payInfo.buyerAliId);
+            // 支付宝的店铺编号
+            //obj.Add("alipay_store_id", "");
+            // 买家支付宝账号
+            //obj.Add("buyer_logon_id", "string");
+            // 业务扩展参数
+            //obj.Add("extend_params", getExtendParams());
+            // 订单包含的商品列表信息
+            //obj.Add("goods_detail", getGoodsDetail());
+            // 商户原始订单号
+            //obj.Add("merchant_order_no", "string");
+            // 商户操作员编号
+            //obj.Add("operator_id", "123213213");
+            // 销售产品码
+            //obj.Add("product_code", "string");
+            // 卖家支付宝用户号
+            //obj.Add("seller_id", "string");
+            // 商户门店编号
+            //obj.Add("store_id", "");
+            // 外部指定买家
+            // obj.Add("ext_user_info", getExtUserInfo());
+            // 订单标题
+            // obj.Add("subject", "");
+            // 商家门店名称
+            // obj.Add("store_name", "");
+            // 小程序应用的appid
+            // obj.Add("op_app_id", "");
+            // 商户业务信息
+            // obj.Add("ali_business_params", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static object getPayeeInfo() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商户类别
+            // obj.Add("mer_cat_code", "");
+            // 二级商户代码
+            // obj.Add("sub_id", "");
+            // 二级商户名称
+            // obj.Add("sub_name", "");
+            // 终端号
+            // obj.Add("term_id", "");
+
+            return obj;
+        }
+        private static string getUnionpayData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 二维码
+            // obj.Add("qr_code", "");
+            // 收款方附加数据
+            // obj.Add("addn_data", "");
+            // 地区信息
+            // obj.Add("area_info", "");
+            // 持卡人ip
+            // obj.Add("customer_ip", "");
+            // 前台通知地址
+            // obj.Add("front_url", "");
+            // 订单描述
+            // obj.Add("order_desc", "");
+            // 收款方附言
+            // obj.Add("payee_comments", "");
+            // 收款方信息
+            // obj.Add("payee_info", getPayeeInfo());
+            // 银联分配的服务商机构标识码
+            // obj.Add("pnr_ins_id_cd", "");
+            // 请求方自定义域
+            // obj.Add("req_reserved", "");
+            // 终端信息
+            // obj.Add("term_info", "");
+            // 银联用户标识
+            // obj.Add("user_id", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getDcData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 数字货币银行编号
+            // obj.Add("digital_bank_no", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static object getAcctInfosRucan() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账接收方ID
+            obj.Add("huifu_id", "6666000109133323");
+            // 分账金额
+            obj.Add("div_amt", "0.10");
+            // 账户号
+            // obj.Add("acct_id", "");
+            // 分账百分比%
+            // obj.Add("percentage_div", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static string getAcctSplitBunch() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账明细
+            obj.Add("acct_infos", getAcctInfosRucan());
+            // 百分比分账标志
+            // obj.Add("percentage_flag", "");
+            // 是否净值分账
+            // obj.Add("is_clean_split", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCombinedpayData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 补贴方汇付商户号
+            // obj.Add("huifu_id", "test");
+            // 补贴方类型
+            // obj.Add("user_type", "test");
+            // 补贴方账户号
+            // obj.Add("acct_id", "test");
+            // 补贴金额
+            // obj.Add("amount", "test");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getRiskCheckData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // ip地址
+            obj.Add("ip_addr", "180.167.105.130");
+            // 基站地址
+            obj.Add("base_station", "192.168.1.1");
+            // 纬度
+            obj.Add("latitude", "33.3");
+            // 经度
+            obj.Add("longitude", "33.3");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getTerminalDeviceData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商户设备类型
+            // obj.Add("mer_device_type", "test");
+            // 汇付机具号
+            obj.Add("devs_id", "SPINTP357338300264411");
+            // 设备类型
+            obj.Add("device_type", "1");
+            // 交易设备IP
+            obj.Add("device_ip", "10.10.0.1");
+            // 交易设备MAC
+            obj.Add("device_mac", "");
+            // 交易设备IMEI
+            obj.Add("device_imei", "");
+            // 交易设备IMSI
+            obj.Add("device_imsi", "");
+            // 交易设备ICCID
+            obj.Add("device_icc_id", "");
+            // 交易设备WIFIMAC
+            obj.Add("device_wifi_mac", "");
+            // 交易设备GPS
+            obj.Add("device_gps", "192.168.0.0");
+            // 商户终端应用程序版本
+            // obj.Add("app_version", "");
+            // SIM 卡卡号
+            // obj.Add("icc_id", "");
+            // 商户终端实时经纬度信息
+            // obj.Add("location", "");
+            // 商户交易设备IP
+            // obj.Add("mer_device_ip", "");
+            // 移动国家代码
+            // obj.Add("mobile_country_cd", "");
+            // 移动网络号码
+            // obj.Add("mobile_net_num", "");
+            // 商户终端入网认证编号
+            // obj.Add("network_license", "");
+            // 商户终端序列号
+            // obj.Add("serial_num", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+    }
+}

+ 224 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiOpen.cs

@@ -0,0 +1,224 @@
+using BasePaySdk.Request;
+using BasePaySdk;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using Newtonsoft.Json.Linq;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiOpen {
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuOpenInfo info) {
+            // 2.组装请求参数
+            V2UserBusiOpenRequest request = new V2UserBusiOpenRequest();
+            // 汇付ID
+            request.setHuifuId(info.huifu_id);
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 渠道商/商户汇付Id
+            request.setUpperHuifuId(huifuConf.sys_id);
+            // 乐接活配置当合作平台为乐接活,必填
+            // request.setLjhData(getLjhData());
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, info);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuOpenInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 结算信息配置
+            //extendInfoMap.Add("settle_config", getSettleConfig());
+            // 结算卡信息
+            extendInfoMap.Add("card_info", getCardInfo(info));
+            // 取现配置列表
+            extendInfoMap.Add("cash_config", getCashConfig());
+            // 文件列表
+            //extendInfoMap.Add("file_list", getFileList());
+            // 延迟入账开关
+            // extendInfoMap.Add("delay_flag", "");
+            // 斗拱e账户功能配置
+            // extendInfoMap.Add("elec_acct_config", getElecAcctConfig());
+            // 灵活用工开关
+            // extendInfoMap.Add("open_tax_flag", "");
+            // 异步请求地址
+            extendInfoMap.Add("async_return_url", info.notifyUrl);
+            // 合作平台
+            // extendInfoMap.Add("lg_platform_type", "");
+            return extendInfoMap;
+        }
+
+        private static string getSettleConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 结算周期
+            obj.Add("settle_cycle", "D1");
+            // 结算手续费外扣时的汇付ID外扣手续费承担方的汇付ID。外扣时必填;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:6666000123123123&lt;/font&gt;
+            obj.Add("out_settle_huifuid", "");
+            // 结算手续费外扣时的账户类型外扣手续费账户类型; 01:基本户(为空时默认值), 05:充值户;外扣时必填;&lt;br/&gt;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:01&lt;/font&gt;
+            obj.Add("out_settle_acct_type", "");
+            // 结算批次号settle_pattern为P0时必填;[参见结算批次说明](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_jspc)
+            obj.Add("settle_batch_no", "300");
+            // 是否优先到账settle_pattern为P0时选填, Y:是 N:否(为空默认取值);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:Y&lt;/font&gt;
+            obj.Add("is_priority_receipt", "");
+            // 自定义结算处理时间settle_pattern为P1/P2时必填,注意:00:00到00:30不能指定;格式:HHmmss;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:103000&lt;/font&gt;
+            obj.Add("settle_time", "");
+            // 节假日结算手续费率settle_cycle为D1时必填。单位%,需保留小数点后两位。取值范围[0.00,100.00],不收费请填写0.00;settle_cycle&#x3D;T1时,不生效 ;settle_cycle为D1时,遇节假日按此费率结算 ;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;
+            obj.Add("fixed_ratio", "2");
+            // 起结金额
+            obj.Add("min_amt", "0.01");
+            // 留存金额
+            obj.Add("remained_amt", "10.00");
+            // 结算摘要
+            obj.Add("settle_abstract", "结算摘要");
+            // 手续费外扣标记
+            obj.Add("out_settle_flag", "2");
+            // 结算方式
+            obj.Add("settle_pattern", "");
+            // 工作日结算手续费率
+            // obj.Add("workday_fixed_ratio", "");
+            // 工作日结算手续费固定金额
+            // obj.Add("workday_constant_amt", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCardInfo(HuiFuOpenInfo info) {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 卡类型,个人用户,1 对私
+            obj.Add("card_type", "1");
+            // 卡户名
+            obj.Add("card_name", info.card_info.card_name);
+            // 卡号
+            obj.Add("card_no", info.card_info.card_no);
+            // 银行所在省
+            obj.Add("prov_id", info.card_info.prov_id);
+            // 银行所在市
+            obj.Add("area_id", info.card_info.area_id);
+            //// 银行号当card_type&#x3D;0时必填,对私可以为空[点击查看](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_yhbm);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:01040000&lt;/font&gt;
+            //obj.Add("bank_code", "01050000");
+            //// 支行联行号当card_type&#x3D;0时必填,[点击查看](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_yhzhbm);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:103124075619&lt;/font&gt;
+            //obj.Add("branch_code", "105305264815");
+            // 持卡人证件类型对私必填;参见《[自然人证件类型](https://paas.huifu.com/open/doc/api/#/api_ggcsbm?id&#x3D;%e8%87%aa%e7%84%b6%e4%ba%ba%e8%af%81%e4%bb%b6%e7%b1%bb%e5%9e%8b)》说明;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:00&lt;/font&gt;
+            obj.Add("cert_type", "00");
+            // 持卡人证件号码对私必填; 如:证件类型为身份证, 则填写身份证号码;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:320926198412032059&lt;/font&gt;
+            obj.Add("cert_no", info.card_info.cert_no);
+            // 持卡人证件有效期类型对私必填;1:长期有效;0:非长期有效;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0&lt;/font&gt;
+            obj.Add("cert_validity_type", info.card_info.cert_validity_type);
+            // 持卡人证件有效期(起始)对私必填;日期格式:yyyyMMdd,&lt;font color&#x3D;&quot;green&quot;&gt;示例值:20110112&lt;/font&gt;
+            obj.Add("cert_begin_date", info.card_info.cert_begin_date);
+            // 持卡人证件有效期(截止)当cert_validity_type&#x3D;0时必须填写;日期格式yyyyMMdd,&lt;font color&#x3D;&quot;green&quot;&gt;示例值:20110112&lt;/font&gt;&lt;br/&gt;当cert_validity_type&#x3D;1可不填
+            obj.Add("cert_end_date", info.card_info.cert_end_date);
+            // 银行卡绑定手机号
+            //obj.Add("mp", "15556622368");
+            // 默认结算卡标志 是否为默认结算卡标志;Y:是 N:否(为空默认)
+            obj.Add("is_settle_default", "Y");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCashConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 提现手续费(固定/元)fix_amt与fee_rate至少填写一项, 需保留小数点后两位,不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:1.00&lt;/font&gt;注:当cash_type&#x3D;D1时为节假日取现手续费
+            obj.Add("fix_amt", "0.00");
+            // 提现手续费率(%)fix_amt与fee_rate至少填写一项,需保留小数点后两位,取值范围[0.00,100.00],不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;注:1、如果fix_amt与fee_rate都填写了则手续费&#x3D;fix_amt+支付金额\*fee_rate2、当cash_type&#x3D;D1时为节假日取现手续费
+            obj.Add("fee_rate", "0.00");
+            // D1工作日取现手续费固定金额单位元,需保留小数点后两位。不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:1.00&lt;/font&gt;D1取现配置时选填,其他取现配置无效;cash_type取现类型为D1时,遇工作日按此费率结算,若未配置则默认按照节假日手续费计算
+            // obj.Add("weekday_fix_amt", "test");
+            // D1工作日取现手续费率单位%,需保留小数点后两位。取值范围[0.00,100.00],不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;D1取现配置时选填,其他取现配置无效;cash_type取现类型为D1时,遇工作日按此费率结算 ,若未配置则默认按照节假日手续费计算
+            // obj.Add("weekday_fee_rate", "test");
+            // 业务类型
+            obj.Add("cash_type", "T1");
+            // 是否交易手续费外扣 1:外扣 2:内扣(默认2内扣)
+            obj.Add("out_fee_flag", "2");
+            //// 手续费承担方
+            //obj.Add("out_fee_huifu_id", "");
+            //// 交易手续费外扣的账户类型
+            //obj.Add("out_fee_acct_type", "");
+            // 是否优先到账 Y:是 ,N:否。不填,默认值为否
+            obj.Add("is_priority_receipt", "Y");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getFileList() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 文件类型
+            obj.Add("file_type", "F02");
+            // 文件jfileID
+            obj.Add("file_id", "71da066c-5d15-3658-a86d-4e85ee67808a");
+            // 文件名称
+            obj.Add("file_name", "企业营业执照1.jpg");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getElecCardList() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 银行编码
+            // obj.Add("bank_code", "test");
+            // 支行联行号
+            // obj.Add("branch_code", "test");
+            // 支行名称
+            // obj.Add("branch_name", "test");
+            // 结算账户名
+            // obj.Add("card_name", "test");
+            // 银行卡号
+            // obj.Add("card_no", "test");
+            // 卡类型
+            // obj.Add("card_type", "test");
+            // 银行所在省
+            // obj.Add("prov_id", "");
+            // 银行所在市
+            // obj.Add("area_id", "");
+            // 银行绑定手机号
+            // obj.Add("mp", "");
+            // 默认卡标识
+            // obj.Add("default_cash_flag", "");
+            // 用户授权协议版本号
+            // obj.Add("auth_version", "");
+            // 用户授权协议号
+            // obj.Add("auth_no", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getElecAcctConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 电子账户开关
+            // obj.Add("switch_state", "test");
+            // 账户类型
+            // obj.Add("acct_type", "test");
+            // 电子账户提现手续费承担方
+            // obj.Add("cash_fee_party", "test");
+            // 场景
+            // obj.Add("scene", "test");
+            // 角色类型(角色编号)
+            // obj.Add("role_type", "test");
+            // 银行卡信息
+            // obj.Add("elec_card_list", getElecCardList());
+            // 用户类型
+            // obj.Add("user_type", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getLjhData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 税源地id当合作平台为乐接活,必填
+            // obj.Add("tax_area_id", "test");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+    }
+}

+ 222 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiOpenModify.cs

@@ -0,0 +1,222 @@
+using BasePaySdk.Request;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiOpenModify {
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuOpenModifyInfo info) {
+            // 2.组装请求参数
+            V2UserBusiModifyRequest request = new V2UserBusiModifyRequest();
+            // 汇付ID
+            request.setHuifuId(info.huifu_id);
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 渠道商/商户汇付Id
+            request.setUpperHuifuId(huifuConf.sys_id);
+            // 乐接活配置当合作平台为乐接活,必填
+            // request.setLjhData(getLjhData());
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, info);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuOpenModifyInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 结算信息配置
+            //extendInfoMap.Add("settle_config", getSettleConfig());
+            // 结算卡信息
+            extendInfoMap.Add("card_info", getCardInfo(info));
+            // 取现配置列表
+            //extendInfoMap.Add("cash_config", getCashConfig());
+            // 文件列表
+            //extendInfoMap.Add("file_list", getFileList());
+            // 延迟入账开关
+            // extendInfoMap.Add("delay_flag", "");
+            // 斗拱e账户功能配置
+            // extendInfoMap.Add("elec_acct_config", getElecAcctConfig());
+            // 灵活用工开关
+            // extendInfoMap.Add("open_tax_flag", "");
+            // 异步请求地址
+            extendInfoMap.Add("async_return_url", info.notifyUrl);
+            // 合作平台
+            // extendInfoMap.Add("lg_platform_type", "");
+            return extendInfoMap;
+        }
+
+        private static string getSettleConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 结算周期
+            obj.Add("settle_cycle", "D1");
+            // 结算手续费外扣时的汇付ID外扣手续费承担方的汇付ID。外扣时必填;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:6666000123123123&lt;/font&gt;
+            obj.Add("out_settle_huifuid", "");
+            // 结算手续费外扣时的账户类型外扣手续费账户类型; 01:基本户(为空时默认值), 05:充值户;外扣时必填;&lt;br/&gt;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:01&lt;/font&gt;
+            obj.Add("out_settle_acct_type", "");
+            // 结算批次号settle_pattern为P0时必填;[参见结算批次说明](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_jspc)
+            obj.Add("settle_batch_no", "300");
+            // 是否优先到账settle_pattern为P0时选填, Y:是 N:否(为空默认取值);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:Y&lt;/font&gt;
+            obj.Add("is_priority_receipt", "");
+            // 自定义结算处理时间settle_pattern为P1/P2时必填,注意:00:00到00:30不能指定;格式:HHmmss;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:103000&lt;/font&gt;
+            obj.Add("settle_time", "");
+            // 节假日结算手续费率settle_cycle为D1时必填。单位%,需保留小数点后两位。取值范围[0.00,100.00],不收费请填写0.00;settle_cycle&#x3D;T1时,不生效 ;settle_cycle为D1时,遇节假日按此费率结算 ;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;
+            obj.Add("fixed_ratio", "2");
+            // 起结金额
+            obj.Add("min_amt", "0.01");
+            // 留存金额
+            obj.Add("remained_amt", "10.00");
+            // 结算摘要
+            obj.Add("settle_abstract", "结算摘要");
+            // 手续费外扣标记
+            obj.Add("out_settle_flag", "2");
+            // 结算方式
+            obj.Add("settle_pattern", "");
+            // 工作日结算手续费率
+            // obj.Add("workday_fixed_ratio", "");
+            // 工作日结算手续费固定金额
+            // obj.Add("workday_constant_amt", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCardInfo(HuiFuOpenInfo info) {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 卡类型,个人用户,1 对私
+            obj.Add("card_type", "1");
+            // 卡户名
+            obj.Add("card_name", info.card_info.card_name);
+            // 卡号
+            obj.Add("card_no", info.card_info.card_no);
+            // 银行所在省
+            obj.Add("prov_id", info.card_info.prov_id);
+            // 银行所在市
+            obj.Add("area_id", info.card_info.area_id);
+            //// 银行号当card_type&#x3D;0时必填,对私可以为空[点击查看](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_yhbm);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:01040000&lt;/font&gt;
+            //obj.Add("bank_code", "01050000");
+            //// 支行联行号当card_type&#x3D;0时必填,[点击查看](https://paas.huifu.com/open/doc/api/#/csfl/api_csfl_yhzhbm);&lt;font color&#x3D;&quot;green&quot;&gt;示例值:103124075619&lt;/font&gt;
+            //obj.Add("branch_code", "105305264815");
+            // 持卡人证件类型对私必填;参见《[自然人证件类型](https://paas.huifu.com/open/doc/api/#/api_ggcsbm?id&#x3D;%e8%87%aa%e7%84%b6%e4%ba%ba%e8%af%81%e4%bb%b6%e7%b1%bb%e5%9e%8b)》说明;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:00&lt;/font&gt;
+            obj.Add("cert_type", "00");
+            // 持卡人证件号码对私必填; 如:证件类型为身份证, 则填写身份证号码;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:320926198412032059&lt;/font&gt;
+            obj.Add("cert_no", info.card_info.cert_no);
+            // 持卡人证件有效期类型对私必填;1:长期有效;0:非长期有效;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0&lt;/font&gt;
+            obj.Add("cert_validity_type", info.card_info.cert_validity_type);
+            // 持卡人证件有效期(起始)对私必填;日期格式:yyyyMMdd,&lt;font color&#x3D;&quot;green&quot;&gt;示例值:20110112&lt;/font&gt;
+            obj.Add("cert_begin_date", info.card_info.cert_begin_date);
+            // 持卡人证件有效期(截止)当cert_validity_type&#x3D;0时必须填写;日期格式yyyyMMdd,&lt;font color&#x3D;&quot;green&quot;&gt;示例值:20110112&lt;/font&gt;&lt;br/&gt;当cert_validity_type&#x3D;1可不填
+            obj.Add("cert_end_date", info.card_info.cert_end_date);
+            // 银行卡绑定手机号
+            //obj.Add("mp", "15556622368");
+            // 默认结算卡标志
+            // obj.Add("is_settle_default", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCashConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 提现手续费(固定/元)fix_amt与fee_rate至少填写一项, 需保留小数点后两位,不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:1.00&lt;/font&gt;注:当cash_type&#x3D;D1时为节假日取现手续费
+            obj.Add("fix_amt", "0.03");
+            // 提现手续费率(%)fix_amt与fee_rate至少填写一项,需保留小数点后两位,取值范围[0.00,100.00],不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;注:1、如果fix_amt与fee_rate都填写了则手续费&#x3D;fix_amt+支付金额\*fee_rate2、当cash_type&#x3D;D1时为节假日取现手续费
+            obj.Add("fee_rate", "2");
+            // D1工作日取现手续费固定金额单位元,需保留小数点后两位。不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:1.00&lt;/font&gt;D1取现配置时选填,其他取现配置无效;cash_type取现类型为D1时,遇工作日按此费率结算,若未配置则默认按照节假日手续费计算
+            // obj.Add("weekday_fix_amt", "test");
+            // D1工作日取现手续费率单位%,需保留小数点后两位。取值范围[0.00,100.00],不收费请填写0.00;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:0.05&lt;/font&gt;D1取现配置时选填,其他取现配置无效;cash_type取现类型为D1时,遇工作日按此费率结算 ,若未配置则默认按照节假日手续费计算
+            // obj.Add("weekday_fee_rate", "test");
+            // 业务类型
+            obj.Add("cash_type", "D1");
+            // 是否交易手续费外扣
+            obj.Add("out_fee_flag", "");
+            // 手续费承担方
+            obj.Add("out_fee_huifu_id", "");
+            // 交易手续费外扣的账户类型
+            obj.Add("out_fee_acct_type", "");
+            // 是否优先到账
+            // obj.Add("is_priority_receipt", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getFileList() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 文件类型
+            obj.Add("file_type", "F02");
+            // 文件jfileID
+            obj.Add("file_id", "71da066c-5d15-3658-a86d-4e85ee67808a");
+            // 文件名称
+            obj.Add("file_name", "企业营业执照1.jpg");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getElecCardList() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 银行编码
+            // obj.Add("bank_code", "test");
+            // 支行联行号
+            // obj.Add("branch_code", "test");
+            // 支行名称
+            // obj.Add("branch_name", "test");
+            // 结算账户名
+            // obj.Add("card_name", "test");
+            // 银行卡号
+            // obj.Add("card_no", "test");
+            // 卡类型
+            // obj.Add("card_type", "test");
+            // 银行所在省
+            // obj.Add("prov_id", "");
+            // 银行所在市
+            // obj.Add("area_id", "");
+            // 银行绑定手机号
+            // obj.Add("mp", "");
+            // 默认卡标识
+            // obj.Add("default_cash_flag", "");
+            // 用户授权协议版本号
+            // obj.Add("auth_version", "");
+            // 用户授权协议号
+            // obj.Add("auth_no", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getElecAcctConfig() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 电子账户开关
+            // obj.Add("switch_state", "test");
+            // 账户类型
+            // obj.Add("acct_type", "test");
+            // 电子账户提现手续费承担方
+            // obj.Add("cash_fee_party", "test");
+            // 场景
+            // obj.Add("scene", "test");
+            // 角色类型(角色编号)
+            // obj.Add("role_type", "test");
+            // 银行卡信息
+            // obj.Add("elec_card_list", getElecCardList());
+            // 用户类型
+            // obj.Add("user_type", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getLjhData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 税源地id当合作平台为乐接活,必填
+            // obj.Add("tax_area_id", "test");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+    }
+}

+ 192 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiRefund.cs

@@ -0,0 +1,192 @@
+using BasePaySdk.Request;
+using BasePaySdk;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json.Linq;
+using static JiaZhiQuan.Common.Models.CommonConst;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiRefund {
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuRefundInfo info) {
+            // 2.组装请求参数
+            V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 商户号
+            request.setHuifuId(huifuConf.sys_id);
+            // 申请退款金额
+            request.setOrdAmt(CommonUtils.DivideAndRound(info.ord_amt, UNIT).ToString("0.00"));
+            if (huifuConf.isDev) {
+                request.setOrdAmt("0.01");//测试
+            }
+            
+            // 原交易请求日期
+            request.setOrgReqDate(info.org_req_date);
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(huifuConf, info);
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuCommonConfig huifuConf,
+            HuiFuRefundInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // 原交易全局流水号
+            //extendInfoMap.Add("org_hf_seq_id", "002900TOP3B221107142320P992ac139c0c00000");
+            // 原交易微信支付宝的商户单号
+            // extendInfoMap.Add("org_party_order_id", "");
+            // 原交易请求流水号
+             extendInfoMap.Add("org_req_seq_id", info.org_req_seq_id);
+            // 分账对象
+            // extendInfoMap.Add("acct_split_bunch", getAcctSplitBunchRucan());
+            // 聚合正扫微信拓展参数集合
+            // extendInfoMap.Add("wx_data", getWxData());
+            // 数字货币扩展参数集合
+            // extendInfoMap.Add("digital_currency_data", getDigitalCurrencyData());
+            // 补贴支付信息
+            // extendInfoMap.Add("combinedpay_data", getCombinedpayData());
+            // 备注
+             //extendInfoMap.Add("remark", JsonConvert.SerializeObject(info.Remark));
+            // 是否垫资退款
+            // extendInfoMap.Add("loan_flag", "");
+            // 垫资承担者
+            // extendInfoMap.Add("loan_undertaker", "");
+            // 垫资账户类型
+            // extendInfoMap.Add("loan_acct_type", "");
+            // 安全信息
+            // extendInfoMap.Add("risk_check_data", getRiskCheckData());
+            // 设备信息
+            // extendInfoMap.Add("terminal_device_data", getTerminalDeviceData());
+            // 异步通知地址
+            extendInfoMap.Add("notify_url", info.notifyUrl);
+            // 银联参数集合
+            // extendInfoMap.Add("unionpay_data", getUnionpayData());
+            return extendInfoMap;
+        }
+
+        private static object getAcctInfosRucan() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账金额
+            // obj.Add("div_amt", "test");
+            // 分账接收方ID
+            // obj.Add("huifu_id", "test");
+            // 垫资金额
+            // obj.Add("part_loan_amt", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static string getAcctSplitBunchRucan() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账信息列表
+            // obj.Add("acct_infos", getAcctInfosRucan());
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static object getGoodsDetail() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商品编码
+            // obj.Add("goods_id", "test");
+            // 优惠退款金额
+            // obj.Add("refund_amount", "test");
+            // 商品退货数量
+            // obj.Add("refund_quantity", "test");
+            // 商品单价
+            // obj.Add("price", "test");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static object getDetail() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 商品详情列表
+            // obj.Add("goods_detail", getGoodsDetail());
+
+            return obj;
+        }
+        private static object getWxData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 退款商品详情
+            // obj.Add("detail", getDetail());
+
+            return obj;
+        }
+        private static string getDigitalCurrencyData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 退款原因
+            // obj.Add("refund_desc", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getCombinedpayData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 补贴方汇付编号
+            // obj.Add("huifu_id", "test");
+            // 补贴方类型
+            // obj.Add("user_type", "test");
+            // 补贴方账户号
+            // obj.Add("acct_id", "test");
+            // 补贴金额
+            // obj.Add("amount", "test");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return JsonConvert.SerializeObject(objList);
+        }
+        private static string getRiskCheckData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // ip地址
+            // obj.Add("ip_addr", "");
+            // 基站地址
+            // obj.Add("base_station", "");
+            // 纬度
+            // obj.Add("latitude", "");
+            // 经度
+            // obj.Add("longitude", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getTerminalDeviceData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 设备类型
+            // obj.Add("device_type", "");
+            // 交易设备IP
+            // obj.Add("device_ip", "");
+            // 交易设备MAC
+            // obj.Add("device_mac", "");
+            // 交易设备IMEI
+            // obj.Add("device_imei", "");
+            // 交易设备IMSI
+            // obj.Add("device_imsi", "");
+            // 交易设备ICCID
+            // obj.Add("device_icc_id", "");
+            // 交易设备WIFIMAC
+            // obj.Add("device_wifi_mac", "");
+            // 交易设备GPS
+            // obj.Add("device_gps", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getUnionpayData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 收款方附加数据
+            // obj.Add("addn_data", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+    }
+}

+ 43 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiRefundQuery.cs

@@ -0,0 +1,43 @@
+using BasePaySdk.Request;
+using BasePaySdk;
+using JiaZhiQuan.Common.Config;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System;
+using Wicture.DbRESTFul;
+using NPOI.Util;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiRefundQuery {
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuRefundQueryInfo info) {
+            // 2.组装请求参数
+            V2TradePaymentScanpayRefundqueryRequest request = new V2TradePaymentScanpayRefundqueryRequest();
+            // 商户号
+            request.setHuifuId(huifuConf.sys_id);
+            // 退款请求日期
+            request.setOrgReqDate(info.org_req_date);
+            // 退款全局流水号退款请求流水号,退款全局流水号,终端订单号三选一不能都为空;
+            request.setOrgHfSeqId("");
+            // 退款请求流水号退款请求流水号,退款全局流水号,终端订单号三选一不能都为空;
+            request.setOrgReqSeqId(info.org_req_seq_id);
+            // 终端订单号退款请求流水号,退款全局流水号,终端订单号三选一不能都为空;
+            // &lt;br/&gt;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:16672670833524393&lt;/font&gt;
+            request.setMerOrdId("");
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos();
+            request.setExtendInfo(extendInfoMap);
+            return request;
+        }
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos() {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            return extendInfoMap;
+        }
+    }
+}

+ 130 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuApiYuEPay.cs

@@ -0,0 +1,130 @@
+using BasePaySdk.Request;
+using JiaZhiQuan.Common.Config;
+using System.Collections.Generic;
+using System;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
+using NPOI.Util;
+using static JiaZhiQuan.Common.Models.CommonConst;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public class HuiFuApiYuEPay {
+        public static BaseRequest InitReq(HuiFuCommonConfig huifuConf,
+            HuiFuYuEPayInfo info) {
+            // 2.组装请求参数
+            V2TradeAcctpaymentPayRequest request = new V2TradeAcctpaymentPayRequest();
+            // 请求流水号
+            request.setReqSeqId(info.reqId);
+            // 请求日期
+            request.setReqDate(DateTime.Now.ToString("yyyyMMdd"));
+            // 出款方商户号
+            request.setOutHuifuId(info.out_huifu_id);
+            // 支付金额
+            request.setOrdAmt(CommonUtils.DivideAndRound(info.ord_amt, UNIT).ToString("0.00"));
+            if (huifuConf.isDev) {
+                request.setOrdAmt("0.01");
+            }
+            // 分账对象
+            request.setAcctSplitBunch(getAcctSplitBunch(info, request));
+            // 安全信息
+            request.setRiskCheckData(getRiskCheckData());
+            // 资金类型资金类型。支付渠道为中信E管家时,资金类型必填([详见说明](https://paas.huifu.com/open/doc/api/#/yuer/api_zxegjzllx))
+            // request.setFundType("test");
+            // 手续费承担方标识余额支付手续费承担方标识;商户余额支付扣收规则为接口指定承担方时必填!枚举值:&lt;br/&gt;OUT:出款方;&lt;br/&gt;IN:分账接受方。&lt;br/&gt;&lt;font color&#x3D;&quot;green&quot;&gt;示例值:IN&lt;/font&gt;
+             request.setTransFeeTakeFlag("OUT");
+
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = getExtendInfos(info);
+            request.setExtendInfo(extendInfoMap);
+
+            return request;
+        }
+
+        /**
+         * 非必填字段
+         * @return
+         */
+        private static Dictionary<string, object> getExtendInfos(HuiFuYuEPayInfo info) {
+            // 设置非必填字段
+            Dictionary<string, object> extendInfoMap = new Dictionary<string, object>();
+            // ~~发起方商户号~~
+            // extendInfoMap.Add("~~huifu_id~~", "");
+            // 商品描述
+            // extendInfoMap.Add("good_desc", "");
+            // 备注
+            // extendInfoMap.Add("remark", "");
+            // 是否延迟交易
+             extendInfoMap.Add("delay_acct_flag", "N");
+            // 出款方账户号
+             //extendInfoMap.Add("out_acct_id", "");
+            // 支付渠道
+            // extendInfoMap.Add("acct_channel", "");
+            // 灵活用工标志
+            // extendInfoMap.Add("hyc_flag", "");
+            // 灵活用工平台
+            // extendInfoMap.Add("lg_platform_type", "");
+            // 代发模式
+            // extendInfoMap.Add("salary_modle_type", "");
+            // 落地公司商户号
+            // extendInfoMap.Add("bmember_id", "");
+            // 乐接活请求参数集合
+            // extendInfoMap.Add("ljh_data", getLjhData());
+            // 异步通知地址
+            extendInfoMap.Add("notify_url", info.notifyUrl);
+            return extendInfoMap;
+        }
+
+        private static object getAcctInfos(HuiFuYuEPayInfo info, V2TradeAcctpaymentPayRequest request) {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账接收方ID
+            obj.Add("huifu_id", info.huifu_id);
+            // 分账金额
+            obj.Add("div_amt", request.getOrdAmt());
+            // 账户号
+            // obj.Add("acct_id", "");
+            // 分账百分比%
+            // obj.Add("percentage_div", "");
+
+            JArray objList = new JArray();
+            objList.Add(JToken.FromObject(obj));
+            return objList;
+        }
+        private static string getAcctSplitBunch(HuiFuYuEPayInfo info, V2TradeAcctpaymentPayRequest request) {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 分账明细
+            obj.Add("acct_infos", getAcctInfos(info, request));
+            // 百分比分账标志
+            // obj.Add("percentage_flag", "");
+            // 是否净值分账
+            // obj.Add("is_clean_split", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getRiskCheckData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 转账原因
+            obj.Add("transfer_type", "03");
+            // 产品子类
+            //obj.Add("sub_product", "1");
+            // 纬度
+            // obj.Add("latitude", "");
+            // 经度
+            // obj.Add("longitude", "");
+            // 基站地址
+            // obj.Add("base_station", "");
+            // IP地址
+            // obj.Add("ip_addr", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+        private static string getLjhData() {
+            Dictionary<string, object> obj = new Dictionary<string, object>();
+            // 税源地ID
+            // obj.Add("tax_area_id", "");
+            // 任务模板ID
+            // obj.Add("template_id", "");
+
+            return JsonConvert.SerializeObject(obj);
+        }
+    }
+}

+ 16 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuEnums.cs

@@ -0,0 +1,16 @@
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    /// <summary>
+    /// 请求类型(1,聚合正扫,2,用户开户3,用户入驻4,用户提现5,取消订单退款6,取消订单退款查询)
+    /// </summary>
+    public enum HuiFuReqTypeEnums {
+        None = 0,
+        Jspay=1,
+        Indv=2,
+        Open=3,
+        Chash=4,
+        Refund=5,
+        RefundQuery=6,
+        OpenModify=7,
+        YuEPay=8//余额支付
+    }
+}

+ 2854 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuModel.cs

@@ -0,0 +1,2854 @@
+using Senparc.Weixin.MP.AdvancedAPIs.Card;
+using System;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+
+    #region 公共参数
+    /// <summary>
+    /// 汇付支付发起信息-
+    /// </summary>
+    public class HuiFuJspayReq<T> {
+        /// <summary>
+        /// 系统号
+        /// </summary>
+        /// <remarks>
+        /// 渠道商/商户的huifu_id。
+        /// <list type="bullet">
+        /// <item><description>当主体为渠道商时,此字段填写渠道商huifu_id;</description></item>
+        /// <item><description>当主体为直连商户时,此字段填写商户huifu_id。</description></item>
+        /// </list>
+        /// 示例值:6666000123120000
+        /// 非空
+        /// </remarks>
+        public string sys_id { get; set; }
+
+        /// <summary>
+        /// 产品号
+        /// </summary>
+        /// <remarks>
+        /// 汇付分配的产品号,示例值:MCS
+        /// 非空
+        /// </remarks>
+        public string product_id { get; set; }
+
+        /// <summary>
+        /// 加签结果
+        /// </summary>
+        /// <remarks>
+        /// 接口加签验签说明
+        /// 非空
+        /// </remarks>
+        public string sign { get; set; }
+
+        /// <summary>
+        /// 数据
+        /// </summary>
+        /// <remarks>
+        /// 业务请求参数,具体值参考API文档
+        /// 非空
+        /// </remarks>
+        public T data { get; set; }
+    }
+
+    public class HuiFuResp<T> {
+        /// <summary>
+        /// 签名
+        /// </summary>
+        /// <remarks>
+        /// 接口加签验签说明
+        /// 非空
+        /// </remarks>
+        public string sign { get; set; }
+
+        /// <summary>
+        /// 响应内容体
+        /// </summary>
+        /// <remarks>
+        /// 业务返回参数
+        /// </remarks>
+        public T data { get; set; }
+    }
+    /// <summary>
+    /// 异步返回参数
+    /// </summary>
+    public class HuiFuAsyncResp<T> {
+        /// <summary>
+        /// 网关返回码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:00000000
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 网关返回信息
+        /// </summary>
+        /// <remarks>
+        /// 示例值:交易成功[000]
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 签名
+        /// </summary>
+        /// <remarks>
+        /// 接口加签验签说明
+        /// 非空
+        /// </remarks>
+        public string sign { get; set; }
+
+        /// <summary>
+        /// 返回业务数据
+        /// </summary>
+        /// <remarks>
+        /// jsonObject
+        /// 非空
+        /// </remarks>
+        public T resp_data { get; set; }
+    }
+
+    public class HuiFuReqBase {
+        public string reqId { get; set; }
+        //原始id
+        public string orgId { get; set; }
+        public string orderId { get; set; }
+        public string userId { get; set; }
+        /// <summary>
+        /// 事件类型-UEBillEventType.
+        /// </summary>
+        public int eventType { get; set; }
+        public string notifyUrl { get; set; }
+        public virtual HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.None; }
+
+        private object _remark;
+        //额外信息-对方会返回-不超过128字符
+        public object Remark {
+            get {
+                return _remark ?? new {
+                    orderId,
+                    orgId,
+                    eventType,
+                };
+            }
+            set { _remark = value; }
+        }
+             
+        public void CopyBaseInfo(HuiFuReqBase baseInfo) {
+            orgId=baseInfo.orgId;
+            eventType=baseInfo.eventType;
+            orderId = baseInfo.orderId;
+            userId = baseInfo.userId;
+        }
+    }
+
+    public class HuiFuRespBase :HuiFuReqBase {
+        /// <summary>
+        /// 请求处理结果:1成功,2失败,3处理中
+        /// </summary>
+        public int dealResult { get; set; }
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        public string hfSeqId { get; set; }
+        /// <summary>
+        /// 额外信息
+        /// </summary>
+        public object extra { get; set; }
+    }
+
+    public class HuiFuPayInfo : HuiFuReqBase {
+        //支付金额-单位分
+        public int payAmount { get; set; }
+        //支付标题
+        public string title { get; set; }
+        //付款方支付宝唯一用户号
+        public string buyerAliId { get; set; }
+        //支付超时时间
+        public DateTime payExpireAt { get; set; }
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.Jspay; }
+    }
+
+    public class HuiFuIndvInfo: HuiFuReqBase {
+        /// <summary>
+        /// 个人姓名
+        /// </summary>
+        /// <remarks>
+        /// 示例值:张三
+        /// 非空
+        /// </remarks>
+        public string name { get; set; }         
+
+        /// <summary>
+        /// 个人证件号码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:320926198312024023
+        /// 非空
+        /// </remarks>
+        public string cert_no { get; set; }
+
+        /// <summary>
+        /// 个人证件有效期类型
+        /// </summary>
+        /// <remarks>
+        /// 1:长期有效 0:非长期有效;示例值:0
+        /// 非空
+        /// </remarks>
+        public string cert_validity_type { get; set; }
+
+        /// <summary>
+        /// 个人证件有效期开始日期
+        /// </summary>
+        /// <remarks>
+        /// 日期格式:yyyyMMdd;示例值:20220909
+        /// 非空
+        /// </remarks>
+        public string cert_begin_date { get; set; }
+
+        /// <summary>
+        /// 个人证件有效期截止日期
+        /// </summary>
+        /// <remarks>
+        /// 日期格式:yyyyMMdd; 示例值:20330909 ;长期有效时可不填,非长期有效必填
+        /// </remarks>
+        public string cert_end_date { get; set; }
+
+        /// <summary>
+        /// 手机号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:13917354627
+        /// 非空
+        /// </remarks>
+        public string mobile_no { get; set; }
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.Indv; }
+    }
+    
+    public class HuiFuChashInfo : HuiFuReqBase {
+        /// <summary>
+        /// 取现金额
+        /// </summary>
+        /// <remarks>
+        /// 单位分
+        /// </remarks>
+        public int cash_amt { get; set; }
+
+        /// <summary>
+        /// 取现方ID号
+        /// </summary>
+        /// <remarks>
+        /// 提取发起方的汇付ID。支持已配置取现规则的商户、用户。
+        /// 示例值:6666000109812123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 账户号
+        /// </summary>
+        /// <remarks>
+        /// 可指定账户号,仅支持基本户、现金户,不填默认为基本户;
+        /// 示例值:F00598600
+        /// </remarks>
+        public string acct_id { get; set; }
+
+        /// <summary>
+        /// 到账日期类型
+        /// </summary>
+        /// <remarks>
+        /// D0:当日到账;当日交易资金当天可取现到账;
+        /// T1:次工作日到账;
+        /// D1:次自然日到账;
+        /// DM:当日到账;到账资金不包括当天的交易资金;
+        /// 示例值:D0
+        /// 非空
+        /// </remarks>
+        public string into_acct_date_type { get; set; }
+
+        /// <summary>
+        /// 取现卡序列号
+        /// </summary>
+        /// <remarks>
+        /// 绑定取现卡后可获取取现卡序列号;
+        /// 示例值:10004053462
+        /// 非空
+        /// </remarks>
+        public string token_no { get; set; }
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.Chash; }
+    }
+
+    public class HuiFuYuEPayInfo : HuiFuReqBase {
+        //为提现保存。
+        public string token_no { get; set; }
+        //支付金额-单位分
+        public int ord_amt { get; set; }
+        //出款方商户号
+        public string out_huifu_id { get; set; }
+        //收款方商户号
+        public string huifu_id { get; set; }
+        //01:卡券推广类;02:卡券核销类;03:消费;04:工资代发;05:分润;06:灵活用工;示例值:01        
+        public string transfer_type { get; set; } = "03";//默认03
+        //余额支付手续费承担方标识;商户余额支付扣收规则为接口指定承担方时必填!枚举值:
+        // OUT:出款方;
+        //IN:分账接受方。
+        public string trans_fee_take_flag { get; set; } = "OUT";//默认03        
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.YuEPay; }
+    }
+
+    public class HuiFuOpenInfo : HuiFuReqBase {
+        /// <summary>
+        /// 用户汇付ID
+        /// </summary>
+        /// <remarks>
+        /// 入驻时返回的huifu_id;示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 平台汇付Id
+        /// </summary>
+        /// <remarks>
+        /// 汇付分配的渠道商或商户编号;示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string upper_huifu_id { get; set; }
+
+        public CardInfo card_info { get; set; }
+
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.Open; }
+    }
+
+    public class HuiFuOpenModifyInfo : HuiFuOpenInfo {
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.OpenModify; }
+    }
+
+    public class CardInfo {
+        /// <summary>
+        /// 卡类型
+        /// </summary>
+        /// <remarks>
+        /// 0:对公,1:对私,2:对私非法人;个人商户/用户不支持对公类型,对私非法人类型
+        /// 示例值:0
+        /// 非空
+        /// </remarks>
+        public string card_type { get; set; }
+
+        /// <summary>
+        /// 卡户名
+        /// </summary>
+        /// <remarks>
+        /// 持卡人姓名;
+        /// 示例值:上海汇付支付服务公司
+        /// 非空
+        /// </remarks>
+        public string card_name { get; set; }
+
+        /// <summary>
+        /// 卡号
+        /// </summary>
+        /// <remarks>
+        /// 银行卡号;
+        /// 示例值:0206014170008888
+        /// 非空
+        /// </remarks>
+        public string card_no { get; set; }
+
+        /// <summary>
+        /// 银行所在省
+        /// </summary>
+        /// <remarks>
+        /// 地区编码内容较多,请下载查询下载;
+        /// 示例值:100000
+        /// 非空
+        /// </remarks>
+        public string prov_id { get; set; }
+
+        /// <summary>
+        /// 银行所在市
+        /// </summary>
+        /// <remarks>
+        /// 地区编码内容较多,请下载查询下载;
+        /// 示例值:110000
+        /// 非空
+        /// </remarks>
+        public string area_id { get; set; }
+
+        /// <summary>
+        /// 持卡人证件类型
+        /// </summary>
+        /// <remarks>
+        /// 对私必填;参见《自然人证件类型》说明;
+        /// 示例值:00 ,表示身份证
+        /// </remarks>
+        public string cert_type { get; set; } = "00";
+
+        /// <summary>
+        /// 持卡人证件号码
+        /// </summary>
+        /// <remarks>
+        /// 对私必填;如:证件类型为身份证, 则填写身份证号码;
+        /// 示例值:320926198412032059
+        /// </remarks>
+        public string cert_no { get; set; }
+
+        /// <summary>
+        /// 持卡人证件有效期类型
+        /// </summary>
+        /// <remarks>
+        /// 对私必填;1:长期有效;0:非长期有效;
+        /// 示例值:0
+        /// </remarks>
+        public string cert_validity_type { get; set; }
+
+        /// <summary>
+        /// 持卡人证件有效期(起始)
+        /// </summary>
+        /// <remarks>
+        /// 对私必填;日期格式:yyyyMMdd;
+        /// 示例值:20110112
+        /// </remarks>
+        public string cert_begin_date { get; set; }
+
+        /// <summary>
+        /// 持卡人证件有效期(截止)
+        /// </summary>
+        /// <remarks>
+        /// 当cert_validity_type=0时必须填写;日期格式yyyyMMdd;
+        /// 示例值:20110112
+        /// 当cert_validity_type=1可不填
+        /// </remarks>
+        public string cert_end_date { get; set; }
+
+        /// <summary>
+        /// 默认结算卡标志
+        /// </summary>
+        /// <remarks>
+        /// 是否为默认结算卡标志;Y:是 N:否(为空默认);
+        /// 示例值:Y
+        /// </remarks>
+        public string is_settle_default { get; set; } = "Y";
+    }
+
+    public class HuiFuRefundInfo : HuiFuReqBase {
+
+        /// <summary>
+        /// 申请退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位;示例值:1.00,最低传入0.01
+        /// 注意:如果是原交易是延时交易,退款金额必须小于等于待确认金额
+        /// 非空
+        /// </remarks>
+        public int ord_amt { get; set; }
+
+        /// <summary>
+        /// 原交易请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式:yyyyMMdd;示例值:20220925
+        /// 非空
+        /// </remarks>
+        public string org_req_date { get; set; }
+
+        /// <summary>
+        /// 原交易请求流水号
+        /// </summary>
+        /// <remarks>
+        /// org_hf_seq_id,org_party_order_id,org_req_seq_id三选一;
+        /// 示例值:202110210012100005
+        /// </remarks>
+        public string org_req_seq_id { get; set; }
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.Refund; }
+    }
+
+    public class HuiFuRefundQueryInfo: HuiFuReqBase {
+
+        /// <summary>
+        /// 退款请求日期
+        /// </summary>
+        /// <remarks>
+        /// 退款发生的日期,格式为yyyyMMdd,示例值:20220925
+        /// 非空
+        /// </remarks>
+        public string org_req_date { get; set; }
+
+        /// <summary>
+        /// 退款请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 退款请求流水号,退款全局流水号,终端订单号三选一不能都为空;
+        /// 示例值:202110210012100005
+        /// </remarks>
+        public string org_req_seq_id { get; set; }
+        public override HuiFuReqTypeEnums ReqType() { return HuiFuReqTypeEnums.RefundQuery; }
+    }
+    #endregion
+
+    #region 聚合支付参数
+    /// <summary>
+    /// 目前只接入alipay.部分字段非必填,已删。
+    /// </summary>
+    public class HuiFuJspayReq {
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMdd;示例值:20220905
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:rQ2021121311173944134649875651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 渠道与一级代理商的直属商户ID;示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 账户号
+        /// </summary>
+        /// <remarks>
+        /// 可指定收款账户号,仅支持基本户、现金户,不填默认为基本户;
+        /// 示例值:F00598600
+        /// </remarks>
+        public string acct_id { get; set; }
+
+        /// <summary>
+        /// 商品描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:XX商品
+        /// 非空
+        /// </remarks>
+        public string goods_desc { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>
+        /// T_JSAPI: 微信公众号
+        /// T_MINIAPP: 微信小程序
+        /// A_JSAPI: 支付宝JS
+        /// A_NATIVE: 支付宝正扫
+        /// U_NATIVE: 银联正扫
+        /// U_JSAPI: 银联JS
+        /// D_NATIVE: 数字人民币正扫
+        /// T_H5:微信直连H5支付
+        /// T_APP:微信APP支付
+        /// T_NATIVE:微信正扫
+        /// 示例值:A_NATIVE
+        /// 非空
+        /// </remarks>
+        public string trade_type { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1000.00,最低传入0.01;
+        /// 非空
+        /// </remarks>
+        public string trans_amt { get; set; }
+
+        /// <summary>
+        /// 交易有效期
+        /// </summary>
+        /// <remarks>
+        /// 该笔订单允许付款最晚时间,建议大于1分钟;
+        /// 注意:微信、支付宝交易有订单超时时间,默认两小时关单;
+        /// 请求格式:yyyyMMddHHmmss;示例值:20220912111230
+        /// </remarks>
+        public string time_expire { get; set; }
+
+        /// <summary>
+        /// 支付宝参数集合
+        /// </summary>
+        /// <remarks>
+        /// HuiFuAlipayReqData 生成的jsonObject字符串
+        /// </remarks>
+        public string alipay_data { get; set; }
+
+        /// <summary>
+        /// 是否延迟交易
+        /// </summary>
+        /// <remarks>
+        /// Y 为延迟 N为不延迟,不传默认N;
+        /// 示例值:Y
+        /// </remarks>
+        public string delay_acct_flag { get; set; }
+
+        /// <summary>
+        /// 手续费扣款标志
+        /// </summary>
+        /// <remarks>
+        /// 1: 外扣 2: 内扣 (默认取控台配置值);
+        /// 示例值:1
+        /// </remarks>
+        public int? fee_flag { get; set; }
+        /// <summary>
+        /// 传入分账遇到优惠的处理规则
+        /// </summary>
+        /// <remarks>
+        /// 1: 按比例分,2: 按顺序保障,3: 只给交易商户(默认);示例值:1
+        /// </remarks>
+        public int? term_div_coupon_type { get; set; }
+        
+        /// <summary>
+        /// 补贴支付信息
+        /// </summary>
+        /// <remarks>
+        /// jsonArray字符串;参见《补贴支付信息》
+        /// </remarks>
+        public object? combinedpay_data { get; set; }
+
+        /// <summary>
+        /// 禁用信用卡标记
+        /// </summary>
+        /// <remarks>
+        /// 本次交易禁止使用的支付方式,默认不禁用;取值参见说明;
+        /// 示例值:NO_CREDIT
+        /// </remarks>
+        public string limit_pay_type { get; set; }
+
+        /// <summary>
+        /// 商户贴息标记
+        /// </summary>
+        /// <remarks>
+        /// 商户补贴活动,Y: 商户全额贴息,P:商户部分贴息,不传为非商户贴息(默认);
+        /// 示例值:Y
+        /// </remarks>
+        public string fq_mer_discount_flag { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 交易后原样返回;
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 异步通知地址
+        /// </summary>
+        /// <remarks>
+        /// 交易异步通知地址,http或https开头。
+        /// 示例值:https://callback.service.com/xx
+        /// </remarks>
+        public string notify_url { get; set; }
+    }
+    public class HuiFuAlipayReq {
+        /// <summary>
+        /// 支付宝的店铺编号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:2016041400077000000003314986
+        /// </remarks>
+        public string alipay_store_id { get; set; }
+
+        /// <summary>
+        /// 买家的支付宝唯一用户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:2088202954065786;
+        /// 非空
+        /// </remarks>
+        public string buyer_id { get; set; }
+
+        /// <summary>
+        /// 买家支付宝账号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:carl.chen@huifu.com;
+        /// </remarks>
+        public string buyer_logon_id { get; set; }
+
+        /// <summary>
+        /// 商户原始订单号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:39045032345
+        /// </remarks>
+        public string merchant_order_no { get; set; }
+
+        /// <summary>
+        /// 商户操作员编号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:carl.li@huifu.com
+        /// </remarks>
+        public string operator_id { get; set; }
+
+        /// <summary>
+        /// 销售产品码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:YYZY
+        /// </remarks>
+        public string product_code { get; set; }
+
+        /// <summary>
+        /// 卖家支付宝用户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:20880414938706770000
+        /// </remarks>
+        public string seller_id { get; set; }
+
+        /// <summary>
+        /// 商户门店编号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:sh1001
+        /// </remarks>
+        public string store_id { get; set; }
+
+        /// <summary>
+        /// 订单标题
+        /// </summary>
+        /// <remarks>
+        /// 直连模式必填;商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来;
+        /// 示例值:红果奶茶
+        /// </remarks>
+        public string subject { get; set; }
+
+    }
+
+    public class HuiFuJspayResp {
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 请求时间
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:20220905
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:rQ2021121311173944134649875651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:00470topo1A221019132207P068ac1362af00000
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>
+        /// T_JSAPI: 微信公众号支付
+        /// T_MINIAPP: 微信小程序支付
+        /// A_JSAPI: 支付宝JS
+        /// A_NATIVE: 支付宝正扫
+        /// U_NATIVE: 银联正扫
+        /// U_JSAPI: 银联 JS
+        /// D_NATIVE: 数字人民币正扫
+        /// T_H5:微信直连H5支付
+        /// T_APP:微信APP支付
+        /// T_NATIVE:微信正扫
+        /// 示例值:T_JSAPI
+        /// </remarks>
+        public string trade_type { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,示例值:1.00
+        /// </remarks>
+        public string trans_amt { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// P:处理中、S:成功、F:失败;交易状态以此字段为准。
+        /// 示例值:S
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 通道返回码
+        /// </summary>
+        /// <remarks>
+        /// 请勿根据此字段判断交易状态,此字段建议在交易失败时配合bank_message使用。
+        /// 示例值:00
+        /// </remarks>
+        public string bank_code { get; set; }
+
+        /// <summary>
+        /// 通道返回描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:成功[0000000]
+        /// </remarks>
+        public string bank_message { get; set; }
+
+        /// <summary>
+        /// 延时标记
+        /// </summary>
+        /// <remarks>
+        /// Y: 延迟 N: 实时(默认)
+        /// 注意:延时交易要调交易确认接口资金才能进入收款方账户,否则会停留在延时账户中。
+        /// 示例值:Y
+        /// </remarks>
+        public string delay_acct_flag { get; set; }
+
+        /// <summary>
+        /// JS支付信息
+        /// </summary>
+        /// <remarks>
+        /// JSAPI支付返回信息;
+        /// </remarks>
+        public string pay_info { get; set; }
+
+        /// <summary>
+        /// 二维码链接
+        /// </summary>
+        /// <remarks>
+        /// NATIVE支付返回二维码链接;
+        /// 示例值:https://qr.alipay.com/bax03232ftw69valbwmg000d
+        /// </remarks>
+        public string qr_code { get; set; }
+
+        /// <summary>
+        /// 支付宝返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// Json格式
+        /// </remarks>
+        public object? alipay_response { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 原样返回;
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 账户号
+        /// </summary>
+        /// <remarks>
+        /// 商户账户号;
+        /// 示例值:F00598600
+        /// </remarks>
+        public string acct_id { get; set; }
+
+        /// <summary>
+        /// 终端类型
+        /// </summary>
+        /// <remarks>
+        /// 01-智能POS
+        /// 02-扫码POS
+        /// 03-云音箱
+        /// 04-台牌
+        /// 05-云打印
+        /// 06-扫脸设备
+        /// 07-收银机
+        /// 08-收银助手
+        /// 09-传统POS
+        /// 10-一体音箱
+        /// 11-虚拟终端
+        /// 示例值:01
+        /// </remarks>
+        public string device_type { get; set; }
+
+        /// <summary>
+        /// 用户账单上的商户订单号
+        /// </summary>
+        /// <remarks>
+        /// 参见用户账单说明;
+        /// 示例值:03232109190255105603561
+        /// </remarks>
+        public string party_order_id { get; set; }
+
+        /// <summary>
+        /// ATU真实商户号
+        /// </summary>
+        /// <remarks>
+        /// 微信、支付宝、银联真实商户号;
+        /// 示例值:411111141
+        /// </remarks>
+        public string aTu_sub_mer_id { get; set; }
+
+        /// <summary>
+        /// 待确认金额
+        /// </summary>
+        /// <remarks>
+        /// 待确认金额;单位元。
+        /// 示例值:1.00
+        /// </remarks>
+        public string unconfirm_amt { get; set; }
+    }
+    
+    public class HuiFuJspayAsyncResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:rQ2021121311173944134649875651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 请求时间
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回,格式为yyyyMMdd,示例值:20091225
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>
+        /// T_JSAPI: 微信公众号支付
+        /// T_MINIAPP: 微信小程序支付
+        /// A_JSAPI: 支付宝JS
+        /// A_NATIVE: 支付宝正扫
+        /// U_NATIVE: 银联正扫
+        /// U_JSAPI: 银联 JS
+        /// T_MICROPAY: 微信反扫
+        /// A_MICROPAY: 支付宝反扫
+        /// U_MICROPAY: 银联反扫
+        /// D_NATIVE: 数字人民币正扫
+        /// D_MICROPAY: 数字人民币反扫
+        /// 示例值:T_JSAPI
+        /// </remarks>
+        public string trans_type { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:00470topo1A221019132207P068ac1362af00000
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 用户账单上的交易订单号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:092021091922001451301445517582;参见用户账单说明
+        /// </remarks>
+        public string out_trans_id { get; set; }
+
+        /// <summary>
+        /// 用户账单上的商户订单号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:03232109190255105603561;参见用户账单说明
+        /// </remarks>
+        public string party_order_id { get; set; }
+
+        /// <summary>
+        /// 交易金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// </remarks>
+        public string trans_amt { get; set; }
+
+        /// <summary>
+        /// 消费者实付金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,示例值:1.00
+        /// </remarks>
+        public string pay_amt { get; set; }
+
+        /// <summary>
+        /// 结算金额(元)
+        /// </summary>
+        /// <remarks>
+        /// 实际应结金额(订单金额扣除优惠金额后的值),需保留小数点后两位,示例值:1000.00,最低传入0.01
+        /// </remarks>
+        public string settlement_amt { get; set; }
+
+        /// <summary>
+        /// 支付完成时间
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMddHHmmss,示例值:20091225091010
+        /// </remarks>
+        public string end_time { get; set; }
+
+        /// <summary>
+        /// 入账时间
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20091225
+        /// </remarks>
+        public string acct_date { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// S:成功、F:失败,交易状态以此字段为准。
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 手续费扣款标志
+        /// </summary>
+        /// <remarks>
+        /// 1: 外扣,2: 内扣。
+        /// </remarks>
+        public int? fee_flag { get; set; }
+
+        /// <summary>
+        /// 手续费费率信息
+        /// </summary>
+        /// <remarks>
+        /// 交易成功时返回手续费费率信息。
+        /// </remarks>
+        public object? fee_formula_infos { get; set; }
+
+        /// <summary>
+        /// 手续费金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01。
+        /// </remarks>
+        public string fee_amount { get; set; }
+
+        /// <summary>
+        /// 补贴支付的手续费
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00。
+        /// </remarks>
+        public string combinedpay_fee_amt { get; set; }
+
+        /// <summary>
+        /// 手续费补贴信息
+        /// </summary>
+        /// <remarks>
+        /// Json格式;参加银行补贴手续费。
+        /// </remarks>
+        public object? trans_fee_allowance_info { get; set; }
+
+        /// <summary>
+        /// 补贴支付信息
+        /// </summary>
+        /// <remarks>
+        /// jsonArray字符串;参见《补贴支付信息》。
+        /// </remarks>
+        public object combinedpay_data { get; set; }
+
+        /// <summary>
+        /// 借贷记标识
+        /// </summary>
+        /// <remarks>
+        /// D-借记卡,C-贷记卡,0-其他。
+        /// </remarks>
+        public string debit_type { get; set; }
+
+        /// <summary>
+        /// 是否分账交易
+        /// </summary>
+        /// <remarks>
+        /// 1:分账交易, 0:非分账交易。
+        /// 非空
+        /// </remarks>
+        public string is_div { get; set; }
+
+        /// <summary>
+        /// 是否延时交易
+        /// </summary>
+        /// <remarks>
+        /// 1:延迟, 0:非延迟。
+        /// 非空
+        /// </remarks>
+        public string is_delay_acct { get; set; }
+
+        /// <summary>
+        /// 支付宝返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// Json格式。
+        /// </remarks>
+        public object? alipay_response { get; set; }
+
+        /// <summary>
+        /// 终端类型
+        /// </summary>
+        /// <remarks>
+        /// 01-智能POS
+        /// 02-扫码POS
+        /// 03-云音箱
+        /// 04-台牌
+        /// 05-云打印
+        /// 06-扫脸设备
+        /// 07-收银机
+        /// 08-收银助手
+        /// 09-传统POS
+        /// 10-一体音箱
+        /// 11-虚拟终端
+        /// 示例值:01
+        /// </remarks>
+        public string device_type { get; set; }
+
+        /// <summary>
+        /// 商户终端定位
+        /// </summary>
+        /// <remarks>
+        /// 商户终端定位信息,jsonObject字符串。
+        /// </remarks>
+        public string mer_dev_location { get; set; }
+
+        /// <summary>
+        /// 通道返回码
+        /// </summary>
+        /// <remarks>
+        /// 请勿根据此字段判断交易状态,此字段建议在交易失败时配合bank_message使用。
+        /// 示例值:00
+        /// </remarks>
+        public string bank_code { get; set; }
+
+        /// <summary>
+        /// 通道返回描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:成功[0000000]
+        /// </remarks>
+        public string bank_message { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 分期资产方式
+        /// </summary>
+        /// <remarks>
+        /// 花呗分期功能,代表优先使用的资产类型;alipayfq_cc:表示信用卡分期。
+        /// 示例值:alipayfq_cc
+        /// </remarks>
+        public string fq_channels { get; set; }
+
+        /// <summary>
+        /// 通知类型
+        /// </summary>
+        /// <remarks>
+        /// 1:通道通知,2:账务通知。
+        /// 示例值:1
+        /// </remarks>
+        public string notify_type { get; set; }
+
+        /// <summary>
+        /// 分账手续费信息
+        /// </summary>
+        /// <remarks>
+        /// 分账手续费信息。
+        /// </remarks>
+        public string split_fee_info { get; set; }
+
+        /// <summary>
+        /// ATU真实商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:411111141
+        /// </remarks>
+        public string aTu_sub_mer_id { get; set; }
+
+        /// <summary>
+        /// 汇付终端号
+        /// </summary>
+        /// <remarks>
+        /// 使用汇付机具交易时返回。
+        /// 示例值:660035730311200000
+        /// </remarks>
+        public string devs_id { get; set; }
+
+        /// <summary>
+        /// 资金冻结状态
+        /// </summary>
+        /// <remarks>
+        /// FREEZE:冻结;UNFREEZE:解冻。
+        /// 示例值:UNFREEZE
+        /// </remarks>
+        public string fund_freeze_stat { get; set; }
+    }
+
+    /// <summary>
+    /// 解冻异步返回参数
+    /// </summary>
+    public class HuiFuJspayAsyncUnfreezeResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 交易的汇付全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:00470topo1A221019132207P068ac1362af00000
+        /// 非空
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 交易请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:rQ2021121311173944134649875651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 交易请求日期
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回,格式为yyyyMMdd,示例值:20091225
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000123120000
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 通知类型
+        /// </summary>
+        /// <remarks>
+        /// 3:资金解冻通知;示例值:3
+        /// 非空
+        /// </remarks>
+        public string notify_type { get; set; }
+
+        /// <summary>
+        /// 资金冻结状态
+        /// </summary>
+        /// <remarks>
+        /// UNFREEZE:解冻;示例值:UNFREEZE
+        /// 非空
+        /// </remarks>
+        public string fund_freeze_stat { get; set; }
+
+        /// <summary>
+        /// 解冻金额
+        /// </summary>
+        /// <remarks>
+        /// 单元:元。示例值:1.23
+        /// 非空
+        /// </remarks>
+        public string unfreeze_amt { get; set; }
+
+        /// <summary>
+        /// 冻结时间
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMddHHMMSS,示例值:20091225091010
+        /// 非空
+        /// </remarks>
+        public string freeze_time { get; set; }
+
+        /// <summary>
+        /// 解冻时间
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMddHHMMSS,示例值:20091225091010
+        /// 非空
+        /// </remarks>
+        public string unfreeze_time { get; set; }
+    }
+    #endregion
+
+    #region 取现参数
+    public class HuiFuChashReq {
+
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMdd;示例值:20210917
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:2021091708126665001
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 取现金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00
+        /// 非空
+        /// </remarks>
+        public string cash_amt { get; set; }
+
+        /// <summary>
+        /// 取现方ID号
+        /// </summary>
+        /// <remarks>
+        /// 提取发起方的汇付ID。支持已配置取现规则的商户、用户。
+        /// 示例值:6666000109812123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 账户号
+        /// </summary>
+        /// <remarks>
+        /// 可指定账户号,仅支持基本户、现金户,不填默认为基本户;
+        /// 示例值:F00598600
+        /// </remarks>
+        public string acct_id { get; set; }
+
+        /// <summary>
+        /// 到账日期类型
+        /// </summary>
+        /// <remarks>
+        /// D0:当日到账;当日交易资金当天可取现到账;
+        /// T1:次工作日到账;
+        /// D1:次自然日到账;
+        /// DM:当日到账;到账资金不包括当天的交易资金;
+        /// 示例值:D0
+        /// 非空
+        /// </remarks>
+        public string into_acct_date_type { get; set; }
+
+        /// <summary>
+        /// 取现卡序列号
+        /// </summary>
+        /// <remarks>
+        /// 绑定取现卡后可获取取现卡序列号;
+        /// 示例值:10004053462
+        /// 非空
+        /// </remarks>
+        public string token_no { get; set; }
+
+        /// <summary>
+        /// 取现渠道
+        /// </summary>
+        /// <remarks>
+        /// 00:汇付(为空默认); 10:中信e账通;
+        /// 示例值:00
+        /// </remarks>
+        public string enchashment_channel { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 异步通知地址
+        /// </summary>
+        /// <remarks>
+        /// 示例值:http://service.example.com/to/path
+        /// </remarks>
+        public string notify_url { get; set; }
+    }
+    public class HuiFuChashResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>
+        /// 参见业务返回码,示例值:00000000
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>
+        /// 业务返回信息,示例值:处理成功
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式:yyyyMMdd;示例值:20211123
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:202109160899013231200005
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 汇付全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:002900TOP3A221112165433P410ac139c1300001
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// S:成功 F:失败 P:处理中;
+        /// 示例值:S
+        /// 非空
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 商户号/机构号
+        /// </summary>
+        /// <remarks>
+        /// 汇付分配的商户号/机构号,示例值:6666000109812123
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 账户号
+        /// </summary>
+        /// <remarks>
+        /// 可指定账户号,仅支持基本户、现金户,不填默认为基本户;
+        /// 示例值:F00598600
+        /// </remarks>
+        public string acct_id { get; set; }
+    }
+    public class HuiFuChashAsyncResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>
+        /// 参见业务返回码,示例值:00000000
+        /// 非空
+        /// </remarks>
+        public string sub_resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>
+        /// 业务返回信息,示例值:处理成功
+        /// 非空
+        /// </remarks>
+        public string sub_resp_desc { get; set; }
+
+        /// <summary>
+        /// 业务请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:202109160899013231200005
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 业务请求时间
+        /// </summary>
+        /// <remarks>
+        /// 格式:yyyyMMdd;示例值:20211123
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 汇付全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:002900TOP3A221112165433P410ac139c1300001
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// S:成功;F:失败;P:处理中;
+        /// 示例值:S
+        /// </remarks>
+        public string trans_status { get; set; }
+
+        /// <summary>
+        /// 账务状态
+        /// </summary>
+        /// <remarks>
+        /// S:成功;F:失败;P:处理中;B:回账成功;
+        /// 示例值:S
+        /// </remarks>
+        public string acct_status { get; set; }
+
+        /// <summary>
+        /// 通道状态
+        /// </summary>
+        /// <remarks>
+        /// S:成功;F:失败;P:处理中;
+        /// 示例值:S
+        /// </remarks>
+        public string channel_status { get; set; }
+
+        /// <summary>
+        /// 手续费
+        /// </summary>
+        /// <remarks>
+        /// 单位:元。示例值:1.23
+        /// 非空
+        /// </remarks>
+        public string fee_amt { get; set; }
+
+        /// <summary>
+        /// 取现金额
+        /// </summary>
+        /// <remarks>
+        /// 单位:元。示例值:1.23
+        /// 非空
+        /// </remarks>
+        public string cash_amt { get; set; }
+
+        /// <summary>
+        /// 消息类型
+        /// </summary>
+        /// <remarks>
+        /// 01:通道;02:账务;
+        /// 示例值:01
+        /// </remarks>
+        public string msg_type { get; set; }
+    }
+    #endregion
+
+    #region 退款返回参数
+    public class HuiFuRefundResp {
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 产品号
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:YYZY
+        /// 非空
+        /// </remarks>
+        public string product_id { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000108854952
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 交易时传入,原样返回;示例值:rQ2021121311173944134649875651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:00470topo1A221019132207P068ac1362af00000
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 原交易请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// </remarks>
+        public string org_req_date { get; set; }
+
+        /// <summary>
+        /// 原交易请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:rQ202112131149875651
+        /// </remarks>
+        public string org_req_seq_id { get; set; }
+
+        /// <summary>
+        /// 退款交易发生日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// </remarks>
+        public string trans_date { get; set; }
+
+        /// <summary>
+        /// 退款交易发生时间
+        /// </summary>
+        /// <remarks>
+        /// 格式:HHMMSS,示例值:091010 代表9点10分10秒
+        /// </remarks>
+        public string trans_time { get; set; }
+
+        /// <summary>
+        /// 退款完成时间
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMddHHmmss,示例值:20091225091010
+        /// </remarks>
+        public string trans_finish_time { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// P:处理中、S:成功、F:失败;
+        /// 示例值:S
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 退款金额(元)
+        /// </summary>
+        /// <remarks>
+        /// 需保留小数点后两位;示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string ord_amt { get; set; }
+
+        /// <summary>
+        /// 实际退款金额(元)
+        /// </summary>
+        /// <remarks>
+        /// 需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// </remarks>
+        public string actual_ref_amt { get; set; }
+
+        /// <summary>
+        /// 支付宝返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// 直连返回字段
+        /// </remarks>
+        public string alipay_response { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 原样返回;
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 是否垫资退款
+        /// </summary>
+        /// <remarks>
+        /// Y 是垫资出款, N 是普通出款, 为空默认N;
+        /// 示例值:N
+        /// </remarks>
+        public string loan_flag { get; set; }
+
+        /// <summary>
+        /// 垫资承担者
+        /// </summary>
+        /// <remarks>
+        /// 为空:各自承担,不为空走第三方垫资;
+        /// 示例值:6666000108854952
+        /// </remarks>
+        public string loan_undertaker { get; set; }
+
+        /// <summary>
+        /// 垫资账户类型
+        /// </summary>
+        /// <remarks>
+        /// 01:基本户, 05: 充值户, 默认充值户;
+        /// 示例值:05
+        /// </remarks>
+        public string loan_acct_type { get; set; }
+
+        /// <summary>
+        /// 通道返回码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:01020000
+        /// </remarks>
+        public string bank_code { get; set; }
+
+        /// <summary>
+        /// 通道返回描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:SUCCESS
+        /// </remarks>
+        public string bank_message { get; set; }
+
+        /// <summary>
+        /// 待确认金额
+        /// </summary>
+        /// <remarks>
+        /// 待确认金额;单位元。
+        /// 示例值:1.00
+        /// </remarks>
+        public string unconfirm_amt { get; set; }
+
+        /// <summary>
+        /// 资金冻结状态
+        /// </summary>
+        /// <remarks>
+        /// FREEZE:冻结;UNFREEZE:解冻;
+        /// 退款发生时,对应原交易的资金冻结状态。
+        /// 示例值:UNFREEZE
+        /// </remarks>
+        public string fund_freeze_stat { get; set; }
+    }
+
+    public class HuiFuRefundAsyncResp {
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000108854952
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:rQ202112131117394413651
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:0030default220825182711P099ac1f343f00000
+        /// </remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 原交易请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// </remarks>
+        public string org_req_date { get; set; }
+
+        /// <summary>
+        /// 原交易请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:rQ202112131149875651
+        /// </remarks>
+        public string org_req_seq_id { get; set; }
+
+        /// <summary>
+        /// 原交易订单金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string org_ord_amt { get; set; }
+
+        /// <summary>
+        /// 原交易手续费
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string org_fee_amt { get; set; }
+
+        /// <summary>
+        /// 退款交易发生日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// 非空
+        /// </remarks>
+        public string trans_date { get; set; }
+
+        /// <summary>
+        /// 退款交易发生时间
+        /// </summary>
+        /// <remarks>
+        /// 格式:HHMMSS,示例值:0910109点10分10秒
+        /// </remarks>
+        public string trans_time { get; set; }
+
+        /// <summary>
+        /// 退款完成时间
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMddHHmmss;示例值:20091225091010
+        /// </remarks>
+        public string trans_finish_time { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>
+        /// TRANS_REFUND:交易退款;目前仅该一个枚举值;
+        /// 示例值:TRANS_REFUND
+        /// 非空
+        /// </remarks>
+        public string trans_type { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// P:处理中、S:成功、F:失败;
+        /// 示例值:
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string ord_amt { get; set; }
+
+        /// <summary>
+        /// 实际退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// </remarks>
+        public string actual_ref_amt { get; set; }
+
+        /// <summary>
+        /// 原交易累计退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string total_ref_amt { get; set; }
+
+        /// <summary>
+        /// 原交易累计退款手续费金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,示例值:1.00;注意:退还手续费规则参见说明文档
+        /// 非空
+        /// </remarks>
+        public string total_ref_fee_amt { get; set; }
+
+        /// <summary>
+        /// 累计退款次数
+        /// </summary>
+        /// <remarks>
+        /// 示例值:1
+        /// 非空
+        /// </remarks>
+        public string ref_cut { get; set; }
+
+        /// <summary>
+        /// 分账信息
+        /// </summary>
+        /// <remarks>
+        /// 分账信息
+        /// 非空
+        /// </remarks>
+        public object acct_split_bunch { get; set; }
+
+        /// <summary>
+        /// 微信支付宝的商户单号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:03232109190255105603561;参见用户账单说明
+        /// </remarks>
+        public string party_order_id { get; set; }
+
+        /// <summary>
+        /// 微信返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// 直连返回字段
+        /// </remarks>
+        public object wx_response { get; set; }
+
+        /// <summary>
+        /// 数字人民币响应报文
+        /// </summary>
+        /// <remarks>
+        /// jsonObject格式
+        /// </remarks>
+        public object dc_response { get; set; }
+
+        /// <summary>
+        /// 补贴支付信息
+        /// </summary>
+        /// <remarks>
+        /// 参见《补贴支付信息》
+        /// </remarks>
+        public object combinedpay_data { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>
+        /// 原样返回;
+        /// 示例值:备注
+        /// </remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 通道返回码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:01020000
+        /// </remarks>
+        public string bank_code { get; set; }
+
+        /// <summary>
+        /// 通道返回描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:SUCCESS
+        /// </remarks>
+        public string bank_message { get; set; }
+
+        /// <summary>
+        /// 银联返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// Json格式
+        /// </remarks>
+        public object unionpay_response { get; set; }
+
+        /// <summary>
+        /// 资金冻结状态
+        /// </summary>
+        /// <remarks>
+        /// FREEZE:冻结;UNFREEZE:解冻;
+        /// 退款发生时,对应原交易的资金冻结状态。
+        /// 示例值:UNFREEZE
+        /// </remarks>
+        public string fund_freeze_stat { get; set; }
+    }
+    #endregion
+
+    #region 退款查询
+    public class HuiFuRefundQueryResp {
+
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000108854952
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 退款全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:0030default220825182711P099ac1f343f00000
+        /// </remarks>
+        public string org_hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 退款请求日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// </remarks>
+        public string org_req_date { get; set; }
+
+        /// <summary>
+        /// 退款请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:202110210012100005
+        /// </remarks>
+        public string org_req_seq_id { get; set; }
+
+        /// <summary>
+        /// 退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// 非空
+        /// </remarks>
+        public string ord_amt { get; set; }
+
+        /// <summary>
+        /// 实际退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// </remarks>
+        public string actual_ref_amt { get; set; }
+
+        /// <summary>
+        /// 交易发生日期
+        /// </summary>
+        /// <remarks>
+        /// 格式为yyyyMMdd,示例值:20220925
+        /// </remarks>
+        public string trans_date { get; set; }
+
+        /// <summary>
+        /// 交易发生时间
+        /// </summary>
+        /// <remarks>
+        /// 格式:HHMMSS;示例值:091010 表示9点10分10秒
+        /// </remarks>
+        public string trans_time { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>
+        /// 示例值:TRANS_REFUND
+        /// </remarks>
+        public string trans_type { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>
+        /// P:处理中;S:成功;F:失败;I: 初始
+        /// 初始状态很罕见,请联系汇付技术人员处理;
+        /// 示例值:TRANS_REFUND
+        /// </remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 通道返回码
+        /// </summary>
+        /// <remarks>
+        /// 示例值:01020000
+        /// </remarks>
+        public string bank_code { get; set; }
+
+        /// <summary>
+        /// 通道返回描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:SUCCESS
+        /// </remarks>
+        public string bank_message { get; set; }
+
+        /// <summary>
+        /// 手续费金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00,最低传入0.01
+        /// </remarks>
+        public string fee_amt { get; set; }
+
+        /// <summary>
+        /// 分账对象
+        /// </summary>
+        /// <remarks>
+        /// 分账对象,jsonObject字符串
+        /// </remarks>
+        public string acct_split_bunch { get; set; }
+
+        /// <summary>
+        /// 分账手续费信息
+        /// </summary>
+        /// <remarks>
+        /// 分账手续费信息
+        /// </remarks>
+        public string split_fee_info { get; set; }
+
+        /// <summary>
+        /// 补贴支付信息
+        /// </summary>
+        /// <remarks>
+        /// jsonArray字符串;参见《补贴支付信息》
+        /// </remarks>
+        public string combinedpay_data { get; set; }
+
+        /// <summary>
+        /// 补贴部分的手续费
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00
+        /// </remarks>
+        public string combinedpay_fee_amt { get; set; }
+
+        /// <summary>
+        /// 数字货币返回报文
+        /// </summary>
+        /// <remarks>
+        /// 数字货币返回报文
+        /// </remarks>
+        public string dc_response { get; set; }
+
+        /// <summary>
+        /// 原交易用户账单上的商户订单号
+        /// </summary>
+        /// <remarks>
+        /// 原交易微信/支付宝/云闪付支付账单页商户订单号;
+        /// 示例值:03232109190255105603561;参见用户账单说明
+        /// </remarks>
+        public string org_party_order_id { get; set; }
+        /// <summary>
+        /// 授权号
+        /// </summary>
+        /// <remarks>
+        /// 同一商户当天,同一终端,同一批次号唯一;示例值:727902
+        /// </remarks>
+        public string auth_no { get; set; }
+
+        /// <summary>
+        /// 借贷标识
+        /// </summary>
+        /// <remarks>
+        /// 1-借,2-贷,3-其他(目前只有民生通道返回);示例值:1
+        /// </remarks>
+        public string debit_flag { get; set; }
+
+        /// <summary>
+        /// 商户名称
+        /// </summary>
+        /// <remarks>
+        /// 示例值:上海汇付支付服务公司
+        /// </remarks>
+        public string mer_name { get; set; }
+
+        /// <summary>
+        /// 商户私有域
+        /// </summary>
+        /// <remarks>
+        /// 示例值:商户私有域
+        /// </remarks>
+        public string mer_priv { get; set; }
+
+        /// <summary>
+        /// 原授权号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:727902
+        /// </remarks>
+        public string org_auth_no { get; set; }
+
+        /// <summary>
+        /// 原外部订单号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:20220810165837685701
+        /// </remarks>
+        public string org_out_order_id { get; set; }
+
+        /// <summary>
+        /// 预授权撤销返还手续费
+        /// </summary>
+        /// <remarks>
+        /// 示例值:0.10
+        /// </remarks>
+        public string pre_auth_cance_fee_amount { get; set; }
+
+        /// <summary>
+        /// 预授权撤销金额
+        /// </summary>
+        /// <remarks>
+        /// 示例值:100.00
+        /// </remarks>
+        public string pre_auth_cancel_amt { get; set; }
+
+        /// <summary>
+        /// 原预授权全局流水号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:0035000topA220628152651P306c0a8217a00000
+        /// </remarks>
+        public string pre_auth_hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 店铺名称
+        /// </summary>
+        /// <remarks>
+        /// 示例值:汇付宝山分公司
+        /// </remarks>
+        public string shop_name { get; set; }
+
+        /// <summary>
+        /// 分期退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元 格式:0.00;示例值:1.00
+        /// </remarks>
+        public string fq_acq_ord_amt { get; set; }
+
+        /// <summary>
+        /// 分期退款手续费金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元 格式:0.00;示例值:1.00
+        /// </remarks>
+        public string fq_acq_fee_amt { get; set; }
+
+        /// <summary>
+        /// 除分期外的退款金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元 格式:0.00;示例值:1.00
+        /// </remarks>
+        public string oth_ord_amt { get; set; }
+
+        /// <summary>
+        /// 除分期外的退款手续费金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元 格式:0.00;示例值:1.00
+        /// </remarks>
+        public string oth_fee_amt { get; set; }
+
+        /// <summary>
+        /// 微信返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// 直连模式返回
+        /// </remarks>
+        public string wx_response { get; set; }
+
+        /// <summary>
+        /// 支付宝返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// 直连模式返回
+        /// </remarks>
+        public string alipay_response { get; set; }
+
+        /// <summary>
+        /// 退款完成时间
+        /// </summary>
+        /// <remarks>
+        /// 格式yyyyMMddHHmmss;示例值:20091225091010
+        /// </remarks>
+        public string trans_finish_time { get; set; }
+
+        /// <summary>
+        /// 银联返回的响应报文
+        /// </summary>
+        /// <remarks>
+        /// Json格式
+        /// </remarks>
+        public string unionpay_response { get; set; }
+
+        /// <summary>
+        /// 待确认总金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00
+        /// </remarks>
+        public string unconfirm_amt { get; set; }
+
+        /// <summary>
+        /// 已确认总金额
+        /// </summary>
+        /// <remarks>
+        /// 单位元,需保留小数点后两位,示例值:1.00
+        /// </remarks>
+        public string confirmed_amt { get; set; }
+    }
+    #endregion
+    #region 用户进件
+    /// <summary>
+    /// 基本开户
+    /// </summary>
+    public class HuiFuIndvResp {
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 业务返回码,非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 业务返回描述,非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 汇付ID
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000123123123
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 管理员账号
+        /// </summary>
+        /// <remarks>
+        /// 示例值:Lg2022022201394910571
+        /// </remarks>
+        public string login_name { get; set; }
+
+        /// <summary>
+        /// 管理员密码
+        /// </summary>
+        /// <remarks>
+        /// 传login_name的时候要返回初始密码;示例值:cwqq304903
+        /// </remarks>
+        public string login_password { get; set; }
+    }
+    /// <summary>
+    /// 用户业务入驻
+    /// </summary>
+    public class HuiFuOpenResp {
+
+        /// <summary>
+        /// 业务响应码
+        /// </summary>
+        /// <remarks>
+        /// 业务返回码,非空
+        /// </remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务响应信息
+        /// </summary>
+        /// <remarks>
+        /// 业务返回描述,非空
+        /// </remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 汇付ID
+        /// </summary>
+        /// <remarks>
+        /// 示例值:6666000123123123
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 取现卡序列号
+        /// </summary>
+        /// <remarks>
+        /// 取现卡序列号,交易时使用;示例值:10000406827
+        /// </remarks>
+        public string token_no { get; set; }
+
+        /// <summary>
+        /// 业务配置结果状态列表
+        /// </summary>
+        /// <remarks>
+        /// jsonArray格式
+        /// </remarks>
+        public string resp_business { get; set; }
+
+        /// <summary>
+        /// 申请单号
+        /// </summary>
+        /// <remarks>
+        /// 返回审核中时有值,业务申请单号;示例值:2024022934731647
+        /// </remarks>
+        public string apply_no { get; set; }
+
+        /// <summary>
+        /// 乐接活配置状态
+        /// </summary>
+        /// <remarks>
+        /// 灵工场景下,且合作平台为乐接活时,返回该参数。
+        /// </remarks>
+        public string ljh_response { get; set; }
+    }
+
+    public class HuiFuOpenAsyncResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>
+        /// 业务返回码,非空
+        /// </remarks>
+        public string sub_resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>
+        /// 业务返回描述,非空
+        /// </remarks>
+        public string sub_resp_desc { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>
+        /// 原请求流水号;示例值:rQ2022101705562413620614285150
+        /// 非空
+        /// </remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 请求时间
+        /// </summary>
+        /// <remarks>
+        /// 原请求时间YYYYMMDD;示例值:20240123
+        /// 非空
+        /// </remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 汇付客户号
+        /// </summary>
+        /// <remarks>
+        /// 固定18位,汇付分配的商户号;示例值:6666000123123123
+        /// 非空
+        /// </remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 通知类型
+        /// </summary>
+        /// <remarks>
+        /// H:灵活用工,A:审核消息,Z:电子账户;示例值:A
+        /// 非空
+        /// </remarks>
+        public string notify_type { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        /// <remarks>
+        /// 灵活用工场景且合作平台为汇优财时,1-待开户 2-开户成功待签约 3-开户失败 4-签约成功 5-签约失败;
+        /// 示例值:4
+        /// </remarks>
+        public string state { get; set; }
+
+        /// <summary>
+        /// 状态描述
+        /// </summary>
+        /// <remarks>
+        /// 示例值:入驻失败
+        /// </remarks>
+        public string state_desc { get; set; }
+
+        /// <summary>
+        /// 审核信息
+        /// </summary>
+        /// <remarks>
+        /// jsonObject; notify_type = A时返回;
+        /// </remarks>
+        public string audit_info { get; set; }
+
+        /// <summary>
+        /// 斗拱e账户开通结果
+        /// </summary>
+        /// <remarks>
+        /// jsonObject格式;notify_type=Z时返回
+        /// </remarks>
+        public string elec_acct_result { get; set; }
+    }
+    #endregion
+
+    #region 余额支付
+    public class HuiFuYuEPayResp {
+        /// <summary>
+        /// 业务返回码
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string resp_code { get; set; }
+
+        /// <summary>
+        /// 业务返回描述
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string resp_desc { get; set; }
+
+        /// <summary>
+        /// 请求流水号
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 请求日期
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 出款商户号
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string out_huifu_id { get; set; }
+
+        /// <summary>
+        /// 支付金额
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string ord_amt { get; set; }
+
+        /// <summary>
+        /// 分账对象
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string acct_split_bunch { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 商品描述
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string good_desc { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 交易完成时间
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string trans_finish_time { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string remark { get; set; }
+
+        /// <summary>
+        /// 出款方账户号
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string out_acct_id { get; set; }
+
+        /// <summary>
+        /// 资金类型
+        /// </summary>
+        /// <remarks>条件必填,支付渠道为中信E管家时必填</remarks>
+        public string fund_type { get; set; }
+
+        /// <summary>
+        /// 支付渠道
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string acct_channel { get; set; }
+
+        /// <summary>
+        /// 灵活用工标志
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string hyc_flag { get; set; }
+
+        /// <summary>
+        /// 灵活用工平台
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string lg_platform_type { get; set; }
+
+        /// <summary>
+        /// 代发模式
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string salary_modle_type { get; set; }
+
+        /// <summary>
+        /// 落地公司商户号
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string bmember_id { get; set; }
+
+        /// <summary>
+        /// 灵活用工代发批次号
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string hyc_attach_id { get; set; }
+
+        /// <summary>
+        /// 乐接活返回参数集合
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string ljh_response { get; set; }
+
+        /// <summary>
+        /// 手续费承担方标识
+        /// </summary>
+        /// <remarks>条件必填,余额支付手续费承担方标识;商户余额支付扣收规则为接口指定承担方时必填</remarks>
+        public string trans_fee_take_flag { get; set; }
+
+        /// <summary>
+        /// 待确认总金额
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string unconfirm_amt { get; set; }
+
+        /// <summary>
+        /// 已确认总金额
+        /// </summary>
+        /// <remarks>非必填</remarks>
+        public string confirmed_amt { get; set; }
+    }
+
+    public class HuiFuYuEPayAsyncResp {
+        /// <summary>
+        /// 交易请求日期
+        /// </summary>
+        /// <remarks>必填,业务请求时间格式为YYYYMMDD(发起余额支付请求时间)</remarks>
+        public string req_date { get; set; }
+
+        /// <summary>
+        /// 交易请求流水号
+        /// </summary>
+        /// <remarks>必填,业务请求流水号(发起余额支付请求流水号)</remarks>
+        public string req_seq_id { get; set; }
+
+        /// <summary>
+        /// 全局流水号
+        /// </summary>
+        /// <remarks>非必填,汇付返回流水号</remarks>
+        public string hf_seq_id { get; set; }
+
+        /// <summary>
+        /// 产品号
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string product_id { get; set; }
+
+        /// <summary>
+        /// 商户号
+        /// </summary>
+        /// <remarks>必填,发起方商户号</remarks>
+        public string huifu_id { get; set; }
+
+        /// <summary>
+        /// 订单金额
+        /// </summary>
+        /// <remarks>必填</remarks>
+        public string ord_amt { get; set; }
+
+        /// <summary>
+        /// 交易类型
+        /// </summary>
+        /// <remarks>必填,余额支付:ACCT_PAYMENT</remarks>
+        public string trans_type { get; set; }
+
+        /// <summary>
+        /// 交易状态
+        /// </summary>
+        /// <remarks>必填,PSF P:处理中;S:成功;F:失败;C:完成。状态为完成时,需查看分账对象中每个分账的具体状态</remarks>
+        public string trans_stat { get; set; }
+
+        /// <summary>
+        /// 灵活用工标志
+        /// </summary>
+        /// <remarks>非必填,灵活用工标志 Y:灵活用工,N:非灵活用工(默认)</remarks>
+        public string hyc_flag { get; set; }
+
+        /// <summary>
+        /// 灵活用工代发批次号
+        /// </summary>
+        /// <remarks>非必填,灵活用工代发批次号,灵活用工平台为汇优财时返回</remarks>
+        public string hyc_attach_id { get; set; }
+
+        /// <summary>
+        /// 分账对象
+        /// </summary>
+        /// <remarks>必填,分账对象,jsonObject字符串</remarks>
+        public string acct_split_bunch { get; set; }
+    }
+
+
+    #endregion
+}

+ 128 - 0
JiaZhiQuan.Common/JuheAPI/HuiFu/HuiFuUtil.cs

@@ -0,0 +1,128 @@
+using BasePaySdk;
+using BasePaySdk.Request;
+using JiaZhiQuan.Common.Config;
+using JiaZhiQuan.Common.Utils;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.HuiFu {
+    public static class HuiFuUtil {
+
+        public static bool CheckSign(string huifuPubKey,string sign,
+            object data,bool isAsync=false) {
+            string dataStr = null;
+            if (isAsync) {
+                dataStr= JsonConvert.SerializeObject(data);
+            } else {
+                var str = JsonConvert.SerializeObject(data);
+                dataStr = sort4JsonString(str);
+            }
+            return RsaUtils.verfySign(huifuPubKey, sign,dataStr);
+        }
+        public static string sort4JsonString(string sourceJson) {
+
+            var dic = JsonConvert.DeserializeObject<SortedDictionary<string, object>>(sourceJson);
+            SortedDictionary<string, object> keyValues = new SortedDictionary<string, object>(dic);
+            var result = keyValues.OrderBy(m => m.Key);//升序 把Key换成Value 就是对Value进行排序
+            //var result = keyValues.OrderByDescending(m => m.Key);//降序
+            Dictionary<string, object> resultDic = result.ToDictionary(x => x.Key, x => x.Value);
+            return JsonConvert.SerializeObject(resultDic);
+        }
+
+        public static void InitConfig(HuiFuCommonConfig huifuConf) {
+            MerConfig config = new MerConfig {
+                ProductId = huifuConf.product_id,
+                SysId = huifuConf.sys_id,
+                RsaPrivateKey = huifuConf.app_secret_key,
+                RsaPublicKey = huifuConf.huifu_pub_key
+            };
+            //BasePay.debug = isDev;
+            BasePay.debug = true;
+            //BasePay.prodMode = !BasePay.debug;
+            BasePay.prodMode = true;
+            BasePay.initWithMerConfig(config);
+        }
+
+        public static void InitNoticeUrl(this HuiFuReqBase reqInfo, ConfigFromDb config) {
+            reqInfo.notifyUrl = reqInfo.ReqType() switch {
+                HuiFuReqTypeEnums.Jspay => config.HuiFuJspayCallbackUrl,
+                HuiFuReqTypeEnums.Chash => config.HuiFuChashCallbackUrl,
+                HuiFuReqTypeEnums.Open => config.HuiFuOpenCallbackUrl,
+                HuiFuReqTypeEnums.Refund => config.HuiFuRefundCallbackUrl,
+                HuiFuReqTypeEnums.OpenModify => config.HuiFuOpenCallbackUrl,
+               HuiFuReqTypeEnums.YuEPay => config.HuiFuYuEPayCallbackUrl,
+                _ => ""
+            };
+        }
+
+        /// <summary>
+        /// 流水号前缀
+        /// </summary>
+        /// <param name="reqType"></param>
+        /// <returns></returns>
+        public static void InitReqId(HuiFuReqBase info) {
+            var pre = info.ReqType() switch {
+                HuiFuReqTypeEnums.Jspay => "P",
+                HuiFuReqTypeEnums.Chash => "C",
+                HuiFuReqTypeEnums.Open => "O",
+                HuiFuReqTypeEnums.Refund => "R",
+                HuiFuReqTypeEnums.Indv => "I",
+                HuiFuReqTypeEnums.RefundQuery => "RQ",
+                HuiFuReqTypeEnums.OpenModify =>"OM",
+                HuiFuReqTypeEnums.YuEPay => "Y",
+                _ => ""
+            };
+
+            info.reqId = (info.orgId.Length+6)>32? info.orgId: pre + info.orgId + "A" + StrEncryUtils.GetRandom(4);
+        }
+
+        public static TResp Request<TResp>(HuiFuCommonConfig huifuConf,
+            HuiFuReqBase info) {
+            InitConfig(huifuConf);
+            BaseRequest request;
+            string reqTypeStr = "";
+            if (info is HuiFuPayInfo pInfo) {
+                request = HuiFuApiJspay.InitReq(huifuConf, pInfo);
+                reqTypeStr=pInfo.ReqType().ToString();
+            } else if(info is HuiFuRefundInfo rInfo) {
+                request = HuiFuApiRefund.InitReq(huifuConf, rInfo);
+                reqTypeStr = rInfo.ReqType().ToString();
+            } else if (info is HuiFuOpenInfo oInfo) {
+                request = HuiFuApiOpen.InitReq(huifuConf, oInfo);
+                reqTypeStr = oInfo.ReqType().ToString();
+            } else if (info is HuiFuChashInfo cInfo) {
+                request = HuiFuApiChash.InitReq(huifuConf, cInfo);
+                reqTypeStr = cInfo.ReqType().ToString();
+            } else if (info is HuiFuIndvInfo iInfo) {
+                request = HuiFuApiIndv.InitReq(huifuConf, iInfo);
+                reqTypeStr = iInfo.ReqType().ToString();
+            } else if (info is HuiFuRefundQueryInfo rqInfo) {
+                request = HuiFuApiRefundQuery.InitReq(huifuConf, rqInfo);
+                reqTypeStr = rqInfo.ReqType().ToString();
+            } else if (info is HuiFuOpenModifyInfo omInfo) {
+                request = HuiFuApiOpenModify.InitReq(huifuConf, omInfo);
+                reqTypeStr = omInfo.ReqType().ToString();
+            } else if (info is HuiFuYuEPayInfo yInfo) {
+                request = HuiFuApiYuEPay.InitReq(huifuConf, yInfo);
+                reqTypeStr = yInfo.ReqType().ToString();
+            } else {
+                throw new Exception("不支持的汇付接口");
+            }
+            try {
+                Dictionary<string, Object> result = null;
+                LoggerManager.Logger.Info($"{reqTypeStr} 请求入参:" + JsonConvert.SerializeObject(request));
+                result = BasePayClient.postRequest(request, null);
+                LoggerManager.Logger.Info($"{reqTypeStr} 响应结果:" + JsonConvert.SerializeObject(result));
+                var rstStr = JsonConvert.SerializeObject(result);
+                var rst = JsonConvert.DeserializeObject<TResp>(rstStr);
+                return rst;
+            } catch (Exception ex) {
+                LoggerManager.Logger.Error($"{reqTypeStr} 请求异常" + ex.Message);
+                return default;
+            }
+        }
+    }
+}

+ 60 - 0
JiaZhiQuan.Common/JuheAPI/IpAddress/JuheIpAddressUtils.cs

@@ -0,0 +1,60 @@
+using JiaZhiQuan.Common.JuheAPI.PhoneNumber;
+using Newtonsoft.Json;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.IpAddress
+{
+    /// <summary>
+    /// IP归属地查询
+    /// </summary>
+    public class JuheIpAddressUtils
+    {
+        const string JUHE_IP_KEY = "fe8483723642e2ec7df225caf4ae7889";
+
+        /// <summary>
+        /// 调用聚合API查询IP信息
+        /// <return>Item1:是不是需要保存结果到ES,Item2:拼接的地址信息,Item3:省,Item4:市</return>
+        /// </summary>
+        public static async Task<(bool, string, string, string)> GetIpAddressAsync(string ip, HttpClient client)
+        {
+            try
+            {
+                var res = await client.GetStringAsync($"http://apis.juhe.cn/ip/ipNewV3?ip={ip}&key={JUHE_IP_KEY}");
+                var obj = JsonConvert.DeserializeObject<JuheResponseModel<JuheMobileAddressResultDetails>>(res);
+                if (obj.ResultCode == "200" && obj.ErrorCode == 0)
+                {
+                    string province = string.IsNullOrEmpty(obj.Result.Province) ? "未知" : obj.Result.Province,
+                           city = string.IsNullOrEmpty(obj.Result.City) ? "未知" : obj.Result.City;
+                    string addr = !province.Equals(city) ? $"{province}{city}" : province;
+                    return (true, addr, province, city);
+                }
+                // 查询无结果
+                else if (obj.ResultCode == "200" && (obj.ErrorCode == 200103 || obj.ErrorCode == 200105))
+                {
+                    return (true, "未知", "未知", "未知");
+                }
+                else
+                {
+                    LoggerManager.Logger.Error($"调用聚合IP归属地API失败,请求结果:" + res);
+                    return (false, "未知", "未知", "未知");
+                }
+            }
+            catch (Exception ex)
+            {
+                LoggerManager.Logger.Error(ex, $"调用聚合IP归属地API报错:" + ex.Message);
+                return (false, "未知", "未知", "未知");
+            }
+        }
+    }
+    public class JuheMobileAddressResultDetails
+    {
+        public string Country { get; set; }
+        public string Province { get; set; }
+        public string City { get; set; }
+        public string District { get; set; }
+        public string Isp { get; set; }
+    }
+}

+ 20 - 0
JiaZhiQuan.Common/JuheAPI/JuheResponseModel.cs

@@ -0,0 +1,20 @@
+using JiaZhiQuan.Common.JuheAPI.PhoneNumber;
+
+namespace JiaZhiQuan.Common.JuheAPI
+{
+    public class JuheResponseModel<T>
+    {
+        public string ResultCode { get; set; }
+        public string Reason { get; set; }
+        public T Result { get; set; }
+        public int ErrorCode { get; set; }
+    }
+    
+    
+    public class JuheResponseModel1<T>
+    {
+        public string reason { get; set; }
+        public T result { get; set; }
+        public int error_code { get; set; }
+    }
+}

+ 62 - 0
JiaZhiQuan.Common/JuheAPI/MobileAddress/JuheMobileAddressUtils.cs

@@ -0,0 +1,62 @@
+using Newtonsoft.Json;
+using NLog;
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.JuheAPI.PhoneNumber
+{
+    /// <summary>
+    /// 手机号归属地查询
+    /// </summary>
+    /// <param name="db"></param>
+    /// <param name="phone"></param>
+    /// <returns>Item1: 是不是要保存到ES,Item2: 地址,Item3: 省,Item4: 市</returns>
+    public class JuheMobileAddressUtils
+    {
+        const string JUHE_PHONE_KEY = "641cf7b85574a965e6eb3d4864e18da3";
+        public static async Task<(bool, string, string, string)> GetMobileAddressAsync(string mobile, HttpClient client)
+        {
+            try
+            {
+                var res = await client.GetStringAsync($"http://apis.juhe.cn/mobile/get?phone={mobile}&key={JUHE_PHONE_KEY}");
+                var obj = JsonConvert.DeserializeObject<JuheResponseModel<JuheMobileAddressResultDetails>>(res);
+                if (obj.ResultCode == "200" && obj.ErrorCode == 0)
+                {
+                    string company = string.IsNullOrEmpty(obj.Result.Company) ? "未知" : obj.Result.Company,
+                           province = string.IsNullOrEmpty(obj.Result.Province) ? "未知" : obj.Result.Province,
+                           city = string.IsNullOrEmpty(obj.Result.City) ? "未知" : obj.Result.City;
+                    string addr = $"【{company}】-【{province}-{city}】";
+                    return (true, addr, province, city);
+                }
+                // 查询无结果
+                else if (obj.ResultCode == "200" && obj.ErrorCode == 201103)
+                {
+                    return (true, "未知", "未知", "未知");
+                }
+                else
+                {
+                    LoggerManager.Logger.Error($"调用聚合手机号归属地API失败,请求结果:" + res);
+                    return (false, "未知", "未知", "未知");
+                }
+            }
+            catch (Exception ex)
+            {
+                LoggerManager.Logger.Error(ex, $"调用聚合手机号归属地API报错:" + ex.Message);
+                return (false, "未知", "未知", "未知");
+            }
+        }
+    }
+
+    public class JuheMobileAddressResultDetails
+    {
+        public string Province { get; set; }
+        public string City { get; set; }
+        public string AreaCode { get; set; }
+        public string Zip { get; set; }
+        public string Company { get; set; }
+        public string Card { get; set; }
+    }
+
+}

+ 73 - 0
JiaZhiQuan.Common/JuheAPI/SendSms/JuheSendSmsUtils.cs

@@ -0,0 +1,73 @@
+using Aliyun.OSS.Model;
+using CSRedis;
+using Newtonsoft.Json;
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Web;
+using Wicture.DbRESTFul;
+using Wicture.DbRESTFul.Cache;
+
+namespace JiaZhiQuan.Common.JuheAPI.SendSms
+{
+    /// <summary>
+    /// 发送短信服务
+    /// 1分钟两次,每天最多10次
+    /// </summary>
+    public static class JuheSendSmsUtils
+    {
+        const string JUHE_SMS_KEY = "d753412f9bf62957f872b4e0a12d3122";
+        const int JUHE_SMS_TPL_ID = 266760;
+
+        /// <summary>
+        /// 发送验证码短信
+        /// </summary>
+        /// <param name="mobile">手机号</param>
+        /// <param name="client"></param>
+        /// <returns></returns>
+        public static async Task SendCodeSms(string mobile, string code, RedisCacheProvider redis, HttpClient client)
+        {
+            string dayLimitKey = CacheKeys.MobileDayLimit(mobile),
+                   continuousLimitKey = CacheKeys.ContinuousLimit(mobile);
+            int dayLimitCount = await redis.Get<int>(dayLimitKey);
+            dynamic continuousLimit = await redis.Get<dynamic>(continuousLimitKey);
+            if (dayLimitCount >= 10)
+            {
+                throw new LogicalException("您当日发送短信太频繁,请明天再试", ErrorCodes.SMSendDayLimitError);
+            }
+            if (continuousLimit != null && continuousLimit.count >= 2)
+            {
+                throw new LogicalException("您发送短信太频繁,请稍后再试", ErrorCodes.SMSendBusinessLimitError);
+            }
+            // 发送短信
+            string sendParams = HttpUtility.UrlEncode($"#code#={code}");
+            var res = await client.GetStringAsync($"http://v.juhe.cn/sms/send?mobile={mobile}&tpl_id={JUHE_SMS_TPL_ID}&tpl_value={sendParams}&key={JUHE_SMS_KEY}");
+            // 设置今天的发送次数
+            int newDayLimitCount = dayLimitCount + 1;
+            await redis.Set(dayLimitKey, newDayLimitCount, DateTime.Now.Date.AddDays(1));
+            // 设置连续发送的次数
+            DateTime expiration = continuousLimit is null ? DateTime.Now.AddMinutes(1) : continuousLimit.endTime;
+            int newcontinuousLimitCount = continuousLimit is null ? 1 : continuousLimit.count + 1;
+            dynamic newContinuousLimit = new
+            {
+                count = newcontinuousLimitCount,
+                endTime = expiration
+            };
+            await redis.Set(continuousLimitKey, newContinuousLimit, expiration);
+            // 查看发送结果
+            var obj = JsonConvert.DeserializeObject<JuheResponseModel1<JuheMobileAddressResultDetails>>(res);
+            if (obj.error_code != 0)
+            {
+                LoggerManager.Logger.Error($"调用聚合发送验证码短信API失败:" + JsonConvert.SerializeObject(obj));
+                throw new LogicalException("发送短信失败,请稍后再试[" + res + "]", ErrorCodes.Exception);
+            }
+        }
+    }
+
+    public class JuheMobileAddressResultDetails
+    {
+        public string sid { get; set; }
+        public int count { get; set; }
+        public int fee { get; set; }
+    }
+}

+ 126 - 0
JiaZhiQuan.Common/KDNiao/KDNiaoHelper.cs

@@ -0,0 +1,126 @@
+using Newtonsoft.Json;
+using System;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.KDNiao
+{
+    /// <summary>
+    /// 快递鸟帮助类
+    /// </summary>
+    public static class KDNiaoHelper
+    {
+        /// <summary>
+        /// 轨迹订阅地址
+        /// </summary>
+        private static string trackApiUrl = "https://api.kdniao.com/api/dist";
+
+        private static string trackInfoApiUrl = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
+
+        /// <summary>
+        /// 轨迹订阅接口
+        /// </summary>
+        /// <param name="request"></param>
+        /// <param name="httpClient"></param>
+        /// <returns></returns>
+        public static async Task<KDNiaoTrackResponse> SubscribeTrack(KDNiaoRequest request, IHttpClientFactory httpClientFactory)
+        {
+            var res = new KDNiaoTrackResponse();
+            try
+            {
+                using (var httpClient = httpClientFactory.CreateClient())
+                {
+                    var content = new StringContent($"RequestData={request.RequestData}&RequestType={(int)request.RequestType}&EBusinessID={request.EBusinessID}&DataSign={request.DataSign}&DataType={request.DataType}", Encoding.UTF8, "application/x-www-form-urlencoded");
+                    var response = await httpClient.PostAsync(trackApiUrl, content);
+                    if (response.IsSuccessStatusCode)
+                    {
+                        string responseContent = await response.Content.ReadAsStringAsync();
+                        res = JsonConvert.DeserializeObject<KDNiaoTrackResponse>(responseContent);
+                    }
+                    else
+                    {
+                        LoggerManager.Logger.Error($"调用快递鸟轨迹订阅失败: {response}");
+                    }
+                }
+                return res;
+            }
+            catch (System.Exception ex)
+            {
+                LoggerManager.Logger.Error($"调用快递鸟轨迹订阅失败: {ex.Message}");
+                return res;
+            }
+        }
+
+        /// <summary>
+        /// 即时查询、快递查询接口 RequestType不同
+        /// </summary>
+        /// <param name="request"></param>
+        /// <param name="httpClient"></param>
+        /// <returns></returns>
+        public static async Task<KDNiaoTrackDataItem> QueryTrackingInfo(KDNiaoRequest request, IHttpClientFactory httpClientFactory)
+        {
+            var res = new KDNiaoTrackDataItem();
+            try
+            {
+                using (var httpClient = httpClientFactory.CreateClient())
+                {
+                    var content = new StringContent($"RequestData={request.RequestData}&RequestType={(int)request.RequestType}&EBusinessID={request.EBusinessID}&DataSign={request.DataSign}&DataType={request.DataType}", Encoding.UTF8, "application/x-www-form-urlencoded");
+                    var response = await httpClient.PostAsync(trackInfoApiUrl, content);
+                    if (response.IsSuccessStatusCode)
+                    {
+                        string responseContent = await response.Content.ReadAsStringAsync();
+                        res = JsonConvert.DeserializeObject<KDNiaoTrackDataItem>(responseContent);
+                    }
+                    else
+                    {
+                        LoggerManager.Logger.Error($"调用快递鸟即时查询接口失败: {response}");
+                    }
+                }
+                return res;
+            }
+            catch (System.Exception ex)
+            {
+                LoggerManager.Logger.Error($"调用快递鸟即时查询接口失败: {ex.Message}");
+                return res;
+            }
+        }
+
+
+        /// <summary>
+        /// 快递在途查询
+        /// </summary>
+        /// <param name="LogisticCode">快递单号</param>
+        /// <param name="ShipperCode">快递公司编码,需维护进系统</param>
+        /// <param name="receivePhone">收货人手机号码,会自动截取为后4位</param>
+        /// <returns></returns>
+        public static async Task<KDNiaoTrackDataItem> QueryLogistics(string LogisticCode, 
+            string ShipperCode,string receivePhone, string EBusinessID, string ApiKey,
+            IHttpClientFactory httpClientFactory) {
+            var resp = new KDNiaoTrackDataItem();
+            string CustomerName = null;
+            try {
+                if ("SF".Equals(ShipperCode)) {
+                    if (receivePhone == null || receivePhone.Length < 4) {
+                        throw new System.Exception("当ShipperCode为顺风时,需提供收货人手机号后4位");
+                    }
+                    CustomerName = receivePhone[^4..];
+                }
+                var requestData = new {
+                    LogisticCode,
+                    ShipperCode,
+                    CustomerName
+                };
+                var data = JsonConvert.SerializeObject(requestData);
+                KDNiaoRequest request = new KDNiaoRequest(EBusinessID, ApiKey,
+                    data, KDNiaoRequestType.即时查询_增值版);
+                resp = await QueryTrackingInfo(request, httpClientFactory);
+            } catch(Exception ex) {
+                LoggerManager.Logger.Error("快递查询失败:" + ex.Message);
+            }            
+            if (null == resp.Traces) { resp.Traces = new System.Collections.Generic.List<KDNiaoTrace>(); }
+            return resp;
+        }
+    }
+}

+ 254 - 0
JiaZhiQuan.Common/KDNiao/KDNiaoModel.cs

@@ -0,0 +1,254 @@
+using System.Net;
+using System.Text;
+using System;
+using System.Security.Cryptography;
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.KDNiao
+{
+    /// <summary>
+    /// 快递鸟请求数据
+    /// </summary>
+    public class KDNiaoRequest
+    {
+        /// <summary>
+        /// apikey
+        /// </summary>
+        private string ApiKey;
+        public KDNiaoRequest(string EBusinessID, string ApiKey, string RequestData, KDNiaoRequestType RequestType)
+        {
+            this.ApiKey = ApiKey;
+            this.EBusinessID = EBusinessID;
+            this.RequestData = RequestData.Replace(" ", "");
+            this.RequestType = RequestType;
+            GenerateDataSign();
+        }
+        /// <summary>
+        /// 请求参数
+        /// </summary>
+        public string RequestData { get; }
+        /// <summary>
+        /// 用户id
+        /// </summary>
+        public string EBusinessID { get; }
+        /// <summary>
+        /// 请求接口类型
+        /// </summary>
+        public KDNiaoRequestType RequestType { get; }
+        /// <summary>
+        /// 数据内容签名 (请求体(未编码)+ApiKey)进行MD5加密(32位小写),然后Base64编码,最后进行URL(utf-8)编码
+        /// </summary>
+        public string DataSign { get; private set; }
+        public string DataType { get; } = "2";
+
+        private void GenerateDataSign()
+        {
+            string jsonString = RequestData;
+            string stringToSign = jsonString + ApiKey; // 拼接字符串和ApiKey
+            string md5Hash = CalculateMD5Hash(stringToSign); // MD5加密
+            string base64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(md5Hash)); // Base64编码
+            DataSign = WebUtility.UrlEncode(base64Encoded); // URL编码
+        }
+
+        /// <summary>
+        /// MD5 32位小写
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        private static string CalculateMD5Hash(string input)
+        {
+            using (MD5 md5 = MD5.Create())
+            {
+                byte[] inputBytes = Encoding.UTF8.GetBytes(input);
+                byte[] hashBytes = md5.ComputeHash(inputBytes);
+
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < hashBytes.Length; i++)
+                {
+                    sb.Append(hashBytes[i].ToString("x2")); // 转换为32位小写的16进制字符串
+                }
+                return sb.ToString();
+            }
+        }
+    }
+
+    /// <summary>
+    /// 快递鸟请求接口指令
+    /// </summary>
+    public enum KDNiaoRequestType
+    {
+        轨迹订阅_免费版 = 1008,
+        轨迹订阅_增值版 = 8008,
+        即时查询_免费版 = 1001,
+        即时查询_增值版 = 8001,
+        快递查询_增值版 = 8002
+    }
+
+    /// <summary>
+    /// 快递鸟轨迹订阅接口返回参数
+    /// </summary>
+    public class KDNiaoTrackResponse
+    {
+        /// <summary>
+        /// 快递公司编码
+        /// </summary>
+        public string ShipperCode { get; set; }
+        /// <summary>
+        /// 快递单号
+        /// </summary>
+        public string LogisticCode { get; set; }
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public DateTime UpdateTime { get; set; } = DateTime.Now;
+        /// <summary>
+        /// 成功与否
+        /// </summary>
+        public bool Success { get; set; } = false;
+    }
+
+    /// <summary>
+    /// 快递鸟callback轨迹参数
+    /// </summary>
+    public class KDNiaoTrackInfo
+    {
+        /// <summary>
+        /// 推送时间,示例:2021-01-01 09:00:00
+        /// </summary>
+        public string PushTime { get; set; }
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string EBusinessID { get; set; }
+        /// <summary>
+        /// 推送的轨迹数据集合
+        /// </summary>
+        public List<KDNiaoTrackDataItem> Data { get; set; }
+        /// <summary>
+        /// 推送的快递单号个数
+        /// </summary>
+        public string Count { get; set; }
+    }
+
+    public class KDNiaoTrackDataItem
+    {
+        /// <summary>
+        /// 物流状态编码
+        /// </summary>
+        /// 0-暂无轨迹信息
+        /*
+        1-已揽收
+        2-在途中
+         201-到达派件城市
+         204-到达转运中心
+         205-到达派件网点
+         206-寄件网点发件
+         202-派件中
+         211-已放入快递柜或驿站
+        3-已签收
+         301-正常签收
+         302-派件异常后最终签收
+         304-代收签收
+         311-快递柜或驿站签收
+        4-问题件
+         401-发货无信息
+         402-超时未签收
+         403-超时未更新
+         404-拒收(退件)
+         405-派件异常
+         406-退货签收
+         407-退货未签收
+         412-快递柜或驿站超时未取
+         413-单号已拦截
+         414-破损
+         415-客户取消发货
+         416-无法联系
+         417-配送延迟
+         418-快件取出
+         419-重新派送
+         420-收货地址不详细
+         421-收件人电话错误
+         422-错分件
+         423-超区件
+        5-转寄
+        6-清关
+         601-待清关
+         602-清关中
+         603-已清关
+         604-清关异常
+        10-待揽件*/
+        public string StateEx { get; set; }
+        /// <summary>
+        /// 快递单号
+        /// </summary>
+        public string LogisticCode { get; set; }
+        /// <summary>
+        /// 快递公司编码
+        /// </summary>
+        public string ShipperCode { get; set; }
+        /// <summary>
+        /// 轨迹信息
+        /// </summary>
+        public List<KDNiaoTrace> Traces { get; set; }
+        /// <summary>
+        /// 普通物流状态:
+        /// </summary>
+        /*
+        0-暂无轨迹信息
+        1-已揽收
+        2-在途中
+        3-签收
+        4-问题件
+        5-转寄
+        6-清关*/
+        public int State { get; set; }
+        /// <summary>
+        /// 当前城市
+        /// </summary>
+        public string Location { get; set; }
+        /// <summary>
+        /// 成功与否
+        /// </summary>
+        public bool Success { get; set; }
+        /// <summary>
+        /// 用户自定义回传字段
+        /// </summary>
+        public string Callback { get; set; }
+        /// <summary>
+        /// 失败原因
+        /// </summary>
+        public string Reason { get; set; }
+        /// <summary>
+        /// 用户id
+        /// </summary>
+        public string EBusinessID { get; set; }
+        /// <summary>
+        /// 快递员电话
+        /// </summary>
+        public string DeliveryManTel { get; set; }
+    }
+
+    public class KDNiaoTrace
+    {
+        /// <summary>
+        /// 同上面 StateEx
+        /// </summary>
+        public string Action { get; set; }
+        /// <summary>
+        /// 轨迹描述
+        /// </summary>
+        public string AcceptStation { get; set; }
+        /// <summary>
+        /// 轨迹发生时间
+        /// </summary>
+        public string AcceptTime { get; set; }
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Remark { get; set; }
+        /// <summary>
+        /// 历史节点所在城市
+        /// </summary>
+        public string Location { get; set; }
+    }
+}

+ 42 - 0
JiaZhiQuan.Common/Mapster/BuildTypeAdapterConfig.cs

@@ -0,0 +1,42 @@
+using JiaZhiQuan.Common.Models.PO;
+using JiaZhiQuan.Common.Models.VO.BalanceManage;
+using JiaZhiQuan.Common.Models.VO.CreatorCenter;
+using JiaZhiQuan.Common.Utils;
+using Mapster;
+
+namespace JiaZhiQuan.Common.Mapster
+{
+    public static class BuildTypeAdapterConfig
+    {
+        /// <summary>
+        /// ContentRewardVO => ContentRewardResultVO
+        /// 奖励金额(分为单位) => 奖励金额(元为单位)
+        /// </summary>
+        public static TypeAdapterConfig BuildContentRewardVOConfig()
+        {
+            TypeAdapterConfig config = new TypeAdapterConfig();
+            config.ForType<ContentRewardVO, ContentRewardResultVO>()
+                  // 奖励金额(分为单位) => 奖励金额(元为单位)
+                  .Map(dest => dest.amount, src => AmountUtils.ConvertCentToYuanStr(src.amount));
+            return config;
+        }
+
+        /// <summary>
+        /// ContentRewardVO => ContentRewardResultVO
+        /// 奖励金额(分为单位) => 奖励金额(元为单位)
+        /// </summary>
+        public static TypeAdapterConfig BuildBalanceCashoutPlatformVOConfig()
+        {
+            TypeAdapterConfig config = new TypeAdapterConfig();
+            config.ForType<BalanceCashoutPlatformPO, BalanceCashoutPlatformVO>()
+                  // 税率百分比
+                  .Map(dest => dest.taxRate, src => src.taxRate * 100)
+                  // 服务费率百分比
+                  .Map(dest => dest.feeRate, src => src.feeRate * 100)
+                  // 最少服务费金额(分为单位) => 最少服务费金额(元为单位)
+                  .Map(dest => dest.feeMinAmount, src => AmountUtils.ConvertCentToYuan((decimal)src.feeMinAmount));
+            return config;
+        }
+    }
+
+}

+ 23 - 0
JiaZhiQuan.Common/Mapster/GlobalSettings.cs

@@ -0,0 +1,23 @@
+using Mapster;
+using Newtonsoft.Json;
+using System.Linq;
+
+namespace JiaZhiQuan.Common.Mapster
+{
+    public static class MapsterGlobalSettings
+    {
+        public static void DefaultMapsterGlobalSettings()
+        {
+            // 忽略大小写敏感
+            TypeAdapterConfig.GlobalSettings
+                             .Default
+                             .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);
+            // 如果配置了JsonPropertyAttribute,则使用JsonPropertyAttribute的PropertyName
+            TypeAdapterConfig.GlobalSettings.Default
+                             .GetMemberName(member => member.GetCustomAttributes(true)
+                                                            .OfType<JsonPropertyAttribute>()
+                                                            .FirstOrDefault()
+                                                            ?.PropertyName);
+        }
+    }
+}

+ 213 - 0
JiaZhiQuan.Common/Messaging/BaseConsumer.cs

@@ -0,0 +1,213 @@
+using Confluent.Kafka;
+using Polly;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Wicture.DbRESTFul;
+
+namespace JiaZhiQuan.Common.Messaging
+{
+    public abstract class BaseConsumer : IConsumer
+    {
+        public event EventHandler<MessageReceivedEventArgs> Received;
+
+        private IConsumer<Ignore, string> consumer;
+
+        public abstract ConsumerConfig ClientConfig { get; set; }
+
+        public abstract IEnumerable<string> TopicNames { get; set; }
+
+        private CancellationTokenSource cancellationTokenSource;
+
+        public void Init()
+        {
+            Consume();
+        }
+
+        protected virtual void OnException(Exception ex)
+        {
+        }
+
+        protected virtual void OnExecuteTooLong(double secs, string message)
+        {
+        }
+
+        protected virtual void Consume1()
+        {
+            Task.Run(async () =>
+            {
+                var politicaWaitAndRetry = Policy.Handle<Exception>().WaitAndRetryForeverAsync(idx =>
+                {
+                    var sec = idx == 0 ? 1 : idx == 1 ? 10 : idx == 2 ? 30 : 60;
+                    return TimeSpan.FromSeconds(sec);
+                }, (ex, time) => { OnException(ex); });
+                await politicaWaitAndRetry.ExecuteAsync(async () =>
+                {
+                    ClientConfig = ClientConfig ?? new ConsumerConfig()
+                    {
+                        GroupId = "0",
+                        EnableAutoCommit = true,
+                        MaxPollIntervalMs = 900000
+                    };
+                    if (string.IsNullOrEmpty(ClientConfig.BootstrapServers))
+                    {
+                        var cfg = KafkaClientConfig.GetFromConfig();
+                        ClientConfig.BootstrapServers = cfg.BootstrapServers;
+                    }
+                    
+                    cancellationTokenSource = new CancellationTokenSource();
+                    consumer = new ConsumerBuilder<Ignore, string>(ClientConfig).Build();
+                    consumer.Subscribe(TopicNames);
+                    
+                    try
+                    {
+                        while (true)
+                        {
+                            try
+                            {
+                                var cr = consumer.Consume(cancellationTokenSource.Token);
+                                await ConsumeInternal(cr);
+                                Received?.Invoke(this, new MessageReceivedEventArgs { Message = cr.Message.Value });
+                                LoggerManager.Logger.Info($"Consumed message '{cr.Message.Value}' at: '{cr.TopicPartitionOffset}'.");
+                            }
+                            catch (ConsumeException e)
+                            {
+                                LoggerManager.Logger.Error(e, $"Error occured: {e.Error.Reason}");
+                                throw e;
+                            }
+                            catch (Exception e)
+                            {
+                                LoggerManager.Logger.Info($"Canceled Consume operation.");
+                                throw e;
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        throw ex;
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            cancellationTokenSource.Cancel();
+                            cancellationTokenSource.Dispose();
+                            consumer.Dispose();
+                        }
+                        catch { }
+                    }
+                });
+            });
+        }
+
+
+        protected virtual void Consume()
+        {
+            new Task(() =>
+            {
+                var politicaWaitAndRetry = Policy.Handle<Exception>().WaitAndRetryForever(idx =>
+                {
+                    var sec = idx == 0 ? 1 : idx == 1 ? 10 : idx == 2 ? 30 : 60;
+                    return TimeSpan.FromSeconds(sec);
+                }, (ex, time) => { OnException(ex); });
+                politicaWaitAndRetry.Execute(() =>
+                {
+                    var cfg = KafkaClientConfig.GetFromConfig();
+                    ClientConfig = ClientConfig ?? new ConsumerConfig()
+                    {
+                        GroupId = cfg?.GroupId ?? "0",
+                        EnableAutoCommit = true,
+                        MaxPollIntervalMs = 900000
+                    };
+                    if (string.IsNullOrEmpty(ClientConfig.BootstrapServers))
+                    {
+                        ClientConfig.BootstrapServers = cfg.BootstrapServers;
+                    }
+                    
+                    cancellationTokenSource = new CancellationTokenSource();
+                    consumer = new ConsumerBuilder<Ignore, string>(ClientConfig).Build();
+                    consumer.Subscribe(TopicNames);
+                    
+                    try
+                    {
+                        while (true) 
+                        {
+                            try
+                            {
+                                var cr = consumer.Consume(cancellationTokenSource.Token);
+                                ConsumeInternal(cr).Wait();
+                                Received?.Invoke(this, new MessageReceivedEventArgs { Message = cr.Message.Value });
+                                LoggerManager.Logger.Info($"Consumed message '{cr.Message.Value}' at: '{cr.TopicPartitionOffset}'.");
+                            }
+                            catch (ConsumeException e)
+                            {
+                                LoggerManager.Logger.Error(e, $"Error occured: {e.Error.Reason}");
+                                throw e;
+                            }
+                            catch (Exception e)
+                            {
+                                LoggerManager.Logger.Info($"Canceled Consume operation.");
+                                throw e;
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        throw ex;
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            cancellationTokenSource.Cancel();
+                            cancellationTokenSource.Dispose();
+                            consumer.Dispose();
+                        }
+                        catch { }
+                    }
+                });
+            }, TaskCreationOptions.LongRunning).Start();
+        }
+
+        private async Task ConsumeInternal(ConsumeResult<Ignore, string> cr)
+        {
+            try
+            {
+                var start = DateTime.Now;
+                await ConsumeAsync(cancellationTokenSource, cr.Message.Value);
+                var completed = DateTime.Now;
+                var secs = (completed - start).TotalSeconds;
+                if (secs > 1)
+                {
+                    LoggerManager.Logger.Error($"Task【{string.Join(',', TopicNames)}】运行时间过长【{secs}s】,内容:" + cr.Message.Value);
+                    OnExecuteTooLong(secs, cr.Message.Value);
+                }
+                // consumer.Commit(new List<TopicPartitionOffset> { cr.TopicPartitionOffset });
+            }
+            catch (NullReferenceException)
+            {
+                LoggerManager.Logger.Error($"Please check if null returned by ConsumeAsync, use Task.CompletedTask instead.");
+            }
+            catch (Exception ex)
+            {
+                LoggerManager.Logger.Error(ex, $"Error occured to consume message");
+            }
+        }
+
+        public abstract Task ConsumeAsync(CancellationTokenSource cts, string message);
+
+        public void Dispose()
+        {
+            if (consumer != null)
+            {
+                cancellationTokenSource.Cancel();
+                cancellationTokenSource.Dispose();
+                consumer.Dispose();
+                consumer = null;
+                GC.SuppressFinalize(this);
+            }
+        }
+    }
+}

+ 19 - 0
JiaZhiQuan.Common/Messaging/IConsumer.cs

@@ -0,0 +1,19 @@
+using Confluent.Kafka;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JiaZhiQuan.Common.Messaging
+{
+    public interface IConsumer : IDisposable
+    {
+        event EventHandler<MessageReceivedEventArgs> Received;
+
+        ConsumerConfig ClientConfig { get; set; }
+        IEnumerable<string> TopicNames { get; set; }
+        void Init();
+        Task ConsumeAsync(CancellationTokenSource cts, string message);
+    }
+}

+ 11 - 0
JiaZhiQuan.Common/Messaging/MessageReceivedEventArgs.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging
+{
+    public class MessageReceivedEventArgs : EventArgs
+    {
+        public string Message { get; set; }
+    }
+}

+ 24 - 0
JiaZhiQuan.Common/Messaging/MessagingConfig.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Wicture.DbRESTFul.Configuration;
+
+namespace JiaZhiQuan.Common.Messaging
+{
+    public class KafkaClientConfig
+    {
+        public const string ConfigSectionName = "KafkaClientConfig";
+
+        public string BootstrapServers { get; set; }
+        public string GroupId { get; set; }
+
+        public static KafkaClientConfig GetFromConfig()
+        {
+            if (ConfigurationManager.Settings.Document.ContainsKey(KafkaClientConfig.ConfigSectionName))
+            {
+                return ConfigurationManager.Settings.GetConfig<KafkaClientConfig>(ConfigSectionName);
+            }
+            return new KafkaClientConfig();
+        }
+    }
+}

+ 63 - 0
JiaZhiQuan.Common/Messaging/MessagingService.cs

@@ -0,0 +1,63 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Wicture.DbRESTFul;
+using Wicture.DbRESTFul.Configuration;
+
+namespace JiaZhiQuan.Common.Messaging
+{
+    public static class MessagingService
+    {
+        private static IEnumerable<IConsumer> consumers;
+        private static List<Producer> producers;
+
+        public static IApplicationBuilder UserMessageConsumption(this IApplicationBuilder app)
+        {
+            if (!ConfigurationManager.Settings.Document.ContainsKey(KafkaClientConfig.ConfigSectionName))
+            {
+                LoggerManager.Logger.Info("No configuration found, ignore message consumption.");
+                return app;
+            }
+
+            var aft = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
+            try
+            {
+                consumers = app.ApplicationServices.GetServices<IConsumer>();
+                if (consumers?.Count() > 0)
+                {
+                    aft.ApplicationStopping.Register(() =>
+                    {
+                        consumers.ForEach(c => c.Dispose());
+                    });
+
+                    foreach (var consumer in consumers)
+                    {
+                        consumer.Init();
+                        LoggerManager.Logger.Info($"Initialized consumer `{consumer.GetType().Name}`");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                LoggerManager.Logger.Error(ex, "Failed to init consumers.");
+            }
+            aft.ApplicationStopping.Register(() =>
+            {
+                producers?.ForEach(p => p?.Dispose());
+            });
+
+            return app;
+        }
+
+        public static void RegisterProducer(Producer producer)
+        {
+            if (producers == null) producers = new List<Producer>();
+            producers.Add(producer);
+        }
+    }
+}

+ 25 - 0
JiaZhiQuan.Common/Messaging/Models/CommentAuthModel.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public class CommentAuthModel
+    {
+        /// <summary>
+        /// 评论Id、评论回复Id
+        /// </summary>
+        public int CommentId { get; set; }
+
+        /// <summary>
+        /// 0 动态评论
+        /// 1 动态评论回复
+        /// </summary>
+        public int Type { get; set; } = 0;
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Comment_Auth_Msg";
+        }
+    }
+}

+ 28 - 0
JiaZhiQuan.Common/Messaging/Models/IMMessageModel.cs

@@ -0,0 +1,28 @@
+using JiaZhiQuan.Common.Hubs;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public class IMMessageModel
+    {
+
+        /// <summary>
+        /// 发送人id
+        /// </summary>
+        public long FromUserId { get; set; }
+
+        /// <summary>
+        /// 接收人id
+        /// </summary>
+        public long TargetUserId { get; set; }
+
+        /// <summary>
+        /// 消息内容
+        /// </summary>
+        public MessageContentDTO Content { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_IM_SendMessage";
+        }
+    }
+}

+ 22 - 0
JiaZhiQuan.Common/Messaging/Models/KDNaioTraceModel.cs

@@ -0,0 +1,22 @@
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum KDNiaoTraceType
+    {
+        /// <summary>
+        /// 轨迹订阅回调
+        /// </summary>
+        Callback = 0
+    }
+
+    public class KDNiaoTraceModel
+    {
+        public KDNiaoTraceType Type;
+
+        public string Content;
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_KDNiao_TrackCallback_Msg";
+        }
+    }
+}

+ 96 - 0
JiaZhiQuan.Common/Messaging/Models/LogRecordModel.cs

@@ -0,0 +1,96 @@
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum LogType
+    {
+        Api = 1
+    }
+
+    public class LogRecordModel
+    {
+
+        public LogType Type { get; set; }
+
+        public string Content { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Log_Record_Msg";
+        }
+    }
+
+    public class ApiLogRecordSubModel
+    {
+        /// <summary>
+        /// 耗时
+        /// </summary>
+        public int Milliseconds { get; set; }
+        /// <summary>
+        /// 全路径
+        /// </summary>
+        public string Url { get; set; }
+        /// <summary>
+        /// 参数(JSON字符串)
+        /// </summary>
+        public string Param { get; set; }
+        /// <summary>
+        /// 状态码
+        /// </summary>
+        public int StatusCode { get; set; }
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        public string ErrorMessage { get; set; }
+        /// <summary>
+        /// 用户Id,如果没有则为0
+        /// </summary>
+        public long UserId { get; set; }
+        /// <summary>
+        /// 设备Id
+        /// </summary>
+        public string DeviceId { get; set; }
+        /// <summary>
+        /// 设备信息
+        /// </summary>
+        public string DeviceInfo { get; set; }
+        /// <summary>
+        /// 渠道
+        /// </summary>
+        public string Channel { get; set; }
+        /// <summary>
+        /// IP
+        /// </summary>
+        public string IP { get; set; }
+        /// <summary>
+        /// 哪个系统
+        /// </summary>
+        public string System { get; set; }
+        /// <summary>
+        /// 记录时间
+        /// </summary>
+        public DateTime LogTime { get; set; } = DateTime.Now;
+    }
+
+    public class iOSDeviceInfo
+    {
+        public string os { get; set; }
+        public string appVersoft_versionsion { get; set; }
+        public string os_version { get; set; }
+    }
+
+    public class AndroidDeviceInfo
+    {
+        public string brand { get; set; }
+        public string device { get; set; }
+        public string manufacturer { get; set; }
+        public string model { get; set; }
+        public string os { get; set; }
+        public string os_version { get; set; }
+        public int sdk_int { get; set; }
+        public string soft_version { get; set; }
+    }
+}

+ 24 - 0
JiaZhiQuan.Common/Messaging/Models/MallGoodsSyncModel.cs

@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum MallGoodsSyncType
+    {
+        /// <summary>
+        /// 同步Es商品
+        /// </summary>
+        SyncEsMallGoods = 0
+    }
+
+    public class MallGoodsSyncModel
+    {
+        public MallGoodsSyncType Type;
+
+        public List<long> GoodsIds;
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_MallGoods_Sync_Msg";
+        }
+    }
+}

+ 222 - 0
JiaZhiQuan.Common/Messaging/Models/NotificationModel.cs

@@ -0,0 +1,222 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum NotificationType
+    {
+        /// <summary>
+        /// 通用系统通知
+        /// </summary>
+        Common = 0,
+
+        /// <summary>
+        /// 某人发送新动态时,需要通知关注他的用户
+        /// </summary>
+        NewPost = 1,
+
+        Comment = 2,
+
+        Thumbsup = 3,
+        
+        Focus = 4,
+        
+        CommonWithPost = 5,
+        
+        CommonWithAfterSale = 6,
+        
+        NewGoods = 7,
+        
+        CommonWithOrder = 8,
+        
+        /// <summary>
+        /// 商城流水
+        /// </summary>
+        CommonWithMallBill = 9,
+        
+        /// <summary>
+        /// 寄售单通知
+        /// </summary>
+        UEPostOrder = 11,
+        
+        /// <summary>
+        /// 寄售销售单通知
+        /// </summary>
+        UEPostSaleOrder = 12,
+        
+        /// <summary>
+        /// 挂售销售单通知
+        /// </summary>
+        UEHangSaleOrder = 13,
+        
+    }
+
+    public class NotificationModel
+    {
+        public NotificationType Type { get; set; }
+
+        public string Content { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Notification_Msg";
+        }
+    }
+
+    public class CommonSubModel
+    {
+        public long UserId { get; set; }
+        /// <summary>
+        /// 系统消息中,展示的标题。如果标题为空,则表示只发推送信息
+        /// </summary>
+        public string Title { get; set; }
+        /// <summary>
+        /// 消息内容
+        /// </summary>
+        public string Message { get; set; }
+        /// <summary>
+        /// 推送标题,如果不设置默认为“价值圈”
+        /// </summary>
+        public string PushTitle { get; set; }
+        /// <summary>
+        /// 推送标题,如果不设置,则取Message
+        /// </summary>
+        public string PushContent { get; set; }
+
+        /// <summary>
+        /// 系统消息中,显示的图片
+        /// </summary>
+        public string Image { get; set; }
+
+        /// <summary>
+        /// 消息点击行为链接
+        /// </summary>
+        public string ActionLink { get; set; }
+    }
+
+    public class CommonWithPostSubModel : CommonSubModel
+    {
+        public long PostId { get; set; }
+    }
+
+    public class AfterSaleSubModel : CommonSubModel
+    {
+        public long AfterSaleId { get; set; }
+    }
+
+    public class ThumbsupSubModel
+    {
+        public ThumbsupTargetType Type { get; set; }
+        public long TargetId { get; set; }
+
+        public long UserId { get; set; }
+
+        public DateTime CreateAt { get; set; }
+
+    }
+
+    public class CommentSubModel
+    {
+        /// <summary>
+        /// 评论Id、评论回复Id
+        /// </summary>
+        public int CommentId { get; set; }
+
+        /// <summary>
+        /// 0 动态评论
+        /// 1 动态评论回复
+        /// </summary>
+        public int Type { get; set; } = 0;
+
+    }
+
+    public class FocusSubModel
+    {
+        /// <summary>
+        /// 关注的用户Id
+        /// </summary>
+        public long FromUserId { get; set; }
+
+        /// <summary>
+        /// 被关注的用户Id
+        /// </summary>
+        public long ToUserId { get; set; }
+
+        public DateTime CreateAt { get; set; }
+    }
+
+    public class NewPostSubModel
+    {
+        public long Id { get; set; }
+    }
+
+    public class NewGoodsSubModel
+    {
+        public long Id { get; set; }
+    }
+
+    /// <summary>
+    /// 商品禁用通知
+    /// </summary>
+    public class GoodsDisabledModel : CommonSubModel
+    {
+        /// <summary>
+        /// 商品id
+        /// </summary>
+        public long GoodsId { get; set; }
+        /// <summary>
+        /// 商品描述
+        /// </summary>
+        public string GoodsDesc { get; set; }
+        /// <summary>
+        /// 商品主图
+        /// </summary>
+        public string CoverImg { get; set; }
+    }
+
+    public class CommonWithOrderSubModel : CommonSubModel
+    {
+        public long OrderId { get; set; }
+    }
+    
+    public class CommonWithMallBillSubModel : CommonSubModel
+    {
+        public long BillId { get; set; }
+    }
+
+    public class UECommonPubAccountModel : CommonSubModel
+    {
+        /// <summary>
+        /// 公众推送指定系统用户id
+        /// </summary>
+        public List<int> SysUserIds { get; set; } = new List<int>();
+
+        /// <summary>
+        /// 公众号消息内容
+        /// </summary>
+        public string PubAccountMessage { get; set; }
+
+        /// <summary>
+        /// 消息点击跳转链接
+        /// </summary>
+        public string PubAccountPath { get; set; }
+    }
+    
+    public class UEPostOrderModel : UECommonPubAccountModel
+    {
+        public long OrderId { get; set; }
+    }
+
+    public class UEPostSaleOrderModel : UECommonPubAccountModel
+    {
+        public long OrderId { get; set; }
+        public long SaleOrderId { get; set; }
+    }
+    
+    public class UEHangSaleOrderModel : UECommonPubAccountModel
+    {
+        public long OrderId { get; set; }
+    }
+    
+}

+ 25 - 0
JiaZhiQuan.Common/Messaging/Models/PostAuthModel.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum PostAuthAction
+    {
+        START = 1, // 开始审核
+        UPLOAD = 2, // 上传并转码完成
+    }
+
+    public class PostAuthModel
+    {
+        public long PostId { get; set; }
+
+        public PostAuthAction Action { get; set; }
+        public string VideoId { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Post_Auth_Msg";
+        }
+    }
+}

+ 51 - 0
JiaZhiQuan.Common/Messaging/Models/SendMessageToClientModel.cs

@@ -0,0 +1,51 @@
+using JiaZhiQuan.Common.Hubs;
+using System.Collections.Generic;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    /// <summary>
+    /// 发送信息到客户端
+    /// </summary>
+    public class SendMessageToClientModel
+    {
+        /// <summary>
+        /// 消息类型
+        /// </summary>
+        public SendMessageType MessageType { get; set; }
+
+        /// <summary>
+        /// 消息内容
+        /// SendMessageType.Private: List<PrivateMessage>, 批量私发
+        /// SendMessageType.All: string, 像所有用户发送的内容
+        /// </summary>
+        public string Content { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Send_Message_Client";
+        }
+    }
+
+    /// <summary>
+    /// 私发消息的内容
+    /// </summary>
+    public class PrivateMessage
+    {
+        public long UserId { get; set; }
+
+        public ServerResultDTO Message { get; set; }
+    }
+
+    public enum SendMessageType
+    {
+        /// <summary>
+        /// 私发
+        /// </summary>
+        Private,
+
+        /// <summary>
+        /// 全部
+        /// </summary>
+        All
+    }
+}

+ 224 - 0
JiaZhiQuan.Common/Messaging/Models/StatisticActionModel.cs

@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JiaZhiQuan.Common.Messaging.Models
+{
+    public enum StatisticActionType
+    {
+        /// <summary>
+        /// **已废弃,使用POST_VIEW_COUNT。如果传入 用户Id时,则将插入浏览记录,并且当类别是动态时更新用户的标签画像
+        /// </summary>
+        POST_VIEW,
+
+        POST_RECOMMEND,
+
+        /// <summary>
+        /// 当某一个用户的粉丝量变化时(用来同步粉丝数量到ES)
+        /// </summary>
+        USER_FANS_CHANGE,
+
+        /// <summary>
+        /// 整体更新用户的获赞数量
+        /// </summary>
+        UPDATE_THUMBSUP_USER,
+        /// <summary>
+        /// 整体更新动态的获赞数量
+        /// </summary>
+        UPDATE_THUMBSUP_POST,
+
+        /// <summary>
+        /// **已废弃,使用POST_VIEW_COUNT。更新用户的标签数据
+        /// </summary>
+        UPDATE_TAG_USER,
+
+        /// <summary>
+        /// 统计文章的阅读次数
+        /// </summary>
+        POST_VIEW_COUNT,
+
+        /// <summary>
+        /// 统计有效的分享数量
+        /// </summary>
+        POST_SHARE_COUNT,
+
+        /// <summary>
+        /// 用户个人主页访问次数
+        /// </summary>
+        USER_PERSONAL_PAGE_VIEW_COUNT,
+        
+        /// <summary>
+        /// 用户省变更检测
+        /// </summary>
+        USER_PROVINCE_CHECK,
+        
+        /// <summary>
+        /// 当某一批用户的粉丝量变化时(用来同步粉丝数量到ES)
+        /// </summary>
+        USER_FANS_CHANGE_BATCH,
+        
+        /// <summary>
+        /// 商品推荐
+        /// </summary>
+        GOODS_RECOMMEND,
+
+        /// <summary>
+        /// 商品推荐
+        /// </summary>
+        GOODS_RECOMMEND_SCORE,
+
+        /// <summary>
+        /// IM,保存会话最后一条消息的id
+        /// </summary>
+        IM_CHAT_LASTMESSAGE,
+    }
+
+    public class StatisticActionModel
+    {
+        public StatisticActionType Type { get; set; }
+
+        public string Content { get; set; }
+
+        public static string GetMsgKey()
+        {
+            return "JZQ_Statistic_Action_Msg";
+        }
+    }
+
+    public class SPostViewCountSubModel
+    {
+        public long PostId { get; set; }
+        /// <summary>
+        /// 是否是粉丝
+        /// </summary>
+        public bool IsFan { get; set; }
+        public bool IsValid { get; set; }
+        public long UserId { get; set; }
+        public string IP { get; set; }
+        public int CategoryType { get; set; }
+        public string ClientId { get; set; }
+        public DateTime CreateAt { get; set; }
+    }
+
+    public class SPostShareCountSubModel
+    {
+        public long PostId { get; set; }
+        public long UserId { get; set; }
+        public string IP { get; set; }
+        public string ClientId { get; set; }
+        public DateTime CreateAt { get; set; }
+    }
+
+    public class SUserPersonalPageViewCountSubModel
+    {
+        public long PageUserId { get; set; }
+        public long UserId { get; set; }
+        public string IP { get; set; }
+        public string ClientId { get; set; }
+        public DateTime CreateAt { get; set; }
+    }
+
+    //public class SPostViewSubModel
+    //{
+    //    public long PostId { get; set; }
+    //    public long UserId { get; set; }
+    //    /// <summary>
+    //    /// 0 资讯 1 动态/笔记 2 研报
+    //    /// </summary>
+    //    public int Type { get; set; }
+    //    /// <summary>
+    //    /// 查看次数
+    //    /// </summary>
+    //    public int Count { get; set; } = 1;
+    //    public bool IsFan { get; set; }
+    //}
+
+    // 暂时去除
+    //public class SUserPostTagSubModel
+    //{
+    //    public long PostId { get; set; }
+    //    public long UserId { get; set; }
+    //    /// <summary>
+    //    /// 浏览为1,点赞为5,收藏为8
+    //    /// </summary>
+    //    public int Weight { get; set; }
+    //}
+
+    public class SPostRecommendSubModel
+    {
+        /// <summary>
+        /// 是否将推荐记录到数据库,用于Filter的定时移除
+        /// </summary>
+        public bool InsertIntoRecommend { get; set; }
+        public long UserId { get; set; }
+        /// <summary>
+        /// 如果需要插入到BloomFilter中,如果登录情况下不传,如果未登录,则需要传客户端的GUID
+        /// </summary>
+        public string ClientId { get; set; }
+        public IList<long> PostIds { get; set; }
+    }
+
+    public class SGoodsRecommendSubModel
+    {
+        /// <summary>
+        /// 是否将推荐记录到数据库,用于Filter的定时移除
+        /// </summary>
+        public bool InsertIntoRecommend { get; set; }
+        public long UserId { get; set; }
+        /// <summary>
+        /// 如果需要插入到BloomFilter中,如果登录情况下不传,如果未登录,则需要传客户端的GUID
+        /// </summary>
+        public string ClientId { get; set; }
+        public IList<long> GoodsIds { get; set; }
+    }
+
+    /// <summary>
+    /// 计算推荐分消息体
+    /// </summary>
+    public class RecommendScoreModel {
+        /// <summary>
+        /// 商品id
+        /// </summary>
+        public List<long> goodsIds { get; set; }
+        /// <summary>
+        /// 卖家用户id
+        /// </summary>
+        public long sellerId { get; set; }
+        /// <summary>
+        /// 来源 1寄售,2挂售
+        /// </summary>
+        public int source { get; set; }
+    }
+
+    public class SUserFansCountModel
+    {
+        public long UserId { get; set; }
+    }
+
+    public class SUserIdListModel
+    {
+        public List<long> UserIds { get; set; }
+    }
+
+    public class SPostIdListModel
+    {
+        public List<long> PostIds { get; set; }
+    }
+
+    public class SUserProvinceCheckModel
+    {
+        /// <summary>
+        /// Key为用户编号,值为IP
+        /// </summary>
+        public List<KeyValuePair<long, string>> DataList { get; set; }
+    }
+
+    public class SIMChatLastMessageModel
+    {
+        public long ChatId { get; set; }
+
+        public long MessageId { get; set; }
+
+        public DateTime SendTime { get; set; }
+    }
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott