ソースを参照

新增随手拍导入工具

qinchaoyue 1 ヶ月 前
コミット
e818f263a2
60 ファイル変更1800 行追加9 行削除
  1. 362 4
      .gitignore
  2. 11 5
      DataTransmission.sln
  3. 0 0
      DataTransmission/App.config
  4. 0 0
      DataTransmission/CommonTool.cs
  5. 0 0
      DataTransmission/DataTransmission.csproj
  6. 0 0
      DataTransmission/Entity/Base.cs
  7. 0 0
      DataTransmission/Entity/CallNative.cs
  8. 0 0
      DataTransmission/Entity/Config.cs
  9. 0 0
      DataTransmission/Entity/IWorkflow.cs
  10. 0 0
      DataTransmission/Entity/Order.cs
  11. 0 0
      DataTransmission/Entity/OrderDelay.cs
  12. 0 0
      DataTransmission/Entity/OrderPublish.cs
  13. 0 0
      DataTransmission/Entity/OrderScreen.cs
  14. 0 0
      DataTransmission/Entity/OrderVisit.cs
  15. 0 0
      DataTransmission/Entity/OrderVisitDetail.cs
  16. 0 0
      DataTransmission/Entity/StepBasicEntity.cs
  17. 0 0
      DataTransmission/Entity/TrCallRecord.cs
  18. 0 0
      DataTransmission/Entity/Workflow.cs
  19. 0 0
      DataTransmission/Entity/WorkflowStep.cs
  20. 0 0
      DataTransmission/Entity/WorkflowTrace.cs
  21. 0 0
      DataTransmission/Enum/Order.cs
  22. 0 0
      DataTransmission/Execute.cs
  23. 0 0
      DataTransmission/Form1.Designer.cs
  24. 0 0
      DataTransmission/Form1.cs
  25. 0 0
      DataTransmission/Form1.resx
  26. 0 0
      DataTransmission/Joint/Delay.cs
  27. 0 0
      DataTransmission/Joint/Knowledge.cs
  28. 0 0
      DataTransmission/Joint/Notice.cs
  29. 0 0
      DataTransmission/Joint/Order.cs
  30. 0 0
      DataTransmission/Joint/OrderPublic.cs
  31. 0 0
      DataTransmission/Joint/Organize.cs
  32. 0 0
      DataTransmission/Joint/Public.cs
  33. 0 0
      DataTransmission/Joint/User.cs
  34. 0 0
      DataTransmission/Joint/Visit.cs
  35. 0 0
      DataTransmission/Joint/Workflow.cs
  36. 0 0
      DataTransmission/Program.cs
  37. 11 0
      SnapshotWinFormsApp/App.config
  38. 40 0
      SnapshotWinFormsApp/Application/Dtos/WeChatUserDto.cs
  39. 72 0
      SnapshotWinFormsApp/Application/SnapshotUserInfoApplication.cs
  40. 244 0
      SnapshotWinFormsApp/Entities/NewHotline/Base.cs
  41. 40 0
      SnapshotWinFormsApp/Entities/NewHotline/SnapshotUserInfo.cs
  42. 65 0
      SnapshotWinFormsApp/Entities/NewHotline/ThirdAccount.cs
  43. 43 0
      SnapshotWinFormsApp/Entities/OldHotline/Flow03_PushContent.cs
  44. 21 0
      SnapshotWinFormsApp/Entities/OldHotline/WeChatFollowUserEntity.cs
  45. 34 0
      SnapshotWinFormsApp/Entities/OldHotline/WeChatUserEntity.cs
  46. 139 0
      SnapshotWinFormsApp/MainForm.Designer.cs
  47. 44 0
      SnapshotWinFormsApp/MainForm.cs
  48. 120 0
      SnapshotWinFormsApp/MainForm.resx
  49. 21 0
      SnapshotWinFormsApp/Program.cs
  50. 47 0
      SnapshotWinFormsApp/Repository/BaseRepository.cs
  51. 49 0
      SnapshotWinFormsApp/Repository/DbSqlServer.cs
  52. 19 0
      SnapshotWinFormsApp/Repository/Enum/EAppType.cs
  53. 22 0
      SnapshotWinFormsApp/Repository/Enum/EReadPackUserType.cs
  54. 21 0
      SnapshotWinFormsApp/Repository/Enum/EThirdType.cs
  55. 25 0
      SnapshotWinFormsApp/Repository/Interfaces/IRepository.cs
  56. 35 0
      SnapshotWinFormsApp/Repository/Repository.cs
  57. 26 0
      SnapshotWinFormsApp/SnapshotWinFormsApp.csproj
  58. 156 0
      SnapshotWinFormsApp/Tools/Logs.cs
  59. 24 0
      SnapshotWinFormsApp/Tools/MapsterConfig.cs
  60. 109 0
      SnapshotWinFormsApp/Tools/MyExtensions.cs

+ 362 - 4
.gitignore

@@ -1,5 +1,363 @@
-################################################################################
-# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
-################################################################################
+## 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
 
-/.vs
+# 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/
+[Oo]ut/
+[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
+*.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
+
+# 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_*
+.*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
+# 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
+
+# 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
+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
+*- [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

+ 11 - 5
DataTransmission.sln

@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.7.34024.191
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataTransmission", "DataTransmission.csproj", "{10883182-3CA0-43FE-B0F5-C8610C16012A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataTransmission", "DataTransmission\DataTransmission.csproj", "{7AA6A23C-8E6E-CB04-C7BB-DBAE971E2C3B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SnapshotWinFormsApp", "SnapshotWinFormsApp\SnapshotWinFormsApp.csproj", "{3A94D9A9-75F0-4172-8F43-47D5E273F21F}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +13,14 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{10883182-3CA0-43FE-B0F5-C8610C16012A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{10883182-3CA0-43FE-B0F5-C8610C16012A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{10883182-3CA0-43FE-B0F5-C8610C16012A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{10883182-3CA0-43FE-B0F5-C8610C16012A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7AA6A23C-8E6E-CB04-C7BB-DBAE971E2C3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AA6A23C-8E6E-CB04-C7BB-DBAE971E2C3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7AA6A23C-8E6E-CB04-C7BB-DBAE971E2C3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7AA6A23C-8E6E-CB04-C7BB-DBAE971E2C3B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3A94D9A9-75F0-4172-8F43-47D5E273F21F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3A94D9A9-75F0-4172-8F43-47D5E273F21F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3A94D9A9-75F0-4172-8F43-47D5E273F21F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3A94D9A9-75F0-4172-8F43-47D5E273F21F}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 0
App.config → DataTransmission/App.config


+ 0 - 0
CommonTool.cs → DataTransmission/CommonTool.cs


+ 0 - 0
DataTransmission.csproj → DataTransmission/DataTransmission.csproj


+ 0 - 0
Entity/Base.cs → DataTransmission/Entity/Base.cs


+ 0 - 0
Entity/CallNative.cs → DataTransmission/Entity/CallNative.cs


+ 0 - 0
Entity/Config.cs → DataTransmission/Entity/Config.cs


+ 0 - 0
Entity/IWorkflow.cs → DataTransmission/Entity/IWorkflow.cs


+ 0 - 0
Entity/Order.cs → DataTransmission/Entity/Order.cs


+ 0 - 0
Entity/OrderDelay.cs → DataTransmission/Entity/OrderDelay.cs


+ 0 - 0
Entity/OrderPublish.cs → DataTransmission/Entity/OrderPublish.cs


+ 0 - 0
Entity/OrderScreen.cs → DataTransmission/Entity/OrderScreen.cs


+ 0 - 0
Entity/OrderVisit.cs → DataTransmission/Entity/OrderVisit.cs


+ 0 - 0
Entity/OrderVisitDetail.cs → DataTransmission/Entity/OrderVisitDetail.cs


+ 0 - 0
Entity/StepBasicEntity.cs → DataTransmission/Entity/StepBasicEntity.cs


+ 0 - 0
Entity/TrCallRecord.cs → DataTransmission/Entity/TrCallRecord.cs


+ 0 - 0
Entity/Workflow.cs → DataTransmission/Entity/Workflow.cs


+ 0 - 0
Entity/WorkflowStep.cs → DataTransmission/Entity/WorkflowStep.cs


+ 0 - 0
Entity/WorkflowTrace.cs → DataTransmission/Entity/WorkflowTrace.cs


+ 0 - 0
Enum/Order.cs → DataTransmission/Enum/Order.cs


+ 0 - 0
Execute.cs → DataTransmission/Execute.cs


+ 0 - 0
Form1.Designer.cs → DataTransmission/Form1.Designer.cs


+ 0 - 0
Form1.cs → DataTransmission/Form1.cs


+ 0 - 0
Form1.resx → DataTransmission/Form1.resx


+ 0 - 0
Joint/Delay.cs → DataTransmission/Joint/Delay.cs


+ 0 - 0
Joint/Knowledge.cs → DataTransmission/Joint/Knowledge.cs


+ 0 - 0
Joint/Notice.cs → DataTransmission/Joint/Notice.cs


+ 0 - 0
Joint/Order.cs → DataTransmission/Joint/Order.cs


+ 0 - 0
Joint/OrderPublic.cs → DataTransmission/Joint/OrderPublic.cs


+ 0 - 0
Joint/Organize.cs → DataTransmission/Joint/Organize.cs


+ 0 - 0
Joint/Public.cs → DataTransmission/Joint/Public.cs


+ 0 - 0
Joint/User.cs → DataTransmission/Joint/User.cs


+ 0 - 0
Joint/Visit.cs → DataTransmission/Joint/Visit.cs


+ 0 - 0
Joint/Workflow.cs → DataTransmission/Joint/Workflow.cs


+ 0 - 0
Program.cs → DataTransmission/Program.cs


+ 11 - 0
SnapshotWinFormsApp/App.config

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+	<appSettings>
+		<!--日志-->
+		<add key ="LogLevel" value="10"/>
+	</appSettings>
+	<connectionStrings>
+		<add providerName="自贡" name ="SQLServerDB" connectionString="server=61.157.186.3,4368;database=ZG_CityHotline_Ver3;uid=ZGCityHotlineUser;pwd=fway09!@ZG_15;"  />
+		<add providerName="自贡" name ="PGSQLDB" connectionString="Server=110.188.24.182;Port=5432;UserId=dev;Password=fengwo11!!;Database=hotline_zg;" />
+	</connectionStrings>
+</configuration>

+ 40 - 0
SnapshotWinFormsApp/Application/Dtos/WeChatUserDto.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Application.Dtos;
+
+public class WeChatUserDto
+{
+    public string? openid { get; set; }
+    public string WUR_Openid { get; set; }
+    public int WUR_WebUserID { get; set; }
+    public string WUR_WebUserName { get; set; }
+    public string WUR_WebLoginName { get; set; }
+    public string WUR_PhoneNum { get; set; }
+    public string WUR_LoginPWD { get; set; }
+    public string WUR_Gender { get; set; }
+    public string WUR_IDCard { get; set; }
+    public int WUR_AreaID { get; set; }
+    public string WUR_Address { get; set; }
+    public string WUR_Mail { get; set; }
+    public string WUR_RegIP { get; set; }
+    public DateTime WUR_RegDate { get; set; }
+    public string? WUR_StateFlag { get; set; }
+    public string WUR_LastIP { get; set; }
+    public DateTime WUR_LastDate { get; set; }
+    public string WUR_SyncState { get; set; }
+    public string WUR_unionid { get; set; }
+    public string WUR_Img { get; set; }
+    public string WUR_UserType { get; set; }
+    public int WUR_Flag { get; set; }
+    public int UserID { get; set; }
+    public string appid { get; set; }
+    public int subscribe { get; set; }
+    public string unionid { get; set; }
+    public int IsSynchUnionID { get; set; }
+    public DateTime InsertTime { get; set; }
+    public DateTime UpdateTime { get; set; }
+}

+ 72 - 0
SnapshotWinFormsApp/Application/SnapshotUserInfoApplication.cs

@@ -0,0 +1,72 @@
+using Abp.Extensions;
+using Mapster;
+using SnapshotWinFormsApp.Application.Dtos;
+using SnapshotWinFormsApp.Entities.NewHotline;
+using SnapshotWinFormsApp.Entities.OldHotline;
+using SnapshotWinFormsApp.Repository;
+using SnapshotWinFormsApp.Repository.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Application;
+
+public class SnapshotUserInfoApplication
+{
+    private readonly IBaseRepository<ThirdAccount> _thirdAccountRepo;
+    private readonly IRepository<WeChatUserEntity> _weChatRepo;
+    private readonly IRepository<WeChatFollowUserEntity> _weChatFlowRepo;
+    private readonly IBaseRepository<SnapshotUserInfo> _userRepo;
+
+    public SnapshotUserInfoApplication(DbSqlServer sqlServerDB)
+    {
+        _thirdAccountRepo = new BaseRepository<ThirdAccount>(sqlServerDB, "自贡");
+        _weChatRepo = new Repository<WeChatUserEntity>(sqlServerDB, "自贡");
+        _weChatFlowRepo = new Repository<WeChatFollowUserEntity>(sqlServerDB, "自贡");
+        _userRepo = new BaseRepository<SnapshotUserInfo>(sqlServerDB, "自贡");
+    }
+
+    public async Task ImportSnapshotUserInfoAsync(Action<string> log, CancellationToken token)
+    {
+        log($"正在查询旧数据...");
+        var items = await _weChatRepo.Queryable()
+            .LeftJoin<WeChatFollowUserEntity>((w, f) => w.WUR_unionid == f.unionid)
+            .Select((w, f) => new WeChatUserDto(), true)
+            .ToListAsync(token);
+        log($"共查询到{items.Count}条数据");
+        var totalCount = items.Count;
+        var index = 0;
+        foreach (var item in items)
+        {
+            index++;
+            if (token.IsCancellationRequested)
+            {
+                log("任务已取消");
+                return;
+            }
+            var userId = await _userRepo.Queryable()
+                .Where(m => m.PhoneNumber == item.WUR_PhoneNum)
+                .Select(m => m.Id)
+                .FirstAsync(token);
+            if (userId.IsNullOrEmpty())
+            {
+                var userInfo = item.Adapt<SnapshotUserInfo>();
+                userId = await _userRepo.InsertAsync(userInfo, token);
+                log($"{index}/{totalCount} 插入用户信息: {userId}, {userInfo.Name}, {userInfo.PhoneNumber}");
+            }
+            var thirdId = await _thirdAccountRepo.Queryable()
+                .Where(m => m.OpenId == item.openid && m.UnIonId == item.WUR_unionid)
+                .Select(m => m.Id)
+                .FirstAsync(token);
+            if (thirdId.IsNullOrEmpty())
+            {
+                var thirdAccount = item.Adapt<ThirdAccount>();
+                thirdAccount.ExternalId = userId;
+                thirdAccount.Id = await _thirdAccountRepo.InsertAsync(thirdAccount, token);
+                log($"{index}/{totalCount} 插入第三方账号信息: {thirdAccount.Id}, {thirdAccount.OpenId}, {thirdAccount.UserName}, {thirdAccount.PhoneNumber}, {thirdAccount.ExternalId}");
+            }
+        }
+    }
+}

+ 244 - 0
SnapshotWinFormsApp/Entities/NewHotline/Base.cs

@@ -0,0 +1,244 @@
+using Abp;
+using Abp.Domain.Entities;
+using Abp.Domain.Entities.Auditing;
+using DataTransmission.Entity;
+
+namespace SnapshotWinFormsApp.Entities.NewHotline
+{
+	public class Entity
+	{
+		//private List<IAppNotification> _domainEvents = new();
+
+		public string Id { get; set; }
+
+		//[SugarColumn(ColumnDescription = "创建人")]
+		public string? CreatorId { get; set; }
+
+		public string? CreatorName { get; set; }
+
+		//[SugarColumn(ColumnDescription = "组织Id")]
+		public string? CreatorOrgId { get; set; }
+
+		public string? CreatorOrgName { get; set; }
+
+		//[SugarColumn(DefaultValue = "0")]
+		public int CreatorOrgLevel { get; set; } = 0;
+
+		/// <summary>
+		/// 一级部门Id
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "数据权限区域Id")]
+		public string? AreaId { get; set; }
+
+		//public void ClearEvents() => _domainEvents.Clear();
+
+		//public ICollection<IAppNotification> QueryAllEvents() => _domainEvents;
+
+		public void InitId() => Id = SequentialGuidGenerator.Instance.Create().ToString("D");
+	}
+
+	/// <summary>
+	/// 实体(带有创建时间)
+	/// </summary>
+	public abstract class CreationEntity : Entity, IHasCreationTime
+	{
+		/// <summary>
+		/// 创建时间
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "创建时间")]
+		public DateTime CreationTime { get; set; }
+	}
+
+	/// <summary>
+	/// 实体(带有软删除)
+	/// </summary>
+	public abstract class SoftDeleteEntity : Entity, IHasDeletionTime, ISoftDelete
+	{
+		/// <summary>
+		/// 删除时间
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "删除时间")]
+		public DateTime? DeletionTime { get; set; }
+
+		//[SugarColumn(ColumnDescription = "是否删除")]
+		public bool IsDeleted { get; set; }
+
+		public void SoftDelete()
+		{
+			IsDeleted = true;
+			DeletionTime = DateTime.Now;
+		}
+	}
+
+	/// <summary>
+	/// 实体(带有创建时间和软删除)
+	/// </summary>
+	public abstract class CreationSoftDeleteEntity : CreationEntity, IHasDeletionTime, ISoftDelete
+	{
+		//[SugarColumn(ColumnDescription = "是否删除", DefaultValue = "f")]
+		public bool IsDeleted { get; set; }
+
+		/// <summary>
+		/// 删除时间
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "删除时间")]
+		public DateTime? DeletionTime { get; set; }
+
+		public void SoftDelete()
+		{
+			IsDeleted = true;
+			DeletionTime = DateTime.Now;
+		}
+
+		public void Recover() => IsDeleted = false;
+	}
+
+	public abstract class CreationModificationEntity : CreationEntity, IHasModificationTime
+	{
+		/// <summary>
+		/// 最近更新时间
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "最近更新时间")]
+		public DateTime? LastModificationTime { get; set; }
+
+		public void Modified() => LastModificationTime = DateTime.Now;
+	}
+
+	/// <summary>
+	/// 全状态实体(创建时间、更新时间、软删除)
+	/// </summary>
+	public abstract class FullStateEntity : CreationSoftDeleteEntity, IHasModificationTime
+	{
+		/// <summary>
+		/// 最近更新时间
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "最近更新时间")]
+		public DateTime? LastModificationTime { get; set; }
+
+		public void Modified() => LastModificationTime = DateTime.Now;
+	}
+	public abstract class WorkflowEntity : FullStateEntity, IWorkflow
+	{
+		//[SugarColumn(IsNullable = true)] 
+		public string? WorkflowId { get; set; }
+
+		/// <summary>
+		/// 过期时间配置id
+		/// </summary>
+		//[SugarColumn(IsNullable = true)]
+		public string? ExpiredTimeConfigId { get; set; }
+
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<string>? FlowedOrgIds { get; set; } = new();
+
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<string>? FlowedUserIds { get; set; } = new();
+
+		#region 当前办理对象
+
+		/// <summary>
+		/// 办理人id
+		/// </summary>
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<HandlerGroupItem>? HandlerUsers { get; set; } = new();
+
+		/// <summary>
+		/// 办理部门id
+		/// </summary>
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<HandlerGroupItem>? HandlerOrgs { get; set; } = new();
+
+		#endregion
+	}
+
+	public abstract class PositionEntity : FullStateEntity
+	{
+		/// <summary>
+		/// 经度
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "经度")]
+		public double? Longitude { get; set; }
+
+		/// <summary>
+		/// 维度
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "纬度")]
+		public double? Latitude { get; set; }
+
+		/// <summary>
+		/// 行政区划编码
+		/// </summary>
+		//[SugarColumn(ColumnDescription = "行政区划编码")]
+		public string? AreaCode { get; set; }
+
+		/// <summary>
+		/// 省
+		/// </summary>
+		public string? Province { get; set; }
+
+		/// <summary>
+		/// 市
+		/// </summary>
+		public string? City { get; set; }
+
+		/// <summary>
+		/// 区/县
+		/// </summary>
+		public string? County { get; set; }
+
+		/// <summary>
+		/// 乡镇(4级行政区划)
+		/// </summary>
+		public string? Town { get; set; }
+
+		/// <summary>
+		/// 详细街道
+		/// </summary>
+		public string? Street { get; set; }
+
+		/// <summary>
+		/// 行政区划地址
+		/// </summary>
+		public string? Address { get; set; }
+
+		/// <summary>
+		/// 完整地址
+		/// </summary>
+		public string? FullAddress { get; set; }
+	}
+
+	public abstract class PositionWorkflowEntity : PositionEntity, IWorkflow
+	{
+		//[SugarColumn(IsNullable = true)]
+		public string? WorkflowId { get; set; }
+
+		/// <summary>
+		/// 过期时间配置id
+		/// </summary>
+		//[SugarColumn(IsNullable = true)]
+		public string? ExpiredTimeConfigId { get; set; }
+
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<string>? FlowedOrgIds { get; set; } = new();
+
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<string>? FlowedUserIds { get; set; } = new();
+
+		#region 当前办理对象
+
+		/// <summary>
+		/// 办理人id
+		/// </summary>
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<HandlerGroupItem>? HandlerUsers { get; set; } = new();
+
+		/// <summary>
+		/// 办理部门id
+		/// </summary>
+		//[SugarColumn(ColumnDataType = "json", IsJson = true)]
+		public List<HandlerGroupItem>? HandlerOrgs { get; set; } = new();
+
+		#endregion
+
+	}
+}

+ 40 - 0
SnapshotWinFormsApp/Entities/NewHotline/SnapshotUserInfo.cs

@@ -0,0 +1,40 @@
+using SnapshotWinFormsApp.Repository.Enum;
+using SqlSugar;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace SnapshotWinFormsApp.Entities.NewHotline;
+
+/// <summary>
+/// 网格员和普通随手拍人员信息
+/// </summary>
+[SugarTable("snapshot_user_info")]
+[Description("随手拍用户信息")]
+public class SnapshotUserInfo : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 用户自己填的邀请码
+    /// </summary>
+    public string? InvitationCode { get; set; }
+
+    /// <summary>
+    /// 历史已经领取金额总和(单位:元)
+    /// </summary>
+    public double TotalAmount { get; set; }
+
+    /// <summary>
+    /// 用户类型
+    /// 注册时根据手机号码判断是否是 网格员
+    /// </summary>
+    public EReadPackUserType CitizenType { get; set; }
+
+    /// <summary>
+    /// 姓名
+    /// </summary>
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 电话号码
+    /// </summary>
+    public string? PhoneNumber { get; set; }
+}

+ 65 - 0
SnapshotWinFormsApp/Entities/NewHotline/ThirdAccount.cs

@@ -0,0 +1,65 @@
+using DataTransmission.Enum;
+using SqlSugar;
+using System.ComponentModel;
+
+namespace SnapshotWinFormsApp.Entities.NewHotline;
+
+/// <summary>
+/// 随手拍用户微信小程序登录信息
+/// </summary>
+[SugarTable("third_account")]
+[Description("小程序账号信息")]
+public class ThirdAccount : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 外部业务唯一标识
+    /// </summary>
+    public string? ExternalId { get; set; }
+
+    /// <summary>
+    /// 电话
+    /// </summary>
+    public string? PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 第三方平台的Id
+    /// 例如: 微信的OpenId
+    /// </summary>
+    public string OpenId { get; set; }
+
+    /// <summary>
+    /// 第三方平台的SessionKey
+    /// 例如: 微信SessionKey
+    /// </summary>
+    public string? SessionKey { get; set; }
+
+    /// <summary>
+    /// 账号类型
+    /// </summary>
+    public EThirdType AccountType { get; set; }
+
+    /// <summary>
+    /// 用户头像Url
+    /// </summary>
+    public string? HeadImgUrl { get; set; }
+
+    /// <summary>
+    /// 用户昵称
+    /// </summary>
+    public string? UserName { get; set; }
+
+    /// <summary>
+    /// 用户在开放平台的唯一标识符。本字段在满足一定条件的情况下才返回。具体参看:https://mp.weixin.qq.com/debug/wxadoc/dev/api/uinionID.html
+    /// </summary>
+    public string? UnIonId { get; set; }
+
+    /// <summary>
+    /// 应用类型
+    /// </summary>
+    public EAppType AppType { get; set; } = EAppType.Snapshot;
+
+    /// <summary>
+    /// 创建时间
+    /// </summary>
+    public DateTime CreationTime { get; set; }
+}

+ 43 - 0
SnapshotWinFormsApp/Entities/OldHotline/Flow03_PushContent.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Entities.OldHotline;
+
+public class Flow03_PushContent
+{
+    public int FPC_ID { get; set; }
+    public int FPC_FlowID { get; set; }
+    public string? FPC_Code { get; set; }
+    public string? FPC_Content { get; set; }
+    public DateTime? FPC_AcceptDate { get; set; }
+    public DateTime? FPC_InsertDate { get; set; }
+    public int? FPC_StateFalg { get; set; }
+    public DateTime? FPC_SyncDate { get; set; }
+    public string? FPC_BMType { get; set; }
+    public string? FPC_ResultType { get; set; }
+    public int? FPC_Count { get; set; }
+    public bool? FPC_ISTrue { get; set; }
+    public string? MemberName { get; set; }
+    public string? MemberMobile { get; set; }
+    public string? AppealNumber { get; set; }
+    public bool? IsRepeat { get; set; }
+    public string? RepeatAppealNumber { get; set; }
+    public bool? IsHiddenDanger { get; set; }
+    public int? FPC_AreaID { get; set; }
+    public string? FPC_AreaFullName { get; set; }
+    public bool? FPC_TageisTrue { get; set; }
+    public bool? FPC_TageisPunish { get; set; }
+    public bool? FPC_TageisFund { get; set; }
+    public int? FPC_TagBMUserID { get; set; }
+    public DateTime? FPC_TagBMDate { get; set; }
+    public string? FPC_TagType { get; set; }
+    public int? FPC_TagFalg { get; set; }
+    public int? FPC_TagUserID { get; set; }
+    public string? FPC_TagUserName { get; set; }
+    public string? FPC_TagRemark { get; set; }
+    public DateTime? FPC_TagDate { get; set; }
+    public int? FPC_PDUserID { get; set; }
+}

+ 21 - 0
SnapshotWinFormsApp/Entities/OldHotline/WeChatFollowUserEntity.cs

@@ -0,0 +1,21 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Entities.OldHotline;
+
+[SugarTable("ZG_CityHotline_Ver3.dbo.WeChat_FollowUsers")]
+public class WeChatFollowUserEntity
+{
+    public string? openid { get; set; }
+    public int UserID { get; set; }
+    public string appid { get; set; }
+    public int subscribe { get; set; }
+    public string unionid { get; set; }
+    public int IsSynchUnionID { get; set; }
+    public DateTime InsertTime { get; set; }
+    public DateTime UpdateTime { get; set; }
+}

+ 34 - 0
SnapshotWinFormsApp/Entities/OldHotline/WeChatUserEntity.cs

@@ -0,0 +1,34 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Entities.OldHotline;
+
+[SugarTable("ZG_CityHotline_Web.dbo.Web30_UserRegister")]
+public class WeChatUserEntity
+{
+    public string WUR_Openid { get; set; }
+    public int WUR_WebUserID { get; set; }
+    public string WUR_WebUserName { get; set; }
+    public string WUR_WebLoginName { get; set; }
+    public string WUR_PhoneNum { get; set; }
+    public string WUR_LoginPWD { get; set; }
+    public string WUR_Gender { get; set; }
+    public string WUR_IDCard { get; set; }
+    public int WUR_AreaID { get; set; }
+    public string WUR_Address { get; set; }
+    public string WUR_Mail { get; set; }
+    public string WUR_RegIP { get; set; }
+    public DateTime WUR_RegDate { get; set; }
+    public int? WUR_StateFlag { get; set; }
+    public string WUR_LastIP { get; set; }
+    public DateTime WUR_LastDate { get; set; }
+    public int WUR_SyncState { get; set; }
+    public string WUR_unionid { get; set; }
+    public string WUR_Img { get; set; }
+    public string WUR_UserType { get; set; }
+    public int WUR_Flag { get; set; }
+ }

+ 139 - 0
SnapshotWinFormsApp/MainForm.Designer.cs

@@ -0,0 +1,139 @@
+namespace SnapshotWinFormsApp;
+
+partial class MainForm
+{
+    /// <summary>
+    ///  Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary>
+    ///  Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing)
+    {
+        if (disposing && (components != null))
+        {
+            components.Dispose();
+        }
+        base.Dispose(disposing);
+    }
+
+    #region Windows Form Designer generated code
+
+    /// <summary>
+    ///  Required method for Designer support - do not modify
+    ///  the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent()
+    {
+        OkBtn = new Button();
+        logTxt = new TextBox();
+        CancelBtn = new Button();
+        splitContainer1 = new SplitContainer();
+        tableLayoutPanel1 = new TableLayoutPanel();
+        ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
+        splitContainer1.Panel1.SuspendLayout();
+        splitContainer1.Panel2.SuspendLayout();
+        splitContainer1.SuspendLayout();
+        tableLayoutPanel1.SuspendLayout();
+        SuspendLayout();
+        // 
+        // OkBtn
+        // 
+        OkBtn.Location = new Point(3, 3);
+        OkBtn.Name = "OkBtn";
+        OkBtn.Size = new Size(75, 23);
+        OkBtn.TabIndex = 0;
+        OkBtn.Text = "开始导入";
+        OkBtn.UseVisualStyleBackColor = true;
+        OkBtn.Click += OkBtn_Click;
+        // 
+        // logTxt
+        // 
+        logTxt.BackColor = Color.Black;
+        logTxt.BorderStyle = BorderStyle.None;
+        logTxt.Dock = DockStyle.Fill;
+        logTxt.Font = new Font("Courier New", 12F, FontStyle.Bold, GraphicsUnit.Point);
+        logTxt.ForeColor = Color.LimeGreen;
+        logTxt.Location = new Point(0, 0);
+        logTxt.Multiline = true;
+        logTxt.Name = "logTxt";
+        logTxt.ScrollBars = ScrollBars.Vertical;
+        logTxt.Size = new Size(739, 526);
+        logTxt.TabIndex = 1;
+        // 
+        // CancelBtn
+        // 
+        CancelBtn.Location = new Point(103, 3);
+        CancelBtn.Name = "CancelBtn";
+        CancelBtn.Size = new Size(75, 23);
+        CancelBtn.TabIndex = 0;
+        CancelBtn.Text = "停止任务";
+        CancelBtn.UseVisualStyleBackColor = true;
+        CancelBtn.Click += CancelBtn_Click;
+        // 
+        // splitContainer1
+        // 
+        splitContainer1.Dock = DockStyle.Fill;
+        splitContainer1.FixedPanel = FixedPanel.Panel1;
+        splitContainer1.IsSplitterFixed = true;
+        splitContainer1.Location = new Point(0, 0);
+        splitContainer1.Name = "splitContainer1";
+        // 
+        // splitContainer1.Panel1
+        // 
+        splitContainer1.Panel1.Controls.Add(tableLayoutPanel1);
+        // 
+        // splitContainer1.Panel2
+        // 
+        splitContainer1.Panel2.Controls.Add(logTxt);
+        splitContainer1.Panel2MinSize = 200;
+        splitContainer1.Size = new Size(943, 526);
+        splitContainer1.SplitterDistance = 200;
+        splitContainer1.TabIndex = 2;
+        // 
+        // tableLayoutPanel1
+        // 
+        tableLayoutPanel1.ColumnCount = 2;
+        tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
+        tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
+        tableLayoutPanel1.Controls.Add(OkBtn, 0, 0);
+        tableLayoutPanel1.Controls.Add(CancelBtn, 1, 0);
+        tableLayoutPanel1.Dock = DockStyle.Fill;
+        tableLayoutPanel1.Location = new Point(0, 0);
+        tableLayoutPanel1.Name = "tableLayoutPanel1";
+        tableLayoutPanel1.RowCount = 2;
+        tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
+        tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
+        tableLayoutPanel1.Size = new Size(200, 526);
+        tableLayoutPanel1.TabIndex = 1;
+        // 
+        // MainForm
+        // 
+        AcceptButton = OkBtn;
+        AutoScaleDimensions = new SizeF(7F, 15F);
+        AutoScaleMode = AutoScaleMode.Font;
+        ClientSize = new Size(943, 526);
+        Controls.Add(splitContainer1);
+        Name = "MainForm";
+        StartPosition = FormStartPosition.CenterScreen;
+        Text = "随手拍数据导入";
+        splitContainer1.Panel1.ResumeLayout(false);
+        splitContainer1.Panel2.ResumeLayout(false);
+        splitContainer1.Panel2.PerformLayout();
+        ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
+        splitContainer1.ResumeLayout(false);
+        tableLayoutPanel1.ResumeLayout(false);
+        ResumeLayout(false);
+    }
+
+    #endregion
+
+    private Button OkBtn;
+    private TextBox logTxt;
+    private Button CancelBtn;
+    private SplitContainer splitContainer1;
+    private TableLayoutPanel tableLayoutPanel1;
+}

+ 44 - 0
SnapshotWinFormsApp/MainForm.cs

@@ -0,0 +1,44 @@
+using SnapshotWinFormsApp.Application;
+using SnapshotWinFormsApp.Repository;
+using SnapshotWinFormsApp.Tools;
+
+namespace SnapshotWinFormsApp;
+
+public partial class MainForm : Form
+{
+    private readonly DbSqlServer _sqlServerDB;
+    private readonly SnapshotUserInfoApplication _snapshotUserInfoApplication;
+    private CancellationTokenSource? _cts;
+
+    public MainForm(DbSqlServer sqlServerDB)
+    {
+        _sqlServerDB = sqlServerDB;
+        _snapshotUserInfoApplication = new SnapshotUserInfoApplication(sqlServerDB);
+
+        InitializeComponent();
+        logTxt.AppendText("³õʼ»¯Íê³É\r\n");
+        logTxt.AppendText("ÈÕÖ¾Îļþ¼Ð:" + Logs.Path() + "\r\n");
+    }
+
+    private void OkBtn_Click(object sender, EventArgs e)
+    {
+        _cts?.Cancel();
+        _cts = new CancellationTokenSource();
+        var token = _cts.Token;
+        Task.Run(() => _snapshotUserInfoApplication.ImportSnapshotUserInfoAsync(AddLog, token));
+    }
+
+    private void AddLog(string msg)
+    {
+        this.Invoke((EventHandler)delegate 
+        {
+            this.logTxt.AppendText(msg + "\r\n");
+            Logs.Note(msg);
+        });
+    }
+
+    private void CancelBtn_Click(object sender, EventArgs e)
+    {
+        _cts?.Cancel();
+    }
+}

+ 120 - 0
SnapshotWinFormsApp/MainForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 21 - 0
SnapshotWinFormsApp/Program.cs

@@ -0,0 +1,21 @@
+using SnapshotWinFormsApp.Repository;
+using SnapshotWinFormsApp.Tools;
+
+namespace SnapshotWinFormsApp;
+
+internal static class Program
+{
+    /// <summary>
+    ///  The main entry point for the application.
+    /// </summary>
+    [STAThread]
+    static void Main()
+    {
+        // To customize application configuration such as set high DPI settings or default font,
+        // see https://aka.ms/applicationconfiguration.
+        ApplicationConfiguration.Initialize();
+        // ×¢²á Mapster Ó³É乿Ôò
+        MapsterConfig.RegisterMappings();
+        System.Windows.Forms.Application.Run(new MainForm(DbSqlServer.Instance));
+    }
+}

+ 47 - 0
SnapshotWinFormsApp/Repository/BaseRepository.cs

@@ -0,0 +1,47 @@
+using SnapshotWinFormsApp.Entities.NewHotline;
+using SnapshotWinFormsApp.Repository.Interfaces;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Repository;
+
+public class BaseRepository<T> : IBaseRepository<T> where T : Entity, new()
+{
+    private readonly SqlSugarClient _db;
+
+    public BaseRepository(DbSqlServer context, string key)
+    {
+        _db = context.DbItems.GetValueOrDefault(key + "PGSQLDB");
+    }
+
+    public async Task<List<T>> GetAllAsync(CancellationToken token)
+    {
+        return _db.Queryable<T>().ToList();
+    }
+
+    public T GetById(int id)
+    {
+        return _db.Queryable<T>().InSingle(id);
+    }
+
+    public async Task<string> InsertAsync(T entity, CancellationToken token)
+    {
+        entity.InitId();
+        await _db.Insertable(entity).ExecuteCommandAsync(token);
+        return entity.Id;
+    }
+
+    public ISugarQueryable<T> Queryable()
+    {
+        return _db.Queryable<T>();
+    }
+
+    public void Update(T entity)
+    {
+        _db.Updateable<T>(entity).ExecuteCommand();
+    }
+}

+ 49 - 0
SnapshotWinFormsApp/Repository/DbSqlServer.cs

@@ -0,0 +1,49 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Repository;
+
+public class DbSqlServer
+{
+    public Dictionary<string, SqlSugarClient> DbItems { get; private set; }
+
+    private static DbSqlServer _instance;
+    public static DbSqlServer Instance => _instance ??= new DbSqlServer();
+
+    private DbSqlServer()
+    {
+        DbItems = new Dictionary<string, SqlSugarClient>();
+        foreach (var item in ConfigurationManager.ConnectionStrings)
+        {
+            var settings = (ConnectionStringSettings)item;
+            if (settings.ProviderName.Length < 8)
+            {
+                var db = new SqlSugarClient(new ConnectionConfig()
+                {
+                    ConnectionString = settings.ConnectionString,
+                    DbType = settings.Name.StartsWith("PG") ? SqlSugar.DbType.PostgreSQL: SqlSugar.DbType.SqlServer,
+                    IsAutoCloseConnection = true,
+                    InitKeyType = InitKeyType.Attribute,
+                    MoreSettings = new ConnMoreSettings
+                    {
+                        PgSqlIsAutoToLower = false,
+                        PgSqlIsAutoToLowerCodeFirst = false,
+                    }
+                });
+
+                db.Aop.OnLogExecuting = (sql, pars) =>
+                {
+                    Console.WriteLine(sql);
+                };
+
+                DbItems.Add(settings.ProviderName + settings.Name, db);
+            }
+        }
+    }
+}

+ 19 - 0
SnapshotWinFormsApp/Repository/Enum/EAppType.cs

@@ -0,0 +1,19 @@
+namespace DataTransmission.Enum;
+public enum EAppType
+{
+    /// <summary>
+    /// 随手拍
+    /// </summary>
+    Snapshot = 1,
+
+    /// <summary>
+    /// 部门办件app
+    /// </summary>
+    Department = 2,
+
+    /// <summary>
+    /// 市民办件app
+    /// </summary>
+    Citizen = 3
+}
+

+ 22 - 0
SnapshotWinFormsApp/Repository/Enum/EReadPackUserType.cs

@@ -0,0 +1,22 @@
+using System.ComponentModel;
+namespace SnapshotWinFormsApp.Repository.Enum;
+
+/// <summary>
+/// 红包领取人类型;
+/// 1: 市民;
+/// 2: 网格员;
+/// </summary>
+public enum EReadPackUserType
+{
+    /// <summary>
+    /// 市民
+    /// </summary>
+    [Description("市民")]
+    Citizen = 1,
+
+    /// <summary>
+    /// 网络员
+    /// </summary>
+    [Description("网络员")]
+    Guider = 2
+}

+ 21 - 0
SnapshotWinFormsApp/Repository/Enum/EThirdType.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DataTransmission.Enum;
+
+/// <summary>
+/// 第三方平台类型(不传默认微信)
+/// 0: 微信
+/// </summary>
+public enum EThirdType
+{
+    /// <summary>
+    /// 微信
+    /// </summary>
+    [Description("微信")]
+    WeChat = 0
+}

+ 25 - 0
SnapshotWinFormsApp/Repository/Interfaces/IRepository.cs

@@ -0,0 +1,25 @@
+using SnapshotWinFormsApp.Entities.NewHotline;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Repository.Interfaces;
+
+public interface IRepository<T> where T : class, new()
+{
+    ISugarQueryable<T> Queryable();
+    T GetById(int id);
+    List<T> GetAll();
+}
+
+public interface IBaseRepository<T> where T : Entity, new()
+{
+    ISugarQueryable<T> Queryable();
+    T GetById(int id);
+    Task<List<T>> GetAllAsync(CancellationToken token);
+    Task<string> InsertAsync(T entity, CancellationToken token);
+    void Update(T entity);
+}

+ 35 - 0
SnapshotWinFormsApp/Repository/Repository.cs

@@ -0,0 +1,35 @@
+using SnapshotWinFormsApp.Repository.Interfaces;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SnapshotWinFormsApp.Repository;
+
+public class Repository<T> : IRepository<T> where T : class, new()
+{
+    private readonly SqlSugarClient _db;
+
+    public Repository(DbSqlServer context, string key)
+    {
+        _db = context.DbItems.GetValueOrDefault(key+ "SQLServerDB");
+    }
+
+    public T GetById(int id)
+    {
+        return _db.Queryable<T>().InSingle(id);
+    }
+
+    public List<T> GetAll()
+    {
+        return _db.Queryable<T>().ToList();
+    }
+
+
+    public ISugarQueryable<T> Queryable()
+    { 
+        return _db.Queryable<T>();
+    }
+}

+ 26 - 0
SnapshotWinFormsApp/SnapshotWinFormsApp.csproj

@@ -0,0 +1,26 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net6.0-windows</TargetFramework>
+    <Nullable>enable</Nullable>
+    <UseWindowsForms>true</UseWindowsForms>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Mapster" Version="7.4.0" />
+    <PackageReference Include="SqlSugar" Version="5.1.4.185" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\DataTransmission\DataTransmission.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="App.config">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
+</Project>

+ 156 - 0
SnapshotWinFormsApp/Tools/Logs.cs

@@ -0,0 +1,156 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace SnapshotWinFormsApp.Tools
+{
+    /// <summary>
+    /// 最基本的日志记录
+    /// </summary>
+    public static class Logs
+    {
+        /// <summary>
+        /// 获取记录文件路径
+        /// </summary>
+        /// <returns>日志文件路径</returns>
+        public static string Path()
+        {
+            var logPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "logs");
+            if (!Directory.Exists(logPath))
+            {
+                Directory.CreateDirectory(logPath);
+            }
+            return logPath;
+        }
+
+        /// <summary>
+        /// 错误信息记录
+        /// 请在所有的日志记录都无法使用的情况下使用下, 再使用本方法
+        /// </summary>
+        /// <param name="msg">记录的内容</param>
+        public static void Err(string msg)
+        {
+            string logPath = System.IO.Path.Combine(Path(), "err.log");
+
+            StackTrace trace = new StackTrace();
+            MethodBase methodBase = trace.GetFrame(1).GetMethod();
+            msg = $"方法 {methodBase.Name} 异常: {msg}";
+
+            Note(logPath, msg, true);
+        }
+
+        /// <summary>
+        /// 错误信息记录
+        /// </summary>
+        /// <param name="e"></param>
+        public static void Err(Exception e)
+        {
+            var msg = string.Empty;
+            try
+            {
+                msg = "Form: " + e?.InnerException?.Source + "\r\nMsg: " + e;
+            }
+            catch
+            {
+                msg = e.ToString();
+            }
+            Err(msg);
+        }
+
+        /// <summary>
+        /// 记录警告信息
+        /// </summary>
+        /// <param name="msg">内容</param>
+        public static void Warning(string msg)
+        {
+            Note(System.IO.Path.Combine(Path() , "Warning.log"),msg,true);
+        }
+
+        /// <summary>
+        /// 错误信息记录
+        /// </summary>
+        /// <param name="msg">记录的内容</param>
+        /// <param name="name">文件名字</param>
+        public static void Err(string msg, string name)
+        {
+            string path = System.IO.Path.Combine(Path(),  DateTime.Now.ToString("yyyyMMdd") + "[" + name + "][err].log");
+            Note(path, msg, true);
+        }
+
+        /// <summary>
+        /// 错误信息记录
+        /// </summary>
+        /// <param name="method">方法</param>
+        /// <param name="param">参数</param>
+        /// <param name="discription">描述</param>
+        public static void Err(string method, string param ,string discription)
+        {
+            string message = "方法: " + method + "\r\n参数:" + param + "\r\n描述:" + discription;
+            Err(message);
+        }
+
+        /// <summary>
+        /// 日志记录
+        /// </summary>
+        /// <param name="msg">记录的内容</param>
+        public static void Note(string msg)
+        {
+            var logPath = System.IO.Path.Combine(Path(), "note.log");
+            Note(logPath, msg, true);
+        }
+
+        /// <summary>
+        /// 日志记录
+        /// 日志自动记录调用者的名字
+        /// </summary>
+        /// <param name="msg">记录的信息</param>
+        public static void MethodNote(string msg)
+        {
+            StackTrace trace = new StackTrace();
+            MethodBase metbodBase = trace.GetFrame(1).GetMethod();
+            Note(System.IO.Path.Combine(Path(), "note.log"), metbodBase.Name + ":" + msg);
+        }
+
+        /// <summary>
+        /// 日志记录
+        /// </summary>
+        /// <param name="path">日志文件路径</param>
+        /// <param name="msg">内容</param>
+        public static void Note(string path, string msg)
+        {
+            Note(path, msg, false);
+        }
+
+        /// <summary>
+        /// 日志记录
+        /// </summary>
+        /// <param name="msg">记录的内容</param>
+        /// <param name="path">日志文件路径</param>
+        /// <param name="format">是否格式化信息</param>
+        public static void Note(string path, string msg, bool format)
+        {
+            try
+            {
+                if (!File.Exists(path))
+                {
+                    FileStream fs = File.Create(path);
+                    fs.Dispose();
+                    fs.Close();
+                }
+                using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Write))
+                {
+                    StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
+                    if (format) sw.WriteLine(DateTime.Now + "  " + msg);
+                    else sw.WriteLine(msg);
+                    sw.Dispose();
+                    sw.Close();
+                }
+            }
+            catch
+            {
+            }
+        }
+    }
+}

+ 24 - 0
SnapshotWinFormsApp/Tools/MapsterConfig.cs

@@ -0,0 +1,24 @@
+using Mapster;
+using SnapshotWinFormsApp.Application.Dtos;
+using SnapshotWinFormsApp.Entities.NewHotline;
+using SnapshotWinFormsApp.Entities.OldHotline;
+
+namespace SnapshotWinFormsApp.Tools;
+
+public static class MapsterConfig
+{
+    public static void RegisterMappings()
+    {
+        TypeAdapterConfig<WeChatUserDto, SnapshotUserInfo>.NewConfig()
+            .Map(m => m.CreationTime, n => n.WUR_RegDate)
+            .Map(m => m.PhoneNumber, n => n.WUR_PhoneNum)
+            .Map(m => m.Name, n => n.WUR_WebUserName);
+
+        TypeAdapterConfig<WeChatUserDto, ThirdAccount>.NewConfig()
+            .Map(m => m.PhoneNumber, n => n.WUR_PhoneNum)
+            .Map(m => m.UserName, n => n.WUR_WebUserName)
+            .Map(m => m.CreationTime, n => n.WUR_RegDate)
+            .Map(m => m.OpenId, n => n.WUR_Openid)
+            .Map(m => m.UnIonId, n => n.WUR_unionid);
+    }
+}

+ 109 - 0
SnapshotWinFormsApp/Tools/MyExtensions.cs

@@ -0,0 +1,109 @@
+using Castle.Core.Internal;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Data;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DataTransmission.Tools;
+
+public static class MyExtensions
+{
+    public static string GetTableName<T>(this T value) where T : class
+    {
+        var tableAttribute = typeof(T).GetCustomAttribute<TableAttribute>();
+        return tableAttribute?.Name ?? string.Empty;
+    }
+
+    /// <summary>
+    /// 将DataTable转换为指定类型的实体集合
+    /// </summary>
+    /// <typeparam name="T">实体类型</typeparam>
+    /// <param name="dt">DataTable</param>
+    /// <returns>实体集合</returns>
+    public static List<T> ToList<T>(this DataTable dt) where T : new()
+    {
+        List<T> list = new List<T>();
+        if (dt == null || dt.Rows.Count == 0)
+            return list;
+
+        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty);
+
+        foreach (DataRow row in dt.Rows)
+        {
+            T item = new T();
+            foreach (PropertyInfo property in properties)
+            {
+                if (dt.Columns.Contains(property.Name) && !row.IsNull(property.Name))
+                {
+                    object value = Convert.ChangeType(row[property.Name], property.PropertyType);
+                    property.SetValue(item, value, null);
+                }
+            }
+            list.Add(item);
+        }
+
+        return list;
+    }
+
+    public static string ToSqlInsert<T>(this T entity) where T : class
+    {
+        if (entity == null)
+            throw new ArgumentNullException(nameof(entity));
+
+        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+        var tableName = entity.GetTableName();
+        var columns = new StringBuilder();
+        var values = new StringBuilder();
+
+        foreach (var property in properties)
+        {
+            if (!property.CanWrite)
+                continue;
+
+            var columnName = property.Name;
+            var value = property.GetValue(entity);
+
+            if (value == null)
+            {
+                //values.Append("NULL, ");
+                continue;
+            }
+
+            if (property.PropertyType == typeof(string) || property.PropertyType == typeof(double))
+            {
+                value = $"'{value.ToString().Replace("'", "''")}'";
+            }
+            else if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
+            {
+                value = $"'{(DateTime)value:yyyy-MM-dd hh:mm:ss.ffffff}'";
+            }
+            else if (property.PropertyType.BaseType == typeof(System.Enum))
+            {
+                value = $"{(int)value}";
+            }
+            else
+            {
+                value = value.ToString();
+            }
+
+            columns.Append($"\"{columnName}\", ");
+            values.Append($"{value}, ");
+        }
+
+        if (columns.Length == 0)
+            throw new InvalidOperationException("没有可插入的属性。");
+
+        // 移除最后的逗号和空格
+        columns.Length -= 2;
+        values.Length -= 2;
+
+        var sql = $"INSERT INTO {tableName} ({columns}) VALUES ({values});";
+
+        return sql;
+    }
+}