xf 1 년 전
커밋
a4282ad580
31개의 변경된 파일2408개의 추가작업 그리고 0개의 파일을 삭제
  1. 63 0
      .gitattributes
  2. 344 0
      .gitignore
  3. 72 0
      DataSharing.sln
  4. 7 0
      NuGet.Config
  5. 15 0
      src/DataSharing.Application/ApplicationStartupExtensions.cs
  6. 18 0
      src/DataSharing.Application/DataSharing.Application.csproj
  7. 19 0
      src/DataSharing.Application/Mappers/MapperConfigs.cs
  8. 41 0
      src/DataSharing.Application/Province/ProvinceReceiver.cs
  9. 36 0
      src/DataSharing.Application/Services/SendTaskHandler.cs
  10. 29 0
      src/DataSharing.Host/DataSharing.Host.csproj
  11. 49 0
      src/DataSharing.Host/Program.cs
  12. 31 0
      src/DataSharing.Host/Properties/launchSettings.json
  13. 120 0
      src/DataSharing.Host/StartupExtensions.cs
  14. 218 0
      src/DataSharing.Host/StartupHelper.cs
  15. 182 0
      src/DataSharing.Host/config/appsettings.Development.json
  16. 76 0
      src/DataSharing.Host/config/appsettings.json
  17. 74 0
      src/DataSharing.Host/config/appsettings.shared.Development.json
  18. 74 0
      src/DataSharing.Host/config/appsettings.shared.json
  19. 324 0
      src/DataSharing.Repository/BaseRepository.cs
  20. 17 0
      src/DataSharing.Repository/DataSharing.Repository.csproj
  21. 7 0
      src/DataSharing.Repository/DataSharingDbContext.cs
  22. 113 0
      src/DataSharing.Repository/Extensions/SqlSugarExtensions.cs
  23. 24 0
      src/DataSharing.Repository/Extensions/SqlSugarRepositoryExtensions.cs
  24. 282 0
      src/DataSharing.Repository/Extensions/SqlSugarStartupExtensions.cs
  25. 9 0
      src/DataSharing.Share/DataSharing.Share.csproj
  26. 6 0
      src/DataSharing.Share/Requests/BatchRemoveDto.cs
  27. 31 0
      src/DataSharing.Share/Requests/PagedKeywordRequest.cs
  28. 11 0
      src/DataSharing.Share/Requests/PagedRequest.cs
  29. 25 0
      src/DataSharing/DataSharing.csproj
  30. 28 0
      src/DataSharing/DsOrder.cs
  31. 63 0
      src/DataSharing/DsSendTask.cs

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain

+ 344 - 0
.gitignore

@@ -0,0 +1,344 @@
+## 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
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+*.Comments.xml
+document.xml
+Document.xml
+
+# 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
+
+# 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/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.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*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[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
+
+# 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/
+
+# NuGet Packages
+*.nupkg
+# 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
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# 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
+*- Backup*.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/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# 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

+ 72 - 0
DataSharing.sln

@@ -0,0 +1,72 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.8.34330.188
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4B93E463-3EEC-431F-8297-4C9EB662F3A1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8906A12B-6B82-4904-A13D-786B06D665EE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataSharing", "src\DataSharing\DataSharing.csproj", "{97D6D7EC-42EB-4ADE-96E3-4596594443B0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01_Infrastructure", "01_Infrastructure", "{487B598E-9C72-45F0-8708-A532A4289EB6}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02_Domain", "02_Domain", "{E4B0553C-3284-481B-9E90-F5025D98C4AA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03_Application", "03_Application", "{809EA935-FD2A-48FB-9F53-37543F88BED4}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04_Presentation", "04_Presentation", "{C243D2BB-93F3-4327-9E0C-D59BBA5A258A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataSharing.Host", "src\DataSharing.Host\DataSharing.Host.csproj", "{C813C9AA-0FD3-4331-AE7E-534D39B4E766}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataSharing.Application", "src\DataSharing.Application\DataSharing.Application.csproj", "{E0077D7B-C21C-4864-8A39-155E6C3A5B90}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataSharing.Repository", "src\DataSharing.Repository\DataSharing.Repository.csproj", "{DB54E979-4AF6-4C63-BE97-49466A1CDDEF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataSharing.Share", "src\DataSharing.Share\DataSharing.Share.csproj", "{022AA8CA-42ED-4310-A567-F540D7B2AFA3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{97D6D7EC-42EB-4ADE-96E3-4596594443B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{97D6D7EC-42EB-4ADE-96E3-4596594443B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{97D6D7EC-42EB-4ADE-96E3-4596594443B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{97D6D7EC-42EB-4ADE-96E3-4596594443B0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C813C9AA-0FD3-4331-AE7E-534D39B4E766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C813C9AA-0FD3-4331-AE7E-534D39B4E766}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C813C9AA-0FD3-4331-AE7E-534D39B4E766}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C813C9AA-0FD3-4331-AE7E-534D39B4E766}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E0077D7B-C21C-4864-8A39-155E6C3A5B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E0077D7B-C21C-4864-8A39-155E6C3A5B90}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E0077D7B-C21C-4864-8A39-155E6C3A5B90}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E0077D7B-C21C-4864-8A39-155E6C3A5B90}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DB54E979-4AF6-4C63-BE97-49466A1CDDEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DB54E979-4AF6-4C63-BE97-49466A1CDDEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DB54E979-4AF6-4C63-BE97-49466A1CDDEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DB54E979-4AF6-4C63-BE97-49466A1CDDEF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{022AA8CA-42ED-4310-A567-F540D7B2AFA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{022AA8CA-42ED-4310-A567-F540D7B2AFA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{022AA8CA-42ED-4310-A567-F540D7B2AFA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{022AA8CA-42ED-4310-A567-F540D7B2AFA3}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{97D6D7EC-42EB-4ADE-96E3-4596594443B0} = {E4B0553C-3284-481B-9E90-F5025D98C4AA}
+		{487B598E-9C72-45F0-8708-A532A4289EB6} = {4B93E463-3EEC-431F-8297-4C9EB662F3A1}
+		{E4B0553C-3284-481B-9E90-F5025D98C4AA} = {4B93E463-3EEC-431F-8297-4C9EB662F3A1}
+		{809EA935-FD2A-48FB-9F53-37543F88BED4} = {4B93E463-3EEC-431F-8297-4C9EB662F3A1}
+		{C243D2BB-93F3-4327-9E0C-D59BBA5A258A} = {4B93E463-3EEC-431F-8297-4C9EB662F3A1}
+		{C813C9AA-0FD3-4331-AE7E-534D39B4E766} = {C243D2BB-93F3-4327-9E0C-D59BBA5A258A}
+		{E0077D7B-C21C-4864-8A39-155E6C3A5B90} = {809EA935-FD2A-48FB-9F53-37543F88BED4}
+		{DB54E979-4AF6-4C63-BE97-49466A1CDDEF} = {487B598E-9C72-45F0-8708-A532A4289EB6}
+		{022AA8CA-42ED-4310-A567-F540D7B2AFA3} = {E4B0553C-3284-481B-9E90-F5025D98C4AA}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1866F49D-D504-4570-867E-2EF1A18B57FE}
+	EndGlobalSection
+EndGlobal

+ 7 - 0
NuGet.Config

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
+    <add key="fengwo.org" value="http://nuget.12345lm.cn/v3/index.json" />
+  </packageSources>
+</configuration>

+ 15 - 0
src/DataSharing.Application/ApplicationStartupExtensions.cs

@@ -0,0 +1,15 @@
+using DataSharing.Application.Mappers;
+using Mapster;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Hotline.Application
+{
+    public static class ApplicationStartupExtensions
+    {
+        public static IServiceCollection AddApplication(this IServiceCollection services)
+        {
+            TypeAdapterConfig.GlobalSettings.Scan(typeof(MapperConfigs).Assembly);
+            return services;
+        }
+    }
+}

+ 18 - 0
src/DataSharing.Application/DataSharing.Application.csproj

@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Hotline.Share" Version="1.0.36" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DataSharing.Repository\DataSharing.Repository.csproj" />
+    <ProjectReference Include="..\DataSharing\DataSharing.csproj" />
+  </ItemGroup>
+
+</Project>

+ 19 - 0
src/DataSharing.Application/Mappers/MapperConfigs.cs

@@ -0,0 +1,19 @@
+using Mapster;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Share.Dtos.Order;
+
+namespace DataSharing.Application.Mappers
+{
+    public class MapperConfigs : IRegister
+    {
+        public void Register(TypeAdapterConfig config)
+        {
+
+        }
+    }
+
+}

+ 41 - 0
src/DataSharing.Application/Province/ProvinceReceiver.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using DotNetCore.CAP;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Mq;
+using MapsterMapper;
+using Microsoft.Extensions.Logging;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace DataSharing.Application.Province
+{
+    public class ProvinceReceiver : ICapSubscribe, IScopeDependency
+    {
+        private readonly IRepository<DsOrder> _orderRepository;
+        private readonly IMapper _mapper;
+        private readonly ILogger<ProvinceReceiver> _logger;
+
+        public ProvinceReceiver(
+            IRepository<DsOrder> orderRepository,
+            IMapper mapper,
+            ILogger<ProvinceReceiver> logger)
+        {
+            _orderRepository = orderRepository;
+            _mapper = mapper;
+            _logger = logger;
+        }
+
+        [CapSubscribe(EventNames.HotlineOrderFlowStarted)]
+        public async Task AddOrderAsync(OrderDto order, CancellationToken cancellationToken)
+        {
+            var dsOrder = _mapper.Map<DsOrder>(order);
+            dsOrder.Data = System.Text.Json.JsonSerializer.Serialize(order);
+            await _orderRepository.AddAsync(dsOrder, cancellationToken);
+        }
+        
+    }
+}

+ 36 - 0
src/DataSharing.Application/Services/SendTaskHandler.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+
+namespace DataSharing.Application.Services
+{
+    public class SendTaskHandler : ISendTaskHandler
+    {
+        public async Task SendAsync(DsSendTask sendTask, CancellationToken cancellationToken)
+        {
+
+        }
+    }
+
+    public interface ISendTaskHandler
+    {
+        Task SendAsync(DsSendTask sendTask, CancellationToken cancellationToken);
+    }
+
+    public class SendTaskService : BackgroundService
+    {
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            var count = 0;
+            while (!stoppingToken.IsCancellationRequested)
+            {
+                
+
+                await Task.Delay(1000, stoppingToken);
+            }
+        }
+    }
+}

+ 29 - 0
src/DataSharing.Host/DataSharing.Host.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.13" />
+    <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
+    <PackageReference Include="Fw.Utility.Client" Version="1.0.0" />
+    <PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.9" />
+    <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="7.0.14" />
+    <PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.1.0" />
+    <PackageReference Include="Serilog.Sinks.MongoDB" Version="5.3.1" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Controllers\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DataSharing.Application\DataSharing.Application.csproj" />
+  </ItemGroup>
+
+</Project>

+ 49 - 0
src/DataSharing.Host/Program.cs

@@ -0,0 +1,49 @@
+using DataSharing.Host;
+using Serilog;
+
+Log.Logger = new LoggerConfiguration()
+    .WriteTo.Console()
+    .CreateBootstrapLogger();
+
+try
+{
+    Log.Information("data sharing service is Starting up");
+
+    var builder = WebApplication.CreateBuilder(args);
+
+    builder.Host
+        .ConfigureAppConfiguration((hostBuilderContext, configBuilder) =>
+        {
+            var path = Path.Combine(Directory.GetCurrentDirectory(), "config");
+            configBuilder.SetBasePath(path)
+#if DEBUG
+                .AddJsonFile("appsettings.shared.Development.json", true, true)
+#else
+                .AddJsonFile("appsettings.shared.json", true, true)
+#endif
+                .AddJsonFile("appsettings.json", false, true)
+                .AddJsonFile($"appsettings.{hostBuilderContext.HostingEnvironment.EnvironmentName}.json", true, true)
+                .AddEnvironmentVariables()
+                .AddCommandLine(args)
+                ;
+        })
+        .UseSerilog((ctx, lc) => lc
+            //.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}")
+            .Enrich.FromLogContext()
+            .ReadFrom.Configuration(ctx.Configuration))
+        ;
+
+    builder
+        .ConfigureServices()
+        .ConfigurePipelines()
+        .Run();
+}
+catch (Exception ex)
+{
+    Log.Fatal(ex, "Unhandled exception");
+}
+finally
+{
+    Log.Information("Shut down complete");
+    Log.CloseAndFlush();
+}

+ 31 - 0
src/DataSharing.Host/Properties/launchSettings.json

@@ -0,0 +1,31 @@
+{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:47038",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:5026",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 120 - 0
src/DataSharing.Host/StartupExtensions.cs

@@ -0,0 +1,120 @@
+using DataSharing.Repository.Extensions;
+using FluentValidation;
+using FluentValidation.AspNetCore;
+using Hotline.Application;
+using Mapster;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Serilog;
+using XF.Domain.Dependency;
+using XF.Domain.Filters;
+using XF.Domain.Options;
+using XF.EasyCaching;
+using XF.Utility.MQ;
+
+namespace DataSharing.Host;
+
+internal static class StartupExtensions
+{
+    const string CorsOrigins = "CorsOrigins";
+    internal static WebApplication ConfigureServices(this WebApplicationBuilder builder)
+    {
+        var services = builder.Services;
+        var configuration = builder.Configuration;
+
+        services.AddHttpContextAccessor();
+
+#if DEBUG
+        builder.WebHost.UseUrls("http://*:50105");
+#endif
+
+        // Add services to the container.
+        services
+            .BatchInjectServices()
+            .RegisterRepository()
+            .AddApplication()
+            ;
+
+        //Authentication
+        services.RegisterAuthentication(configuration);
+
+        services.AddControllers(options =>
+            {
+                options.Filters.Add<UnifyResponseFilter>();
+                options.Filters.Add<UserFriendlyExceptionFilter>();
+            })
+            ;
+
+        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+        services.AddEndpointsApiExplorer();
+
+        //swagger
+        services.RegisterSwagger();
+
+        //signalR
+        services.RegisterSignalR(configuration);
+
+        /* CORS */
+        services.RegisterCors(configuration, CorsOrigins);
+
+        //mapster
+        services.RegisterMapper();
+
+        //mediatr
+        services.AddMediatR(d =>
+        {
+            d.RegisterServicesFromAssembly(typeof(ApplicationStartupExtensions).Assembly);
+        });
+
+        //sqlsugar
+        services.AddSqlSugar(configuration);
+
+        //cache
+        services.AddCache(d =>
+            {
+                var cacheConfig = configuration.GetSection("Cache").Get<CacheOptions>();
+                cacheConfig.Adapt(d);
+                d.Prefix = "DataSharing";
+                d.TopicName = "Dsharing-topic";
+            });
+
+        //validator
+        services.AddFluentValidationAutoValidation(config =>
+        {
+            config.DisableDataAnnotationsValidation = true;
+        })
+            .AddValidatorsFromAssembly(typeof(ApplicationStartupExtensions).Assembly);
+
+        //mq
+        services.AddMq(configuration);
+
+        //services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
+        //services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
+        
+        return builder.Build();
+    }
+
+    internal static WebApplication ConfigurePipelines(this WebApplication app)
+    {
+        app.UseSerilogRequestLogging();
+
+        // Configure the HTTP request pipeline.
+        var swaggerEnable = app.Configuration.GetSection("Swagger").Get<bool>();
+        if (swaggerEnable)
+        {
+            app.UseSwagger();
+            app.UseSwaggerUI();
+        }
+
+        app.UseCors(CorsOrigins);
+
+        app.UseAuthentication();
+        app.UseAuthorization();
+
+        app.MapControllers()
+            .RequireAuthorization();
+        //app.MapSubscribeHandler();
+
+        return app;
+    }
+}

+ 218 - 0
src/DataSharing.Host/StartupHelper.cs

@@ -0,0 +1,218 @@
+using System.Text;
+using DataSharing.Repository;
+using Mapster;
+using MapsterMapper;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
+using XF.Domain.Entities;
+using XF.Domain.Exceptions;
+using XF.Domain.Options;
+using XF.Domain.Repository;
+
+namespace DataSharing.Host
+{
+    public static class StartupHelper
+    {
+        /// <summary>
+        /// Authentication
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="configuration"></param>
+        /// <returns></returns>
+        public static IServiceCollection RegisterAuthentication(this IServiceCollection services, ConfigurationManager configuration)
+        {
+            //JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
+            //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+            //    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, d =>
+            //    {
+            //        d.Authority = identityConfigs.IdentityUrl;
+            //        d.RequireHttpsMetadata = false;
+            //        d.TokenValidationParameters = new TokenValidationParameters
+            //        {
+            //            ValidateAudience = false
+            //        };
+            //        //d.Audience = "hotline_api";
+
+            //        d.Events = new JwtBearerEvents
+            //        {
+            //            OnMessageReceived = context =>
+            //            {
+            //                var accessToken = context.Request.Query["access_token"];
+
+            //                // If the request is for our hub...
+            //                var path = context.HttpContext.Request.Path;
+            //                if (!string.IsNullOrEmpty(accessToken) &&
+            //                    (path.StartsWithSegments("/hubs/callcenter")))
+            //                {
+            //                    // Read the token out of the query string
+            //                    context.Token = accessToken;
+            //                }
+            //                return Task.CompletedTask;
+            //            }
+            //        };
+            //    });
+
+            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(d =>
+                {
+                    var jwtOptions = configuration.GetSection("IdentityConfiguration").Get<IdentityConfiguration>().Jwt;
+                    byte[] bytes = Encoding.UTF8.GetBytes(jwtOptions.SecretKey);
+                    var secKey = new SymmetricSecurityKey(bytes);
+                    d.TokenValidationParameters = new()
+                    {
+                        ValidateIssuer = false,
+                        ValidateAudience = false,
+                        ValidateLifetime = true,
+                        ValidateIssuerSigningKey = true,
+                        IssuerSigningKey = secKey,
+                    };
+
+                    //d.Audience = "hotline_api";
+                    d.Events = new JwtBearerEvents
+                    {
+                        OnMessageReceived = context =>
+                        {
+                            var accessToken = context.Request.Query["access_token"];
+
+                            // If the request is for our hub...
+                            var path = context.HttpContext.Request.Path;
+                            if (!string.IsNullOrEmpty(accessToken) &&
+                                (path.StartsWithSegments("/hubs/hotline")))
+                            {
+                                // Read the token out of the query string
+                                context.Token = accessToken;
+                            }
+                            return Task.CompletedTask;
+                        }
+                    };
+                })
+                ;
+
+            return services;
+        }
+
+        /// <summary>
+        /// Swagger
+        /// </summary>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        public static IServiceCollection RegisterSwagger(this IServiceCollection services)
+        {
+            services.AddSwaggerGen(c =>
+            {
+                //添加文档
+                c.SwaggerDoc("v1", new OpenApiInfo() { Title = "Hotline Api", Version = "v1.0", Description = "城市热线api" });
+                var files = Directory.GetFiles(AppContext.BaseDirectory).Where(d => d.EndsWith(".xml"));
+                foreach (var file in files)
+                {
+                    c.IncludeXmlComments(file, true);
+                }
+
+                var scheme = new OpenApiSecurityScheme()
+                {
+                    Description = "Authorization header. \r\nExample: 'Bearer ***'",
+                    Reference = new OpenApiReference
+                    {
+                        Type = ReferenceType.SecurityScheme,
+                        Id = "Authorization"
+                    },
+                    Scheme = "oauth2",
+                    Name = "Authorization",
+                    In = ParameterLocation.Header,
+                    Type = SecuritySchemeType.ApiKey,
+                };
+                c.AddSecurityDefinition("Authorization", scheme);
+                var requirement = new OpenApiSecurityRequirement();
+                requirement[scheme] = new List<string>();
+                c.AddSecurityRequirement(requirement);
+            });
+
+            return services;
+        }
+
+        /// <summary>
+        /// Cors
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="configuration"></param>
+        /// <param name="corsOrigins"></param>
+        /// <returns></returns>
+        public static IServiceCollection RegisterCors(this IServiceCollection services, ConfigurationManager configuration, string corsOrigins)
+        {
+            services.AddCors(options =>
+            {
+                options.AddPolicy(name: corsOrigins,
+                    builder =>
+                    {
+                        var origins = configuration.GetSection("Cors:Origins").Get<string[]>();
+                        builder.SetIsOriginAllowed(a =>
+                            {
+                                return origins.Any(origin => origin.StartsWith("*.", StringComparison.Ordinal)
+                                    ? a.EndsWith(origin[1..], StringComparison.Ordinal)
+                                    : a.Equals(origin, StringComparison.Ordinal));
+                            })
+                            .AllowAnyHeader()
+                            .AllowAnyMethod()
+                            .AllowCredentials();
+                    });
+            });
+
+            return services;
+        }
+
+        /// <summary>
+        /// Mapper
+        /// </summary>
+        /// <param name="services"></param>
+        /// <returns></returns>
+        public static IServiceCollection RegisterMapper(this IServiceCollection services)
+        {
+            var config = TypeAdapterConfig.GlobalSettings;
+            config.ForDestinationType<IDataPermission>()
+                .Ignore(d => d.CreatorId)
+                .Ignore(d => d.CreatorOrgId)
+                //.Ignore(d => d.CreatorOrgCode)
+                .Ignore(d => d.AreaId);
+            config.ForDestinationType<IWorkflow>()
+                .Ignore(d => d.ExpiredTimeConfigId);
+            config.ForDestinationType<IHasCreationTime>()
+                .Ignore(d => d.CreationTime);
+            config.ForDestinationType<IHasDeletionTime>().Ignore(d => d.DeletionTime);
+            config.ForDestinationType<ISoftDelete>().Ignore(d => d.IsDeleted);
+            config.ForDestinationType<IHasModificationTime>().Ignore(d => d.LastModificationTime);
+            config.ForDestinationType<Entity>().Ignore(d => d.Id);
+
+            services.AddSingleton(config);
+            services.AddScoped<IMapper, ServiceMapper>();
+
+            return services;
+        }
+
+        /// <summary>
+        /// SignalR
+        /// </summary>
+        /// <param name="services"></param>
+        /// <param name="configuration"></param>
+        /// <returns></returns>
+        public static IServiceCollection RegisterSignalR(this IServiceCollection services, ConfigurationManager configuration)
+        {
+            var connectionString = configuration.GetConnectionString("Redis");
+            if (string.IsNullOrEmpty(connectionString))
+                throw new UserFriendlyException("未配置signalR的redis连接");
+            services.AddSignalR().AddStackExchangeRedis(connectionString, options =>
+            {
+                options.Configuration.ChannelPrefix = "Hotline:signalr:";
+            });
+
+            return services;
+        }
+
+        public static IServiceCollection RegisterRepository(this IServiceCollection services)
+        {
+            services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
+
+            return services;
+        }
+    }
+}

+ 182 - 0
src/DataSharing.Host/config/appsettings.Development.json

@@ -0,0 +1,182 @@
+{
+  "AllowedHosts": "*",
+  "ConnectionStrings": {
+    "Hotline": "PORT=5432;DATABASE=datasharing;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "Redis": "110.188.24.182:50179",
+    "MongoDB": "mongodb://192.168.100.121:27017"
+  },
+  "Cache": {
+    "Host": "110.188.24.182",
+    "Port": 50179,
+    //"Password": "fengwo22@@",
+    "Database": 3
+  },
+  "Swagger": true,
+  "Cors": {
+    "Origins": [ "http://localhost:8888", "http://admin.hotline.fw.com", "http://hotline.fw.com" ]
+  },
+  "IdentityConfiguration": {
+    "Password": {
+      "RequiredLength": 8,
+      "RequireNonAlphanumeric": true,
+      "RequireLowercase": true,
+      "RequireUppercase": true
+    },
+    "User": {
+      "RequireUniqueEmail": false
+    },
+    "SignIn": {
+      "RequireConfirmedAccount": false
+    },
+    "Lockout": {
+      "MaxFailedAccessAttempts": 5,
+      "DefaultLockoutTimeSpan": "00:10:00"
+    },
+    "Account": {
+      "DefaultPassword": "Fwkj@789"
+    },
+    "Jwt": {
+      "SecretKey": "e660d04ef1d3410798c953f5d7b8a4e1",
+      "Issuer": "hotline_server",
+      "Audience": "hotline",
+      "Scope": "hotline_api",
+      "Expired": 86400 //seceonds
+    }
+  },
+  "DatabaseConfiguration": {
+    "ApplyDbMigrations": false,
+    "ApplySeed": false
+  },
+  "MqConfiguration": {
+    "DbConnectionString": "PORT=5432;DATABASE=fwmq;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "UseDashBoard": true,
+    "RabbitMq": {
+      "UserName": "dev",
+      "Password": "123456",
+      "HostName": "110.188.24.182",
+      "VirtualHost": "fwt-master"
+    }
+  },
+  "SmsAccountInfo": {
+    "MessageServerUrl": "http://webservice.fway.com.cn:1432/FWebService.asmx/FWay_Service", //短信发送地址
+    "AccountUser": "CS12345", //短信系统账号
+    "AccountPwd": "9EE3899305A8FC97D6146CAC6B802E6F", //短信系统密码
+    "ReturnAccountUser": "fwkj", //短信回传账号
+    "ReturnAccountPwd": "fwkj12" //短信回传密码
+  },
+  "FwClient": {
+    "ClientId": "hotline",
+    "ClientSecret": "08db29cc-0da0-4adf-850c-1b2689bd535d"
+  },
+  "ConfigCenter": {
+    "ServerAddresses": [ "http://110.188.24.28:8848" ],
+    "Namespace": "17503980-9b0d-4d3e-8e35-c842c41fb888", //debug
+    "ServiceName": "hotline"
+  },
+  "ChannelConfiguration": {
+    //省12345配置
+    "Province": {
+      "HuiJu": "http://103.203.219.157/cns-sccthj-job-test/rest/",
+      "XieTong": "http://103.203.219.157/cns-scxthj-rest-test/rest/",
+      "ClientId": "6384f475-2e1e-4985-9e34-51a3379452d0",
+      "ClientSecret": "3e92b698-d640-4056-be94-128710ac1a7e"
+    },
+    //企业服务
+    "Enterprise": {
+      "AddressUrl": "http://10.12.185.227:8834/",
+      "ClientId": "1462598736",
+      "ClientSecret": "6nZtVK4rKfnsncGymUHB",
+      "TenantId": "000000"
+    },
+    //市州数据交换
+    "CityHandOver": {
+      "SecretKey": "AA9FF92A-5040-442A-BDFF-A50AD536BF3D",
+      "SendCityName": "宜宾",
+      "ReceiveCityName": "泸州",
+      "BaseUrl": "http://localhost:6028/",
+      "UrlAddress": "CityHandOver.asmx/FlowWrite"
+    },
+    //融媒体
+    "MediaCode": {
+      "MediaCode": "FWYB0828"
+    },
+    //系统市州编码
+    "CityCode": {
+      "AreaCode": "511500"
+    },
+    "WebPortal": {
+     // "SystemSettingsTheme": "class=gray2",
+      "SystemSettingsTheme": ""
+    },
+    //业务系统附件上传配置
+    "BusinessFile": {
+      "BaseUrl": "http://open.fs.12345lm.cn/",
+      "UploadUrlAddress": "file/upload",
+      "DownloadUrlAddress": "file/downloadfile",
+      "Source": "数据共享系统"
+    },
+    //110对接
+    "PoliceDS": {
+      //1、非警情分流推送服务_宜宾市
+      //   receive-工单受理
+      //   http://10.12.185.168:8001/service/api/ds/110To12345/chainAlarm
+      "token1_token": "b8aae0a998f5b79c9a35aecb888e1a58",
+      "token1_dcsm": "c9bc4e718d1917a9a68add90fecbe5bb60920e5ab85d9ecb6a6167db4352f42b8ae21ac67a6e2aab48b4c99cd9f93ec5fb017e202df969a91f74456c14e8770a",
+      "token1_sm2_public": "BS/H9JVlRdo8vbsZYQLTkeGGZBVjdkX+VJ82CX7n6i4NubmynRIaxvzoSsEAhbbvTDGm2DS96l95nK6Dkd0UZg==",
+      "token1_sm2_private": "GbjU4GFk0yaa/wTdzxeh5BOh8VNlqvnTcb7EUtDVvOY=",
+      "token1_sm4": "BKrW/v4jeRgsFg3HSbxEKnDi6rPceW0AdRiaa1rhEwAnraf8MnHdXzUQoQ7+zyjfghaK5G+zDz+wW+Ob27Jgxt91HkVmyL6+SjqV9ZnqNeGFgTBkQrHDySGz6jHKa12Sv7PZs8pjc716he3NNHZAkCI=",
+      "token1_sm4_mw": "4034d80c19bbd01d",
+
+      //4、警务警情分流推送服务_宜宾市
+      //   receive-工单办结
+      //   http://10.12.185.168:8001/service/api/ds/110To12345/chainDeal
+      "token4_token": "8806bfba29b997853bdb059a9ba9a3ae",
+      "token4_dcsm": "f5dce079e0f4acd6b6627b89fb5e72af5fa5775d3ee3b8c7876f546c5ebe723888df4a70c09f9aa5e096bb342d73e0c4793c851a7a8035e8683b07430f132bd3",
+      "token4_sm2_public": "P2IVWpFx38GQTDV3hgrxjlOdfPhLQNW2LyvAKmYqMz9UYHCtm/l3K73UIouMXs4jcmZjXyItepvKFv44g3YnXA==",
+      "token4_sm2_private": "yxIkRALHoOTxpiZ/jrvCDQatcR7k11Xhps7c92peU9w=",
+      "token4_sm4": "BCD88AXnIfMxe8PrUcubSbFRr07cOuDDEPzy754W3CzhOqjcpAcu1B9B6U46jyM4hEFPqkx+SS1PUAfRlG5tzYD1Z8SKsJTBUDGR6bTMRvCc+C/aps+IcRBfzjjRchtT1c5iok4CfiT4LoK5cmOHKKU=",
+      "token4_sm4_mw": "d731ff1282dda792",
+
+      //3、警务警情分流查询服务_宜宾市
+      //   send-工单受理
+      //   http://10.12.185.168:8001/service/api/ds/12345To110/chainAlarm
+      "token3_token": "b76ba1896c4880998a86b829cf79888a",
+      "token3_dcsm": "3cccc86e021c0ff7827537053ec1b6e4a57cbb49b77c9492257123703c5a6b711000f0842c035fe6d33eb2a947915af53a1ef501916ec7128bff9514d6184e2c",
+      "token3_sm2_public": "qaao4Xh8/eyYGeVOj1K8D7p3+OriP55azWDAbYVoZelMdluNrJuQWM2qPn+hjTHTBnIMAVK2HlHBx4oGfCxGdA==",
+      "token3_sm2_private": "8bSYM8P3b4I94qGt3XVx3bQddNCy/xVKo7o1b5LI4/M=",
+      "token3_sm4": "BIDhFaEu5NILR7byg/JfaPlJEm4dYWC+u9J1IqhtYeYY1AktOxp7cZWqfk/mWjw72pYGT7YRENCULbjZ2bxVG6UUv2pYukZWtYog34Vicu5IgC8ti4VpED9eGzGgtKJ/CT0KtAnjQPQL0PsVbCjTY5M=",
+      "token3_sm4_mw": "bbeb56d247354360",
+
+      //2、非警情分流查询服务_宜宾市
+      //   send-工单办结
+      //   http://10.12.185.168:8001/service/api/ds/12345To110/chainDeal
+      "token2_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token2_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token2_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token2_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token2_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token2_sm4_mw": "2938d7acb2754a09",
+
+      //5、从公安网侧获取12345政务服务热线平台知识库列表
+      //   send-知识库列表
+      //   http://10.12.185.168:8001/service/api/ds/get_knowledge_info
+      "token5_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token5_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token5_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token5_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token5_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token5_sm4_mw": "2938d7acb2754a09",
+
+      //6、从公安网侧获取12345政务服务热线平台知识内容
+      //   send-知识库内容
+      //   http://10.12.185.168:8001/service/api/ds/get_knowledge_content
+      "token6_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token6_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token6_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token6_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token6_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token6_sm4_mw": "2938d7acb2754a09"
+    }
+  },
+
+}

+ 76 - 0
src/DataSharing.Host/config/appsettings.json

@@ -0,0 +1,76 @@
+{
+  "AllowedHosts": "*",
+  "ConnectionStrings": {
+    "Hotline": "PORT=5432;DATABASE=datasharing;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "Redis": "110.188.24.182:50179,password=fengwo22@@",
+    "MongoDB": "mongodb://192.168.100.121:27017"
+  },
+  "Cache": {
+    "Host": "110.188.24.182",
+    "Port": 50179,
+    "Password": "fengwo22@@",
+    "Database": 1
+  },
+  "Swagger": true,
+  "Cors": {
+    "Origins": [ "http://localhost:8888", "http://hotline.12345lm.cn", "http://110.188.24.28:50101", "http://110.188.24.28:50102", "http://localhost:8113", "http://bs.hotline.12345lm.cn" ]
+  },
+  "IdentityConfiguration": {
+    "Password": {
+      "RequiredLength": 8,
+      "RequireNonAlphanumeric": true,
+      "RequireLowercase": true,
+      "RequireUppercase": true
+    },
+    "User": {
+      "RequireUniqueEmail": false
+    },
+    "SignIn": {
+      "RequireConfirmedAccount": false
+    },
+    "Lockout": {
+      "MaxFailedAccessAttempts": 5,
+      "DefaultLockoutTimeSpan": "00:01:00"
+    },
+    "Account": {
+      "DefaultPassword": "Fwkj@789"
+    },
+    "Jwt": {
+      "SecretKey": "e660d04ef1d3410798c953f5d7b8a4e1",
+      "Issuer": "hotline_server",
+      "Audience": "hotline",
+      "Scope": "hotline_api",
+      "Expired": 3600 //seceonds
+    }
+  },
+  "DatabaseConfiguration": {
+    "ApplyDbMigrations": false,
+    "ApplySeed": false
+  },
+  "MqConfiguration": {
+    "DbConnectionString": "PORT=5432;DATABASE=fwmq;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "UseDashBoard": true,
+    "RabbitMq": {
+      "UserName": "dev",
+      "Password": "123456",
+      "HostName": "110.188.24.182",
+      "VirtualHost": "fwt-master"
+    }
+  },
+  "SmsAccountInfo": {
+    "MessageServerUrl": "http://webservice.fway.com.cn:1432/FWebService.asmx/FWay_Service", //短信发送地址
+    "AccountUser": "CS12345", //短信系统账号
+    "AccountPwd": "9EE3899305A8FC97D6146CAC6B802E6F", //短信系统密码
+    "ReturnAccountUser": "fwkj", //短信回传账号
+    "ReturnAccountPwd": "fwkj12" //短信回传密码
+  },
+  "FwClient": {
+    "ClientId": "hotline",
+    "ClientSecret": "08db29cc-0da0-4adf-850c-1b2689bd535d"
+  },
+  "ConfigCenter": {
+    "ServerAddresses": [ "http://110.188.24.28:8848" ],
+    "Namespace": "f5017bc5-af0a-4f85-8e38-6718accc8f36", //dev
+    "ServiceName": "hotline"
+  },
+}

+ 74 - 0
src/DataSharing.Host/config/appsettings.shared.Development.json

@@ -0,0 +1,74 @@
+{
+  "Serilog": {
+    "Using": [
+      "Serilog.Enrichers.Span",
+      "Serilog.Sinks.Console",
+      "Serilog.Sinks.Grafana.Loki"
+    ],
+    "MinimumLevel": {
+      "Default": "Information",
+      "Override": {
+        "Microsoft": "Warning",
+        "Microsoft.Hosting.Lifetime": "Information",
+        "Microsoft.AspNetCore.Authentication": "Debug",
+        "Microsoft.AspNetCore": "Warning",
+        "Microsoft.AspNetCore.SignalR": "Debug",
+        "Microsoft.AspNetCore.Http.Connections": "Debug",
+        "System": "Warning"
+      }
+    },
+    "WriteTo": [
+      {
+        "Name": "Console",
+        "Args": {
+          //"outputTemplate": "time=\"{Timestamp:yyyy-MM-dd HH:mm:ss}\" level={Level:w3} category={SourceContext} trace={TraceId}{NewLine}msg=\"{Message:lj}\"{NewLine}error=\"{Exception}\"{NewLine}",
+          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+          "theme": "Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console"
+        }
+      },
+      //{
+      //  "Name": "GrafanaLoki",
+      //  "Args": {
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+      //    "uri": "http://192.168.100.217:3100",
+      //    "labels": [
+      //      {
+      //        "key": "app",
+      //        "value": "hotline"
+      //      }
+      //    ],
+      //    "propertiesAsLabels": [
+      //      "fwhl"
+      //    ]
+      //  }
+      //}
+      //{
+      //  "Name": "Exeptionless",
+      //  "Args": {
+      //    //"outputTemplate": "time=\"{Timestamp:yyyy-MM-dd HH:mm:ss}\" level={Level:w3} category={SourceContext} trace={TraceId}{NewLine}msg=\"{Message:lj}\"{NewLine}error=\"{Exception}\"{NewLine}",
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+      //    "theme": "Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console"
+      //  }
+      //}
+      //{
+      //  "Name": "File",
+      //  "Args": {
+      //    "path": "logs/log-.txt",
+      //    "rollingInterval": "Day"
+      //  }
+      //},
+      //{
+      //  "Name": "MongoDBBson",
+      //  "Args": {
+      //    "databaseUrl": "mongodb://192.168.100.121:27017/hotline_logs",
+      //    "collectionName": "logs",
+      //    "cappedMaxSizeMb": "1024",
+      //    "cappedMaxDocuments": "50000",
+      //    "rollingInterval": "Day",
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
+      //  }
+      //}
+    ],
+    "Enrich": [ "FromLogContext", "WithSpan" ]
+  }
+}

+ 74 - 0
src/DataSharing.Host/config/appsettings.shared.json

@@ -0,0 +1,74 @@
+{
+  "Serilog": {
+    "Using": [
+      "Serilog.Enrichers.Span",
+      "Serilog.Sinks.Console",
+      "Serilog.Sinks.Grafana.Loki"
+    ],
+    "MinimumLevel": {
+      "Default": "Information",
+      "Override": {
+        "Microsoft": "Warning",
+        "Microsoft.Hosting.Lifetime": "Information",
+        "Microsoft.AspNetCore.Authentication": "Debug",
+        "Microsoft.AspNetCore": "Warning",
+        "Microsoft.AspNetCore.SignalR": "Debug",
+        "Microsoft.AspNetCore.Http.Connections": "Debug",
+        "System": "Warning"
+      }
+    },
+    "WriteTo": [
+      {
+        "Name": "Console",
+        "Args": {
+          //"outputTemplate": "time=\"{Timestamp:yyyy-MM-dd HH:mm:ss}\" level={Level:w3} category={SourceContext} trace={TraceId}{NewLine}msg=\"{Message:lj}\"{NewLine}error=\"{Exception}\"{NewLine}",
+          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+          "theme": "Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console"
+        }
+      },
+      //{
+      //  "Name": "GrafanaLoki",
+      //  "Args": {
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+      //    "uri": "http://192.168.100.217:3100",
+      //    "labels": [
+      //      {
+      //        "key": "app",
+      //        "value": "hotline"
+      //      }
+      //    ],
+      //    "propertiesAsLabels": [
+      //      "fwhl"
+      //    ]
+      //  }
+      //}
+      //{
+      //  "Name": "Exeptionless",
+      //  "Args": {
+      //    //"outputTemplate": "time=\"{Timestamp:yyyy-MM-dd HH:mm:ss}\" level={Level:w3} category={SourceContext} trace={TraceId}{NewLine}msg=\"{Message:lj}\"{NewLine}error=\"{Exception}\"{NewLine}",
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
+      //    "theme": "Serilog.Sinks.SystemConsole.Themes.ConsoleTheme::None, Serilog.Sinks.Console"
+      //  }
+      //}
+      //{
+      //  "Name": "File",
+      //  "Args": {
+      //    "path": "logs/log-.txt",
+      //    "rollingInterval": "Day"
+      //  }
+      //},
+      //{
+      //  "Name": "MongoDBBson",
+      //  "Args": {
+      //    "databaseUrl": "mongodb://192.168.100.121:27017/hotline_logs",
+      //    "collectionName": "logs",
+      //    "cappedMaxSizeMb": "1024",
+      //    "cappedMaxDocuments": "50000",
+      //    "rollingInterval": "Day",
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
+      //  }
+      //}
+    ],
+    "Enrich": [ "FromLogContext", "WithSpan" ]
+  }
+}

+ 324 - 0
src/DataSharing.Repository/BaseRepository.cs

@@ -0,0 +1,324 @@
+using System.Linq.Expressions;
+using SqlSugar;
+using XF.Domain.Entities;
+using XF.Domain.Repository;
+
+namespace DataSharing.Repository
+{
+    public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity<string>, IHasCreationTime, IDataPermission, new()
+    {
+        protected ISugarUnitOfWork<DataSharingDbContext> Uow { get; }
+        protected ISqlSugarClient Db { get; }
+
+        public BaseRepository(ISugarUnitOfWork<DataSharingDbContext> uow)
+        {
+            Uow = uow;
+            Db = uow.Db;
+        }
+
+        public async Task<string> AddAsync(TEntity entity, CancellationToken cancellationToken = default)
+        {
+            var excEntity = await Db.Insertable(entity).ExecuteReturnEntityAsync();
+            return excEntity.Id;
+        }
+
+        /// <summary>
+        /// 批量插入(应用场景:小数据量,超出1万条建议另行实现)
+        /// </summary>
+        /// <param name="entities"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task AddRangeAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
+        {
+            await Db.Insertable(entities).ExecuteCommandAsync(cancellationToken);
+        }
+
+        public async Task RemoveAsync(TEntity entity, bool? soft = false, CancellationToken cancellationToken = default)
+        {
+            if (soft.HasValue && soft.Value)
+            {
+                await Db.Deleteable(entity).IsLogic().ExecuteCommandAsync("IsDeleted", true, "DeletionTime");
+            }
+            else
+            {
+                await Db.Deleteable(entity).ExecuteCommandAsync(cancellationToken);
+            }
+        }
+
+        public async Task RemoveAsync(string id, bool? soft = false, CancellationToken cancellationToken = default)
+        {
+            if (soft.HasValue && soft.Value)
+            {
+                await Db.Deleteable<TEntity>().In(id).IsLogic().ExecuteCommandAsync("IsDeleted", true, "DeletionTime");
+            }
+            else
+            {
+                await Db.Deleteable<TEntity>().In(id).ExecuteCommandAsync(cancellationToken);
+            }
+        }
+
+        public async Task RemoveAsync(Expression<Func<TEntity, bool>> predicate, bool? soft, CancellationToken cancellationToken = default)
+        {
+            if (soft.HasValue && soft.Value)
+            {
+                await Db.Deleteable<TEntity>().Where(predicate).IsLogic().ExecuteCommandAsync("IsDeleted", true, "DeletionTime");
+            }
+            else
+            {
+                await Db.Deleteable<TEntity>().Where(predicate).ExecuteCommandAsync(cancellationToken);
+            }
+        }
+
+        public async Task RemoveRangeAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
+        {
+            await Db.Deleteable<TEntity>(entities).ExecuteCommandAsync(cancellationToken);
+        }
+
+        public async Task RemoveRangeAsync(IEnumerable<TEntity> entities, bool? soft, CancellationToken cancellationToken = default)
+        {
+	        if (soft.HasValue && soft.Value)
+	        {
+		        await Db.Deleteable<TEntity>(entities).IsLogic().ExecuteCommandAsync("IsDeleted", true, "DeletionTime");
+	        }
+	        else
+	        {
+		        await Db.Deleteable<TEntity>(entities).ExecuteCommandAsync(cancellationToken);
+	        }
+        }
+
+		public async Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
+        {
+            await Db.Updateable(entity)
+                .IgnoreColumns(ignoreAllNullColumns: true)
+                .IgnoreColumns(d => d.CreationTime)
+                .ExecuteCommandAsync(cancellationToken);
+        }
+
+        public async Task UpdateRangeAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
+        {
+            await Db.Updateable(entities)
+                .IgnoreColumns(d => d.CreationTime)
+                .ExecuteCommandAsync(cancellationToken);
+        }
+
+        public async Task<TEntity?> GetAsync(string id, CancellationToken cancellationToken = default)
+        {
+            return await Db.Queryable<TEntity>().FirstAsync(d => d.Id == id, cancellationToken);
+        }
+
+        public TEntity Get(string id)
+        {
+            return Db.Queryable<TEntity>().First(d => d.Id == id);
+        }
+
+        public TEntity Get(Expression<Func<TEntity, bool>> predicate)
+        {
+            return Db.Queryable<TEntity>().First(predicate);
+        }
+
+
+        public async Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
+        {
+            return await Db.Queryable<TEntity>().FirstAsync(predicate, cancellationToken);
+        }
+
+        public async Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate, bool isDesc, Expression<Func<TEntity, object>> orderBy, CancellationToken cancellationToken = default)
+        {
+            if (isDesc)
+                return await Db.Queryable<TEntity>().OrderBy(orderBy, OrderByType.Desc).FirstAsync(predicate, cancellationToken);
+            else
+                return await Db.Queryable<TEntity>().OrderBy(orderBy, OrderByType.Asc).FirstAsync(predicate, cancellationToken);
+        }
+
+
+        public async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>>? predicate = null, params (bool isWhere, Expression<Func<TEntity, bool>> expression)[] whereIfs)
+        {
+            var query = Db.Queryable<TEntity>().Where(predicate ??= d => true);
+            if (whereIfs.Any())
+            {
+                foreach (var whereIf in whereIfs)
+                {
+                    query = query.WhereIF(whereIf.isWhere, whereIf.expression);
+                }
+            }
+
+            return await query.ToListAsync();
+        }
+
+        public Task<bool> AnyAsync(CancellationToken cancellationToken = default) => Db.Queryable<TEntity>().AnyAsync();
+
+        public Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) =>
+             Db.Queryable<TEntity>().AnyAsync(predicate, cancellationToken);
+
+        public Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) =>
+             Db.Queryable<TEntity>().CountAsync(predicate, cancellationToken);
+
+        public ISugarQueryable<TEntity> Queryable(bool permissionVerify = false, bool includeDeleted = false)
+        {
+            if (includeDeleted)
+                Db.QueryFilter.Clear();
+
+            var query = Db.Queryable<TEntity>();
+            return query;
+        }
+
+        public IUpdateable<TEntity> Updateable() => Db.Updateable<TEntity>();
+
+        public IDeleteable<TEntity> Removeable() => Db.Deleteable<TEntity>();
+
+        public UpdateNavTaskInit<TEntity, TEntity> UpdateNav(TEntity entity) => Db.UpdateNav(entity);
+
+        public UpdateNavTaskInit<TEntity, TEntity> UpdateNav(TEntity entity, UpdateNavRootOptions options) => Db.UpdateNav(entity, options);
+
+        public UpdateNavTaskInit<TEntity, TEntity> UpdateNav(List<TEntity> entities) => Db.UpdateNav(entities);
+
+        public UpdateNavTaskInit<TEntity, TEntity> UpdateNav(List<TEntity> entities, UpdateNavRootOptions options) => Db.UpdateNav(entities, options);
+
+        public InsertNavTaskInit<TEntity, TEntity> AddNav(TEntity entity)
+        {
+            return Db.InsertNav(entity);
+        }
+
+        public InsertNavTaskInit<TEntity, TEntity> AddNav(TEntity entity, InsertNavRootOptions options)
+        {
+            return Db.InsertNav(entity, options);
+        }
+
+        public InsertNavTaskInit<TEntity, TEntity> AddNav(List<TEntity> entities)
+        {
+            return Db.InsertNav(entities);
+        }
+
+        public InsertNavTaskInit<TEntity, TEntity> AddNav(List<TEntity> entities, InsertNavRootOptions options)
+        {
+            return Db.InsertNav(entities, options);
+        }
+
+        public DeleteNavTaskInit<TEntity, TEntity> RemoveNav(TEntity entity) => Db.DeleteNav(entity);
+        public DeleteNavTaskInit<TEntity, TEntity> RemoveNav(List<TEntity> entities) => Db.DeleteNav(entities);
+
+        public DeleteNavTaskInit<TEntity, TEntity> RemoveNav(Expression<Func<TEntity, bool>> predicate) => Db.DeleteNav(predicate);
+
+        /// <summary>
+        /// 基础分页
+        /// </summary>
+        /// <param name="predicate"></param>
+        /// <param name="orderByCreator"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <param name="permissionVerify"></param>
+        /// <returns></returns>
+        public async Task<(int Total, List<TEntity> Items)> QueryPagedAsync(
+            Expression<Func<TEntity, bool>> predicate,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>> orderByCreator,
+            int pageIndex,
+            int pageSize,
+            bool permissionVerify = false,
+            params (bool isWhere, Expression<Func<TEntity, bool>> expression)[] whereIfs)
+        {
+            RefAsync<int> total = 0;
+            var query = Db.Queryable<TEntity>().Where(predicate);
+
+            if (whereIfs.Any())
+            {
+                foreach (var whereIf in whereIfs)
+                {
+                    query = query.WhereIF(whereIf.isWhere, whereIf.expression);
+                }
+            }
+            var items = await orderByCreator(query).ToPageListAsync(pageIndex, pageSize, total);
+            return (total.Value, items);
+        }
+
+
+        public async Task<(int Total, List<TEntity> Items)> QueryPagedAsync(
+            Expression<Func<TEntity, bool>> predicate,
+            int pageIndex,
+            int pageSize,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>>? includes = null,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>>? orderByCreator = null,
+            bool permissionVerify = false,
+            params (bool isWhere, Expression<Func<TEntity, bool>> expression)[] whereIfs)
+        {
+            RefAsync<int> total = 0;
+            var query = Db.Queryable<TEntity>().Where(predicate);
+
+            if (includes is not null)
+                query = includes(query);
+
+            if (whereIfs.Any())
+            {
+                foreach (var whereIf in whereIfs)
+                {
+                    query = query.WhereIF(whereIf.isWhere, whereIf.expression);
+                }
+            }
+            if (orderByCreator is not null)
+                query = orderByCreator(query);
+
+            var items = await query.ToPageListAsync(pageIndex, pageSize, total);
+            return (total.Value, items);
+        }
+
+        public async Task<List<TEntity>> QueryExtAsync(
+            Expression<Func<TEntity, bool>> predicate,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>>? includes = null,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>>? orderByCreator = null,
+            bool permissionVerify = false,
+            params (bool isWhere, Expression<Func<TEntity, bool>> expression)[] whereIfs)
+        {
+            var query = Db.Queryable<TEntity>().Where(predicate);
+
+            if (includes is not null)
+                query = includes(query);
+
+            if (whereIfs.Any())
+            {
+                foreach (var whereIf in whereIfs)
+                {
+                    query = query.WhereIF(whereIf.isWhere, whereIf.expression);
+                }
+            }
+
+            if (orderByCreator is not null)
+                query = orderByCreator(query);
+
+            return await query.ToListAsync();
+        }
+
+        public async Task<List<TEntity>> QueryExtAsync(
+            Expression<Func<TEntity, bool>> predicate,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>> includes,
+            bool permissionVerify = false)
+        {
+            var query = Db.Queryable<TEntity>().Where(predicate);
+            query = includes(query);
+            return await query.ToListAsync();
+        }
+
+        public async Task<TEntity> GetExtAsync(
+            Expression<Func<TEntity, bool>> predicate,
+            Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>> includes,
+            bool permissionVerify = false)
+        {
+            var query = Db.Queryable<TEntity>();
+            query = includes(query);
+            return await query.FirstAsync(predicate);
+        }
+
+        public async Task<TEntity> GetExtAsync(string id, Func<ISugarQueryable<TEntity>, ISugarQueryable<TEntity>> includes, bool permissionVerify = false)
+        {
+            var query = Db.Queryable<TEntity>();
+            query = includes(query);
+            return await query.FirstAsync(d => d.Id == id);
+        }
+
+        public async Task UpdateAsync(TEntity entity, bool ignoreNullColumns = true, CancellationToken cancellationToken = default)
+        {
+            await Db.Updateable(entity)
+                .IgnoreColumns(ignoreAllNullColumns: ignoreNullColumns)
+                .IgnoreColumns(d => d.CreationTime)
+                .ExecuteCommandAsync(cancellationToken);
+        }
+    }
+}

+ 17 - 0
src/DataSharing.Repository/DataSharing.Repository.csproj

@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.24" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DataSharing\DataSharing.csproj" />
+  </ItemGroup>
+
+</Project>

+ 7 - 0
src/DataSharing.Repository/DataSharingDbContext.cs

@@ -0,0 +1,7 @@
+using SqlSugar;
+
+namespace DataSharing.Repository;
+
+public class DataSharingDbContext : SugarUnitOfWork
+{
+}

+ 113 - 0
src/DataSharing.Repository/Extensions/SqlSugarExtensions.cs

@@ -0,0 +1,113 @@
+using System.Collections;
+using System.Data;
+using System.Reflection;
+using SqlSugar;
+
+namespace DataSharing.Repository.Extensions
+{
+    public static class SqlSugarExtensions
+    {
+        /// <summary>
+        /// List转Dictionary
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="list"></param>
+        /// <returns></returns>
+        public static List<Dictionary<string, object?>> ToDictionary<T>(this List<T> list)
+        {
+            var result = new List<Dictionary<string, object?>>();
+            if (list.Any())
+            {
+                foreach (var item in list)
+                {
+                    Dictionary<string, object?> dc = new();
+                    var properties = item.GetType().GetProperties();
+                    foreach (var property in properties)
+                    {
+                        if (IsIgnoreColumn(property)) continue;
+                        if (IsNavigateColumn(property)) continue;
+                        dc.Add(property.Name, property.GetValue(item));
+                    }
+                    result.Add(dc);
+                }
+            }
+
+            return result;
+        }
+
+        public static DataTable ToDataTable<T>(this List<T> list, string tableName)
+        {
+            var dt = new DataTable();
+            dt.TableName = tableName; //设置表名
+
+            if (list.Any())
+            {
+                PropertyInfo[] properties = list[0].GetType().GetProperties();
+                foreach (PropertyInfo property in properties)
+                {
+                    if (IsIgnoreColumn(property)) continue;
+                    if (IsNavigateColumn(property)) continue;
+                    Type colType = property.PropertyType;
+                    if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
+                    {
+                        colType = colType.GetGenericArguments()[0];
+                    }
+                    dt.Columns.Add(property.Name, colType);
+                }
+
+                foreach (var item in list)
+                {
+                    ArrayList tempList = new();
+                    //var properties = item.GetType().GetProperties();
+                    foreach (var property in properties)
+                    {
+                        if (IsIgnoreColumn(property)) continue;
+                        if (IsNavigateColumn(property)) continue;
+                        var obj = property.GetValue(item, null);
+                        tempList.Add(obj);
+                    }
+                    dt.LoadDataRow(tempList.ToArray(), true);
+                }
+
+                //for (int i = 0; i < list.Count; i++)
+                //{
+                //    ArrayList tempList = new();
+                //    foreach (PropertyInfo pi in propertys)
+                //    {
+                //        if (IsIgnoreColumn(pi))
+                //            continue;
+                //        object obj = pi.GetValue(list[i], null);
+                //        tempList.Add(obj);
+                //    }
+                //    object[] array = tempList.ToArray();
+                //    result.LoadDataRow(array, true);
+                //}
+            }
+
+            //var addRow = dt.NewRow();
+            //addRow["id"] = 0;
+            //addRow["price"] = 1;
+            //addRow["Name"] = "a";
+            //dt.Rows.Add(addRow);//添加数据
+
+            //var x = db.Storageable(dt).WhereColumns("id").ToStorage();//id作为主键
+            //x.AsInsertable.IgnoreColumns("id").ExecuteCommand();//如果是自增要添加IgnoreColumns
+            //x.AsUpdateable.ExecuteCommand();
+            return dt;
+        }
+
+        /// <summary>
+        /// 排除SqlSugar忽略的列
+        /// </summary>
+        /// <param name="pi"></param>
+        /// <returns></returns>
+        private static bool IsIgnoreColumn(PropertyInfo property)
+        {
+            var sc = property.GetCustomAttributes<SugarColumn>(false).FirstOrDefault(u => u.IsIgnore);
+            return sc != null;
+        }
+
+        private static bool IsNavigateColumn(PropertyInfo property) =>
+            property.GetCustomAttributes<Navigate>(false).Any();
+    }
+}

+ 24 - 0
src/DataSharing.Repository/Extensions/SqlSugarRepositoryExtensions.cs

@@ -0,0 +1,24 @@
+using DataSharing.Share.Requests;
+using SqlSugar;
+
+namespace DataSharing.Repository.Extensions
+{
+    public static class SqlSugarRepositoryExtensions
+    {
+        public static async Task<(int Total, List<TEntity> Items)> ToPagedListAsync<TEntity>(this ISugarQueryable<TEntity> query, int pageIndex, int pageSize, CancellationToken cancellationToken = default)
+            where TEntity : class, new()
+        {
+            RefAsync<int> total = 0;
+            var items = await query.ToPageListAsync(pageIndex, pageSize, total);
+            return (total.Value, items);
+        }
+
+        public static async Task<(int Total, List<TEntity> Items)> ToPagedListAsync<TEntity>(this ISugarQueryable<TEntity> query, PagedRequest dto, CancellationToken cancellationToken = default)
+            where TEntity : class, new()
+        {
+            RefAsync<int> total = 0;
+            var items = await query.ToPageListAsync(dto.PageIndex, dto.PageSize, total);
+            return (total.Value, items);
+        }
+    }
+}

+ 282 - 0
src/DataSharing.Repository/Extensions/SqlSugarStartupExtensions.cs

@@ -0,0 +1,282 @@
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Linq.Dynamic.Core;
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using SqlSugar;
+using XF.Domain.Entities;
+using XF.Domain.Extensions;
+using XF.Domain.Options;
+using XF.Domain.Repository;
+using XF.Utility.SequentialId;
+
+namespace DataSharing.Repository.Extensions
+{
+    public static class SqlSugarStartupExtensions
+    {
+        public static void AddSqlSugar(this IServiceCollection services, IConfiguration configuration, string dbName = "datasharing")
+        {
+            //多租户 new SqlSugarScope(List<ConnectionConfig>,db=>{});
+
+            SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
+            {
+                DbType = DbType.PostgreSQL,
+                ConnectionString = configuration.GetConnectionString(dbName),
+                IsAutoCloseConnection = true,
+                ConfigureExternalServices = new ConfigureExternalServices
+                {
+                    EntityService = (property, column) =>
+                    {
+                        var attributes = property.GetCustomAttributes(true); //get all attributes 
+
+                        if (column.PropertyName.ToLower() == "id" ||
+                            attributes.Any(it => it is KeyAttribute)) //是id的设为主键
+                        {
+                            column.IsPrimarykey = true;
+                            column.Length = 36;
+                        }
+
+                        //if (!column.DbColumnName.Contains("_"))
+                        //    column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName);//ToUnderLine驼峰转下划线
+
+                        //column.ColumnDescription = (attributes.FirstOrDefault(d => d is DescriptionAttribute) as DescriptionAttribute)?.Description ?? string.Empty;
+
+                        //统一设置 nullable等于isnullable=true
+                        if (!column.IsPrimarykey && new NullabilityInfoContext().Create(property).WriteState is NullabilityState.Nullable)
+                        {
+                            column.IsNullable = true;
+                        }
+                    },
+                    EntityNameService = (type, entity) =>
+                    {
+                        var attributes = type.GetCustomAttributes(true);
+                        //if (attributes.Any(it => it is TableAttribute))
+                        //{
+                        //    entity.DbTableName = (attributes.First(it => it is TableAttribute) as TableAttribute).UserName;
+                        //}
+
+                        entity.DbTableName = entity.DbTableName.ToSnakeCase();
+
+                        //if (!entity.DbTableName.Contains("_"))
+                        //    entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);//ToUnderLine驼峰转下划线方法
+                        if (attributes.Any(d => d is DescriptionAttribute))
+                        {
+                            entity.TableDescription =
+                                (attributes.First(d => d is DescriptionAttribute) as DescriptionAttribute)
+                                .Description;
+                        }
+                    }
+                },
+                MoreSettings = new ConnMoreSettings
+                {
+                    PgSqlIsAutoToLower = false,//增删查改支持驼峰表
+                    PgSqlIsAutoToLowerCodeFirst = false, // 建表建驼峰表。5.1.3.30 
+                }
+            },
+                SetDbAop
+            );
+
+            ISugarUnitOfWork<DataSharingDbContext> context = new SugarUnitOfWork<DataSharingDbContext>(sqlSugar);
+            services.AddSingleton(context);
+
+            InitDatabase(context, configuration);
+        }
+
+        private static void InitDatabase(ISugarUnitOfWork<DataSharingDbContext> context, IConfiguration configuration)
+        {
+            var dbOptions = configuration.GetSection("DatabaseConfiguration").Get<DatabaseOptions>() ?? new DatabaseOptions();
+            if (dbOptions.ApplyDbMigrations)
+            {
+                context.Db.DbMaintenance.CreateDatabase();
+
+                var types = typeof(DsOrder).Assembly.GetTypes()
+                    .Where(d => d.GetInterfaces().Any(x => x == typeof(ITable) && !d.IsAbstract))
+                    .Distinct()
+                    .ToArray();
+
+                context.Db.CodeFirst.InitTables(types);//根据types创建表
+            }
+
+            if (dbOptions.ApplySeed)
+            {
+                var allTypes = AppDomain.CurrentDomain.GetAssemblies()
+                    .SelectMany(d => d.GetTypes());
+
+                var seedDataTypes = allTypes.Where(d => !d.IsInterface && !d.IsAbstract && d.IsClass
+                                                        && d.HasImplementedOf(typeof(ISeedData<>)));
+
+                foreach (var seedType in seedDataTypes)
+                {
+                    var instance = Activator.CreateInstance(seedType);
+
+                    var hasDataMethod = seedType.GetMethod("HasData");
+                    var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
+                    if (seedData == null) continue;
+
+                    var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
+
+                    var entityInfo = context.Db.EntityMaintenance.GetEntityInfo(entityType);
+                    if (entityInfo.Columns.Any(d => d.IsPrimarykey))
+                    {
+                        var storage = context.Db.StorageableByObject(seedData.ToList()).ToStorage();
+                        storage.AsInsertable.ExecuteCommand();
+                    }
+                    else
+                    {
+                        // 无主键则只进行插入
+                        if (!context.Db.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
+                            context.Db.InsertableByObject(seedData.ToList()).ExecuteCommand();
+                    }
+                }
+
+            }
+        }
+
+        #region private
+
+        private static void SetDbAop(SqlSugarClient db)
+        {
+            /***写AOP等方法***/
+            db.Aop.OnLogExecuting = (sql, pars) =>
+            {
+                //Log.Information("Sql: {0}", sql);
+                //Log.Information("SqlParameters: {0}", string.Join(',', pars.Select(d => d.Value)));
+            };
+            db.Aop.OnError = (exp) =>//SQL报错
+            {
+                //exp.sql 这样可以拿到错误SQL,性能无影响拿到ORM带参数使用的SQL
+                Log.Error("SqlError: {0}", exp.Sql);
+
+                //5.0.8.2 获取无参数化 SQL  对性能有影响,特别大的SQL参数多的,调试使用
+                //UtilMethods.GetSqlString(DbType.SqlServer,exp.sql,exp.parameters)           
+            };
+            //db.Aop.OnExecutingChangeSql = (sql, pars) => //可以修改SQL和参数的值
+            //{
+            //    //sql=newsql
+            //    //foreach (var p in pars) //修改
+            //    //{
+
+            //    //}
+
+            //    return new KeyValuePair<string, SugarParameter[]>(sql, pars);
+            //};
+
+            db.Aop.OnLogExecuted = (sql, p) =>
+            {
+                //执行时间超过1秒
+                if (db.Ado.SqlExecutionTime.TotalSeconds > 1)
+                {
+                    //代码CS文件名
+                    var fileName = db.Ado.SqlStackTrace.FirstFileName;
+                    //代码行数
+                    var fileLine = db.Ado.SqlStackTrace.FirstLine;
+                    //方法名
+                    var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
+                    //db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息
+
+                    Log.Warning("slow query ==> fileName: {fileName}, fileLine: {fileLine}, FirstMethodName: {FirstMethodName}",
+                        fileName, fileLine, FirstMethodName);
+                    Log.Warning(UtilMethods.GetNativeSql(sql, p));
+                    Log.Warning("slow query totalSeconds: {sec}", db.Ado.SqlExecutionTime.TotalSeconds);
+                }
+                //相当于EF的 PrintToMiniProfiler
+            };
+
+            db.Aop.DataExecuting = (oldValue, entityInfo) =>
+            {
+                //inset生效
+                if (entityInfo.PropertyName == "CreationTime" && entityInfo.OperationType == DataFilterType.InsertByObject)
+                {
+                    if (oldValue is DateTime createTime)
+                    {
+                        if (createTime == DateTime.MinValue)
+                        {
+                            entityInfo.SetValue(DateTime.Now);//修改CreateTime字段
+                                                              //entityInfo有字段所有参数
+                        }
+                    }
+                }
+                //update生效        
+                else if (entityInfo.PropertyName == "LastModificationTime" && entityInfo.OperationType == DataFilterType.UpdateByObject)
+                {
+                    entityInfo.SetValue(DateTime.Now);//修改UpdateTime字段
+                }
+
+                //根据当前列修改另一列 可以么写
+                //if(当前列逻辑==XXX)
+                //var properyDate = entityInfo.EntityValue.GetType().GetProperty("Date");
+                //if(properyDate!=null)
+                //properyDate.SetValue(entityInfo.EntityValue,1);
+
+                else if (entityInfo.EntityColumnInfo.IsPrimarykey
+                         && entityInfo.EntityColumnInfo.PropertyName.ToLower() == "id"
+                         && entityInfo.OperationType == DataFilterType.InsertByObject
+                         && oldValue is null) //通过主键保证只进一次事件
+                {
+                    //var propertyId = entityInfo.EntityValue.GetType().GetProperty("Id");
+                    //if (propertyId is not null)
+                    //{
+                    //    var idValue = propertyId.GetValue(entityInfo.EntityValue);
+                    //    if (idValue is null)
+                    //        //这样每条记录就只执行一次 
+                    //        entityInfo.SetValue(SequentialStringGenerator.Create());
+                    //}
+                    entityInfo.SetValue(SequentialStringGenerator.Create());
+
+                }
+            };
+
+            SetDeletedEntityFilter(db);
+        }
+
+        private static void SetDeletedEntityFilter(SqlSugarClient db)
+        {
+            var cacheKey = $"DbFilter:{db.CurrentConnectionConfig.ConfigId}:IsDeleted";
+            var tableFilterItemList = db.DataCache.Get<List<TableFilterItem<object>>>(cacheKey);
+            if (tableFilterItemList == null)
+            {
+                // 获取基类实体数据表
+                var entityTypes = AppDomain.CurrentDomain.GetAssemblies()
+                    .SelectMany(d => d.GetTypes())
+                    .Where(d => !d.IsInterface
+                                && !d.IsAbstract
+                                && d.IsClass
+                                && d.GetInterfaces().Any(x => x == typeof(ISoftDelete)));
+                if (!entityTypes.Any()) return;
+
+                var tableFilterItems = new List<TableFilterItem<object>>();
+                foreach (var entityType in entityTypes)
+                {
+                    if (entityType.GetProperty("IsDeleted") is null) continue;
+                    //// 排除非当前数据库实体
+                    //var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
+                    //if ((tAtt != null && (string)db.CurrentConnectionConfig.ConfigId != tAtt.configId.ToString()) ||
+                    //    (tAtt == null && (string)db.CurrentConnectionConfig.ConfigId != SqlSugarConst.ConfigId))
+                    //    continue;
+
+                    var lambda = DynamicExpressionParser.ParseLambda(new[] {
+                        Expression.Parameter(entityType, "d") },
+                    typeof(bool),
+                    $"{nameof(SoftDeleteEntity.IsDeleted)} == @0", false);
+                    var tableFilterItem = new TableFilterItem<object>(entityType, lambda);
+                    tableFilterItems.Add(tableFilterItem);
+                    db.QueryFilter.Add(tableFilterItem);
+                }
+                db.DataCache.Add(cacheKey, tableFilterItems);
+            }
+            else
+            {
+                tableFilterItemList.ForEach(u =>
+                {
+                    db.QueryFilter.Add(u);
+                });
+            }
+        }
+
+        #endregion
+    }
+}

+ 9 - 0
src/DataSharing.Share/DataSharing.Share.csproj

@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+</Project>

+ 6 - 0
src/DataSharing.Share/Requests/BatchRemoveDto.cs

@@ -0,0 +1,6 @@
+namespace DataSharing.Share.Requests;
+
+public class BatchRemoveDto
+{
+    public ICollection<string> Ids { get; set; }
+}

+ 31 - 0
src/DataSharing.Share/Requests/PagedKeywordRequest.cs

@@ -0,0 +1,31 @@
+namespace DataSharing.Share.Requests;
+
+public record PagedKeywordRequest : PagedRequest
+{
+    public string? Keyword { get; set; }
+}
+
+public record ReportPagedRequest : PagedKeywordRequest 
+{
+
+	/// <summary>
+	/// 开始时间
+	/// </summary>
+	public DateTime? StartTime { get; set; }
+
+	/// <summary>
+	/// 结束时间
+	/// </summary>
+	public DateTime? EndTime { get; set; }
+
+	/// <summary>
+	/// 排序字段 
+	/// </summary>
+	public string SortField { get; set; }
+
+	/// <summary>
+	/// 排序规则  0 升序  1 降序
+	/// </summary>
+	public int SortRule { get; set; }
+
+}

+ 11 - 0
src/DataSharing.Share/Requests/PagedRequest.cs

@@ -0,0 +1,11 @@
+
+namespace DataSharing.Share.Requests
+{
+    public record PagedRequest
+    {
+        public int PageIndex { get; set; } = 1;
+        public int PageSize { get; set; } = 10;
+
+        public int Skip() => (PageIndex - 1) * PageSize;
+    }
+}

+ 25 - 0
src/DataSharing/DataSharing.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="XF.Domain.Repository" Version="1.0.5" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Mapster" Version="7.3.0" />
+    <PackageReference Include="MediatR" Version="12.0.1" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
+    <PackageReference Include="XF.EasyCaching" Version="1.0.0" />
+    <PackageReference Include="XF.Utility.MQ" Version="1.0.5" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DataSharing.Share\DataSharing.Share.csproj" />
+  </ItemGroup>
+
+</Project>

+ 28 - 0
src/DataSharing/DsOrder.cs

@@ -0,0 +1,28 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace DataSharing
+{
+    public class DsOrder : CreationEntity
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单编号", ColumnDataType = "varchar(50)")]
+        public string No { get; set; }
+
+        /// <summary>
+        /// 上传省工单编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "上传省工单编号", ColumnDataType = "varchar(50)")]
+        public string? ProvinceNo { get; set; }
+
+        [SugarColumn(IsJson = true)]
+        public string? Data { get; set; }
+    }
+}

+ 63 - 0
src/DataSharing/DsSendTask.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SqlSugar;
+using XF.Domain.Repository;
+
+namespace DataSharing
+{
+    /// <summary>
+    /// 发送任务
+    /// </summary>
+    public class DsSendTask : CreationEntity
+    {
+        /// <summary>
+        /// 初次推送时间
+        /// </summary>
+        public DateTime? FirstTime { get; set; }
+
+        /// <summary>
+        /// 最近一次推送时间
+        /// </summary>
+        public DateTime? LastTime { get; set; }
+
+        /// <summary>
+        /// 推送成功时间
+        /// </summary>
+        public DateTime? SuccessTime { get; set; }
+
+        /// <summary>
+        /// 推送次数
+        /// </summary>
+        public int SendTimes { get; set; }
+
+        /// <summary>
+        /// 推送成功
+        /// </summary>
+        public bool IsSuccess { get; set; }
+
+        /// <summary>
+        /// 任务类型
+        /// addOrder, expiredTimeChanged...
+        /// </summary>
+        public string TaskType { get; set; }
+
+        /// <summary>
+        /// 请求方式
+        /// </summary>
+        public string HttpMethod { get; set; }
+
+        /// <summary>
+        /// 请求地址
+        /// </summary>
+        public string Path { get; set; }
+
+        /// <summary>
+        /// 请求参数
+        /// </summary>
+        [SugarColumn(Length = 5000)]
+        public string Request { get; set; }
+    }
+}