init
This commit is contained in:
commit
d5bf18d324
|
|
@ -0,0 +1,5 @@
|
|||
# 2010
|
||||
*.txt -crlf
|
||||
|
||||
# 2020
|
||||
*.txt text eol=lf
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.DS_Store
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
logs/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
results/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
.vscode/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
site/wwwroot/
|
||||
|
||||
# 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
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Microsoft Azure ApplicationInsights config file
|
||||
ApplicationInsights.config
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# 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
|
||||
*.pfx
|
||||
!idsrv3test.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# 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
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# 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
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
!tools/packages.config
|
||||
tools/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
|
||||
# Ocelot acceptance test config
|
||||
test/Ocelot.AcceptanceTests/ocelot.json
|
||||
|
||||
# Read the docstates
|
||||
_build/
|
||||
_static/
|
||||
_templates/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
|
||||
# Test Results
|
||||
*.trx
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DG.Core" Version="1.1.3" />
|
||||
<PackageReference Include="DG.Redis" Version="1.0.17" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.9" />
|
||||
<PackageReference Include="DG.Kafka" Version="1.0.2" />
|
||||
<PackageReference Include="DG.Kafka.Worker" Version="1.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Exceptionless" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
|
||||
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="DG.Tool" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="CommonWorker.Workers" />
|
||||
<Using Include="CommonWorker.Dto" />
|
||||
<Using Include="DG.Kafka.Worker" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="DG.EntityFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Disaster.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommonWorker.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public string zxdCoreApi { get; set; }
|
||||
public string nodeWebApi { get; set; }
|
||||
public string crmCoreApi { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["CommonWorker/CommonWorker.csproj", "CommonWorker/"]
|
||||
COPY ["Zxd.Entity/Zxd.Entity.csproj", "Zxd.Entity/"]
|
||||
COPY ["Zxd.Core.Shared/Zxd.Core.Shared.csproj", "Zxd.Core.Shared/"]
|
||||
COPY ["Zxd.EntityFramework/Zxd.EntityFramework.csproj", "Zxd.EntityFramework/"]
|
||||
RUN dotnet restore "CommonWorker/CommonWorker.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/CommonWorker"
|
||||
RUN dotnet build "CommonWorker.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "CommonWorker.csproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "CommonWorker.dll"]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommonWorker.Dto
|
||||
{
|
||||
public class ResPassTimeDto
|
||||
{
|
||||
public string ResId { get; set; }
|
||||
}
|
||||
|
||||
public class CompanyBussiness
|
||||
{
|
||||
public string[] soft { get; set; }
|
||||
public string[] xinmeiti { get; set; }
|
||||
public int? ProtectTime { get; set; } = 14;
|
||||
public decimal limitPrice { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommonWorker.Dto
|
||||
{
|
||||
public class UserModuleApiModel
|
||||
{
|
||||
public int ret { get; set; }
|
||||
public string? message { get; set; }
|
||||
public Dictionary<string, List<UserModuleModel>> moduelData { get; set; }
|
||||
}
|
||||
|
||||
public class UserModuleModel
|
||||
{
|
||||
public string? orderid { get; set; }
|
||||
public string? productid { get; set; }
|
||||
public long? start { get; set; }
|
||||
public long? end { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
using CommonWorker.Config;
|
||||
using CommonWorker.Dto;
|
||||
using CommonWorker.Workers;
|
||||
using DG.Kafka.Worker;
|
||||
using Exceptionless;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
try
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Console.WriteLine($"Env: {env}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env ?? "Production"}.json", true)
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{env ?? "Production"}.json", true)
|
||||
.Build();
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(config)
|
||||
.WriteTo.Exceptionless(config.GetValue<string>("Exceptionless:ApiKey"), config.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "WeworkUserWorker" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
Log.Information("Starting WeworkUserWorker");
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog();
|
||||
});
|
||||
services.AddSingleton(config);
|
||||
services.AddOptions()
|
||||
.Configure<SystemConfig>(e => config.GetSection("SystemConfig").Bind(e));
|
||||
ExceptionlessClient.Default.Startup(config.GetValue<string>("Exceptionless:ApiKey"));
|
||||
ExceptionlessClient.Default.Configuration.ServerUrl = config.GetValue<string>("Exceptionless:ServerUrl");
|
||||
//services.AddRedis(config);
|
||||
services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(config.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsbaseDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncmsbase"), ServerVersion.AutoDetect(config.GetConnectionString("dncmsbase")));
|
||||
});
|
||||
services.AddDGEntityFramework<UserCenterDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("usercenter"), ServerVersion.AutoDetect(config.GetConnectionString("usercenter")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncms"), ServerVersion.AutoDetect(config.GetConnectionString("dncms")));
|
||||
});
|
||||
services.AddDGEntityFramework<CrmDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("crm"), ServerVersion.AutoDetect(config.GetConnectionString("crm")));
|
||||
});
|
||||
services.AddDGEntityFramework<CompanyBaseConfDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("companyBaseConf"), ServerVersion.AutoDetect(config.GetConnectionString("companyBaseConf")));
|
||||
});
|
||||
services.AddKafkaWorker(config);
|
||||
services.AddDGHttpClient();
|
||||
services.AddRegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>();
|
||||
//构建容器
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var workerManager = serviceProvider.GetRequiredService<IKafkaWorkerManager>();
|
||||
await workerManager.RegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>("ResPassTime");
|
||||
await workerManager.RegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>("ResPassTime");
|
||||
await workerManager.RegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>("ResPassTime");
|
||||
await workerManager.RegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>("ResPassTime");
|
||||
await workerManager.RegisterWorker<CustomerPassTimeWorker, ResPassTimeDto>("ResPassTime");
|
||||
var builder = new HostBuilder();
|
||||
await builder.RunConsoleAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"CommonWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker (1)": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Warning",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
using CommonWorker.Config;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Entity.Crm;
|
||||
using Zxd.Entity.Dncms;
|
||||
using Zxd.Entity.Zxd;
|
||||
using Zxd.Entity.Zxd.Order;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
namespace CommonWorker.Workers
|
||||
{
|
||||
internal class CustomerPassTimeWorker : KafkaWorkerBase<ResPassTimeDto>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<CustomerPassTimeWorker> _logger;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IOptionsSnapshot<SystemConfig> _systemConfig;
|
||||
|
||||
public CustomerPassTimeWorker(
|
||||
IServiceProvider serviceProvider,
|
||||
IOptionsSnapshot<SystemConfig> systemConfig,
|
||||
ILogger<CustomerPassTimeWorker> logger,
|
||||
IHttpClient httpClient
|
||||
) : base(logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
_systemConfig = systemConfig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 算出统计表
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync(ResPassTimeDto model)
|
||||
{
|
||||
var resList = model.ResId.Split(",");
|
||||
//Log.Information($"批量计算客户过期时间{model.ResId}");
|
||||
foreach (var item in resList)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Information($"{item}开始计算客户过期时间");
|
||||
//需要新注册实体
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var _repository = scope.ServiceProvider.GetRequiredService<IBaseRepository<ZxdDbContext>>();
|
||||
var _crmRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
//目前只支持一个resid
|
||||
var allresid = item.Split(",").ToList();
|
||||
//订单信息
|
||||
allresid = allresid.Where(n => !string.IsNullOrWhiteSpace(n)).ToList();
|
||||
var cust = await _repository.GetRepository<RES_CUSTOMER>().Query().FirstOrDefaultAsync(n => n.RESID == item || n.UMID == item);
|
||||
allresid = await _repository.GetRepository<RES_CUSTOMER>().Query().Where(n => n.CUSTOMERID == cust.CUSTOMERID && !string.IsNullOrWhiteSpace(n.RESID))
|
||||
.Select(n => n.RESID).Distinct().ToListAsync();
|
||||
var customerList = await _repository.GetRepository<RES_CUSTOMER>().Query().Where(n => allresid.Contains(n.RESID)).ToListAsync();
|
||||
|
||||
var _orderRepository = _repository.GetRepository<WX_SZZYORDER>();
|
||||
var orderList = await _orderRepository.Query().Where(n => allresid.Contains(n.RESID)).ToListAsync();
|
||||
//退款信息 按实际退款
|
||||
var refundOrderList = await _repository.GetRepository<WX_SzzyOrderRefund>().Query()
|
||||
.Where(n => allresid.Contains(n.resid) && n.auditstatus == 1 && n.isacturalrefund == 1).ToListAsync();
|
||||
//到账信息
|
||||
var orderDepositList = await _repository.GetRepository<WX_SZZYORDERDEPOSIT>().Query()
|
||||
.Where(n => allresid.Contains(n.resid) && n.auditstatus == 1).ToListAsync();
|
||||
var _userRepository = _repository.GetRepository<SOFT_USER>();
|
||||
Log.Information($"实际计算客户过期时间{string.Join(",", allresid)}");
|
||||
var allsoft = _userRepository.Query().Where(m => allresid.Contains(m.RESID)).OrderBy(m => m.REGDATE).ToList();//查出所有的soft
|
||||
//过期时间
|
||||
var usernameList = allsoft.Select(n => n.USERNAME).ToList();
|
||||
if (allsoft.Count == 0)
|
||||
{
|
||||
usernameList = orderList.Select(n => n.SOFTUSERNAME).Distinct().ToList();
|
||||
}
|
||||
List<UserModuleModel> passTimeList = new List<UserModuleModel>();
|
||||
Log.Information($"{item}GetSoftName【{string.Join(",", usernameList)}】");
|
||||
foreach (var username in usernameList)
|
||||
{
|
||||
passTimeList.AddRange(await GetRootPassTime(username));
|
||||
}
|
||||
|
||||
var orderidList = passTimeList.Select(n => n.orderid).ToList();
|
||||
//剔除免费订单
|
||||
var freeOrderList = await _repository.GetRepository<L2_SOFT_ORDER>().Query().Where(n => orderidList.Contains(n.WEBORDERID)).ToListAsync();
|
||||
var freeorderids = freeOrderList.Where(n => !n.MainOrderId.HasValue).Select(n => n.WEBORDERID).ToList();
|
||||
passTimeList = passTimeList.Where(n => !freeorderids.Contains(n.orderid)).ToList(); //不包括免费产品
|
||||
var deptCodes = orderList.GroupBy(n => new { n.Deptid, n.GroupId, n.DeptName }).Select(n => new { deptid = n.Key.Deptid, groupid = n.Key.GroupId, deptname = n.Key.DeptName }).ToList();
|
||||
var depositCodes = orderDepositList.GroupBy(n => new { n.deptid, n.groupid, n.deptName }).Select(n => new { deptid = n.Key.deptid, groupid = n.Key.groupid, deptname = n.Key.deptName }).ToList();
|
||||
var refundCodes = refundOrderList.GroupBy(n => new { n.deptid, n.groupid, n.deptName }).Select(n => new { deptid = n.Key.deptid, groupid = n.Key.groupid, deptname = n.Key.deptName }).ToList();
|
||||
deptCodes.AddRange(depositCodes);
|
||||
deptCodes.AddRange(refundCodes);
|
||||
deptCodes = deptCodes.Distinct().ToList();
|
||||
var protectDay = 14; //默认14天
|
||||
var softbusiness = await _repository.GetRepository<BAS_PARAMETER>().Query().FirstOrDefaultAsync(n => n.PARAKEY == "SoftBusiness");
|
||||
//Log.Information($"获取配置{softbusiness.ToJson()}");
|
||||
decimal limitPrice = 500; //默认500
|
||||
if (softbusiness != null)
|
||||
{
|
||||
CompanyBussiness bussiness = JsonHelper.FromJson<CompanyBussiness>(softbusiness.PARAVALUE);
|
||||
protectDay = bussiness.ProtectTime.Value;
|
||||
limitPrice = bussiness.limitPrice;
|
||||
}
|
||||
foreach (var code in deptCodes)
|
||||
{
|
||||
var deptorders = orderList.Where(n => n.Deptid == code.deptid).ToList();
|
||||
var deptFreeOrder = freeOrderList.Where(n => n.MainOrderId.HasValue && n.deptid == code.deptid).ToList();
|
||||
//算出 余额 = 取流水剩余金额 + 已支付 已提交支付的订单到账金额。
|
||||
var deptDepositList = orderDepositList.Where(n => n.deptid == code.deptid).ToList();
|
||||
var lastPrice = deptDepositList.Sum(n => n.lastprice);
|
||||
|
||||
var unOpenOrderStatus = new List<string> { "200", "190" };
|
||||
var orderUsePrice = deptorders.Where(n => unOpenOrderStatus.Contains(n.ORDERSTATUS)).Sum(n => n.ARRIVALPAY);
|
||||
lastPrice += orderUsePrice;
|
||||
Log.Information($"{item} lastPrice:【{lastPrice}】,orderUsePrice:【{orderUsePrice}】");
|
||||
//退款信息
|
||||
var deptrefundOrderList = refundOrderList.Where(n => n.deptid == code.deptid);
|
||||
//Log.Information($"查询出事业部【{code.deptid}_{code.deptname}】订单信息【{JsonHelper.ToJson(deptorders)}】流水信息{JsonHelper.ToJson(deptDepositList)}退款信息{JsonHelper.ToJson(deptrefundOrderList)}免费订单信息{JsonHelper.ToJson(deptFreeOrder)}");
|
||||
var info = await _crmRepository.GetRepository<ResCutomerPassTime>().Query().FirstOrDefaultAsync(n => n.RESID == item && n.Deptid == code.deptid);
|
||||
var isInsert = false;
|
||||
var customer = customerList.FirstOrDefault(n => n.RESID == item);
|
||||
if (info == null)
|
||||
{
|
||||
isInsert = true;
|
||||
info = new ResCutomerPassTime
|
||||
{
|
||||
Deptid = code.deptid,
|
||||
GroupId = code.groupid,
|
||||
DeptName = code.deptname,
|
||||
RESID = item
|
||||
};
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(info.UMID))
|
||||
{
|
||||
info.UMID = customer?.UMID;
|
||||
}
|
||||
info.balancepay = lastPrice;
|
||||
var orderPassTime = passTimeList.Where(n => deptorders.Select(n => n.SZZYORDERID.ToString()).Contains(n.orderid) || deptFreeOrder.Select(n => n.WEBORDERID).Contains(n.orderid)).ToList();
|
||||
Log.Information($"{item}过期时间计算【{JsonHelper.ToJson(orderPassTime)}】【{JsonHelper.ToJson(info)}】");
|
||||
info.arrivalpay = deptDepositList.Sum(n => n.payprice);
|
||||
info.refundpay = deptrefundOrderList.Sum(n => n.refundprice);
|
||||
var paydeptDepositList = deptDepositList.Where(n => n.lastprice > 0 || n.useprice > 0).ToList();
|
||||
info.firstPayTime = paydeptDepositList.Min(n => n.audittime);
|
||||
info.inpay = info.arrivalpay - info.refundpay;
|
||||
if (orderPassTime.Count > 0)
|
||||
{
|
||||
var longtime = orderPassTime.Max(n => n.end);
|
||||
info.orderpasstime = JavaLongToDateTime(longtime.Value);
|
||||
}
|
||||
if (info.balancepay >= limitPrice)
|
||||
{
|
||||
info.protecttime = Convert.ToDateTime("2050-01-01");
|
||||
}
|
||||
else if (orderPassTime.Count > 0)
|
||||
{
|
||||
info.protecttime = info.orderpasstime.Value.AddDays(protectDay);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.protecttime = null;
|
||||
}
|
||||
//如果净金额小于500 不予保护
|
||||
if (info.inpay < 500)
|
||||
{
|
||||
info.protecttime = null;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (isInsert)
|
||||
{
|
||||
info.Ctime = DateTime.Now;
|
||||
await _crmRepository.GetRepository<ResCutomerPassTime>().InsertAsync(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
info.utime = DateTime.Now;
|
||||
await _crmRepository.GetRepository<ResCutomerPassTime>().UpdateAsync(info);
|
||||
}
|
||||
Log.Information($"{item}计算结果【{JsonHelper.ToJson(info)}】");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"计算客户过期时间错误{ex.Message}");
|
||||
}
|
||||
}
|
||||
//删除无关的数据
|
||||
var existCode = deptCodes.Select(n => n.deptid).ToList();
|
||||
var existItem = await _crmRepository.GetRepository<ResCutomerPassTime>().Query().Where(n => n.RESID == item && !existCode.Contains(n.Deptid)).ToListAsync();
|
||||
if (existItem.Count > 0)
|
||||
{
|
||||
Log.Information($"{item}待删除{string.Join(",", existItem.Select(n => n.Deptid))}");
|
||||
await _crmRepository.GetRepository<ResCutomerPassTime>().BatchDeleteAsync(existItem);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"{item}获取过期时间失败{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<UserModuleModel>> GetRootPassTime(string username)
|
||||
{
|
||||
List<UserModuleModel> res = new List<UserModuleModel>();
|
||||
var url = $"{_systemConfig.Value.nodeWebApi.Trim('/')}/order/doGetUserPerssion";
|
||||
var postJson = new
|
||||
{
|
||||
username = username
|
||||
};
|
||||
try
|
||||
{
|
||||
var data = await _httpClient.PostAsync<UserModuleApiModel>(url, postJson);
|
||||
if (data.ret == 0)
|
||||
{
|
||||
foreach (var item in data.moduelData)
|
||||
{
|
||||
try
|
||||
{
|
||||
res.AddRange(item.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"【{username}】接口获取权限数据失败{ex.Message}【{item.Value}】");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"【{username}】接口获取权限数据失败{ex.Message}");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="timeJavaLong">java长整型日期,毫秒为单位</param>
|
||||
/// <returns></returns>
|
||||
private DateTime JavaLongToDateTime(long timeJavaLong)
|
||||
{
|
||||
var dt1970 = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
var tricks1970 = dt1970.Ticks;//1970年1月1日刻度
|
||||
var timeTricks = tricks1970 + timeJavaLong * 10000;//日志日期刻度
|
||||
return new DateTime(timeTricks).AddHours(8);//转化为DateTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=10.22.15.61;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=10.22.15.68;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=10.22.15.68;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092,172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "ResPassTime"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd.WeworkUserWorker",
|
||||
"TaskRemarks": "Zxd.WeworkUserWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "X5P60jU2Iemg8YaKtp71O4YUhbFqmqgCVLfDAQRy"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://10.22.15.163:8089",
|
||||
"nodeWebApi": "http://10.22.15.5:8080"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092,172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "ResPassTime"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd.WeworkUserWorker",
|
||||
"TaskRemarks": "Zxd.WeworkUserWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "X5P60jU2Iemg8YaKtp71O4YUhbFqmqgCVLfDAQRy"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"nodeWebApi": "https://r2.soft.dn8188.com/"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crm": "Server=192.168.11.141;Database=db_crm;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "192.168.11.104:9092,192.168.11.104:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "ResPassTime"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "DG.Worker.Sample",
|
||||
"TaskRemarks": "DG.Worker.Sample",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "tmrp0GmwyTMe6UxJIw7LXAcIWYKEUgy2kprMiybd"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089",
|
||||
"nodeWebApi": "http://120.238.224.24:10034"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
public abstract class BatchKafkaWorkerBase<T>
|
||||
{
|
||||
private readonly ILogger<BatchKafkaWorkerBase<T>> _logger;
|
||||
private TaskConfig _taskConfig;
|
||||
private int _milliSecondsDelay;
|
||||
|
||||
public BatchKafkaWorkerBase(ILogger<BatchKafkaWorkerBase<T>> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_taskConfig = KafkaClient.Default.ConfigurationManager.GetSection("TaskConfig").Get<TaskConfig>();
|
||||
if (_taskConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_taskConfig));
|
||||
}
|
||||
_milliSecondsDelay = _taskConfig.MilliSecondsDelay;
|
||||
}
|
||||
|
||||
public async Task Start(List<T> t)
|
||||
{
|
||||
Stopwatch watch = new Stopwatch();
|
||||
watch.Reset();
|
||||
watch.Start();
|
||||
try
|
||||
{
|
||||
if (_milliSecondsDelay <= 0)
|
||||
{
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务定时时间不能少于0!");
|
||||
return;
|
||||
}
|
||||
if (!_taskConfig.Enable)
|
||||
{
|
||||
await Task.Delay(_milliSecondsDelay);
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务停止启动!");
|
||||
return;
|
||||
}
|
||||
|
||||
await DoWorkAsync(t);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}]");
|
||||
}
|
||||
watch.Stop();
|
||||
double costtime = watch.ElapsedMilliseconds;
|
||||
_logger.LogDebug($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务执行结束,用时:{costtime}ms");
|
||||
}
|
||||
|
||||
protected virtual async Task DoWorkAsync(List<T> t)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual async Task ShopAsync()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Version>1.0.21</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DG.Kafka\DG.Kafka.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
public interface IKafkaWorkerManager
|
||||
{
|
||||
Task RegisterWorker<TWorker, T>(string? topic) where TWorker : KafkaWorkerBase<T>;
|
||||
|
||||
Task RegisterBatchWorker<TWorker, T>(string? topic, int batchsize = 1000) where TWorker : BatchKafkaWorkerBase<T>;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
public interface IWorkerManager
|
||||
{
|
||||
void DoWork(Action doWork);
|
||||
|
||||
Task DoWorkAsync(Func<Task> doWork);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
public abstract class KafkaWorkerBase<T>
|
||||
{
|
||||
private readonly ILogger<KafkaWorkerBase<T>> _logger;
|
||||
private TaskConfig _taskConfig;
|
||||
private int _milliSecondsDelay;
|
||||
public KafkaWorkerBase(ILogger<KafkaWorkerBase<T>> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_taskConfig = KafkaClient.Default.ConfigurationManager.GetSection("TaskConfig").Get<TaskConfig>();
|
||||
if (_taskConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_taskConfig));
|
||||
}
|
||||
_milliSecondsDelay = _taskConfig.MilliSecondsDelay;
|
||||
}
|
||||
|
||||
public async Task Start(T t)
|
||||
{
|
||||
Stopwatch watch = new Stopwatch();
|
||||
watch.Reset();
|
||||
watch.Start();
|
||||
_logger.LogDebug($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务开始执行1");
|
||||
try
|
||||
{
|
||||
|
||||
if (_milliSecondsDelay <= 0)
|
||||
{
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务定时时间不能少于0!");
|
||||
return;
|
||||
}
|
||||
if (!_taskConfig.Enable)
|
||||
{
|
||||
await Task.Delay(_milliSecondsDelay);
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务停止启动!");
|
||||
return;
|
||||
}
|
||||
|
||||
await DoWorkAsync(t);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}]");
|
||||
}
|
||||
watch.Stop();
|
||||
double costtime = watch.ElapsedMilliseconds;
|
||||
_logger.LogDebug($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务执行结束,用时:{costtime}ms");
|
||||
}
|
||||
|
||||
protected virtual async Task DoWorkAsync(T t)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual async Task ShopAsync()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
internal class KafkaWorkerManager : IKafkaWorkerManager
|
||||
{
|
||||
private TaskConfig _taskConfig;
|
||||
private List<Consumer> _consumers;
|
||||
private readonly ILogger<KafkaWorkerManager> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public KafkaWorkerManager(ILogger<KafkaWorkerManager> logger, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
// 读取任务配置
|
||||
_taskConfig = KafkaClient.Default.ConfigurationManager.GetSection("TaskConfig").Get<TaskConfig>();
|
||||
_consumers = KafkaClient.Default.ConfigurationManager.GetSection("Consumers").Get<List<Consumer>>();
|
||||
if (_taskConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_taskConfig));
|
||||
}
|
||||
if (_consumers == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_consumers));
|
||||
}
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task RegisterWorker<TWorker, T>(string? topic)
|
||||
where TWorker : KafkaWorkerBase<T>
|
||||
{
|
||||
var t = _serviceProvider.GetRequiredService<TWorker>();
|
||||
_logger.LogDebug($"注册worker: {typeof(TWorker).Name}");
|
||||
var consumer = _consumers.FirstOrDefault(c => c.Topic == topic);
|
||||
if (consumer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(consumer));
|
||||
}
|
||||
await KafkaClient.Builder<T>(consumer, t.Start, t.ShopAsync);
|
||||
}
|
||||
|
||||
public async Task RegisterBatchWorker<TWorker, T>(string? topic, int batchsize = 1000)
|
||||
where TWorker : BatchKafkaWorkerBase<T>
|
||||
{
|
||||
var t = _serviceProvider.GetRequiredService<TWorker>();
|
||||
_logger.LogDebug($"注册worker: {typeof(TWorker).Name}");
|
||||
var consumer = _consumers.FirstOrDefault(c => c.Topic == topic);
|
||||
if (consumer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(consumer));
|
||||
}
|
||||
await KafkaClient.BatchBuilder<T>(consumer, t.Start, t.ShopAsync, batchsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using DG.Kafka;
|
||||
using DG.Kafka.Worker;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions method
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Redis service registered
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddKafkaWorker(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddKafka(configuration);
|
||||
services.AddSingleton<IWorkerManager, WorkerManager>();
|
||||
services.AddSingleton<IKafkaWorkerManager, KafkaWorkerManager>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddRegisterWorker<TWorker, T>(this IServiceCollection services) where TWorker : KafkaWorkerBase<T>
|
||||
{
|
||||
services.AddSingleton<TWorker>();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddRegisterBatchWorker<TWorker, T>(this IServiceCollection services) where TWorker : BatchKafkaWorkerBase<T>
|
||||
{
|
||||
services.AddSingleton<TWorker>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
internal class TaskConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// </summary>
|
||||
public string? TaskName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务备注
|
||||
/// </summary>
|
||||
public string? TaskRemarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool Enable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停止毫秒数
|
||||
/// </summary>
|
||||
public int MilliSecondsDelay { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace DG.Kafka.Worker
|
||||
{
|
||||
internal class WorkerManager : IWorkerManager
|
||||
{
|
||||
private TaskConfig _taskConfig;
|
||||
private int _milliSecondsDelay;
|
||||
private readonly ILogger<WorkerManager> _logger;
|
||||
|
||||
public WorkerManager(ILogger<WorkerManager> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
// 读取任务配置
|
||||
_taskConfig = KafkaClient.Default.ConfigurationManager.GetSection("TaskConfig").Get<TaskConfig>();
|
||||
if (_taskConfig == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_taskConfig));
|
||||
}
|
||||
_milliSecondsDelay = _taskConfig.MilliSecondsDelay;
|
||||
}
|
||||
|
||||
public void DoWork(Action doWork)
|
||||
{
|
||||
try
|
||||
{
|
||||
doWork();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"[{DateTimeOffset.Now}] [{_taskConfig?.TaskName}] 获取配置失败!");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DoWorkAsync(Func<Task> doWork)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
_logger.LogDebug($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务开始执行11");
|
||||
try
|
||||
{
|
||||
if (_milliSecondsDelay <= 0)
|
||||
{
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务定时时间不能少于0!");
|
||||
continue;
|
||||
}
|
||||
if (!_taskConfig.Enable)
|
||||
{
|
||||
await Task.Delay(_milliSecondsDelay);
|
||||
_logger.LogWarning($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务停止启动!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 执行主逻辑
|
||||
await doWork();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}]");
|
||||
}
|
||||
_logger.LogDebug($"[{DateTimeOffset.Now}] [{_taskConfig.TaskName}] 任务执行结束");
|
||||
await Task.Delay(_milliSecondsDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka
|
||||
{
|
||||
public class Consumer
|
||||
{
|
||||
public string? Host { get; set; }
|
||||
|
||||
public string? GroupId { get; set; }
|
||||
|
||||
public string Topic { get; set; }
|
||||
public string? TypeName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Version>1.0.18</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Confluent.Kafka" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka
|
||||
{
|
||||
public interface IKafkaProducer
|
||||
{
|
||||
Task ProduceAsync<TMessage>(string? topic, TMessage message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
using Confluent.Kafka;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Kafka
|
||||
{
|
||||
public class KafkaClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否停止服务
|
||||
/// </summary>
|
||||
public static bool Shop { get; set; } = false;
|
||||
|
||||
public void ReadFromConfiguration(IConfiguration configuration)
|
||||
{
|
||||
ConfigurationManager = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration ConfigurationManager { get; private set; }
|
||||
|
||||
private static readonly Lazy<KafkaClient> _defaultClient = new(() => new KafkaClient());
|
||||
|
||||
public static KafkaClient Default
|
||||
{
|
||||
get { return _defaultClient.Value; }
|
||||
}
|
||||
|
||||
|
||||
private static List<Consumer> _consumers { get; set; } = new List<Consumer>();
|
||||
|
||||
public static List<Consumer> GetConsumers()
|
||||
{
|
||||
_consumers = Default.ConfigurationManager.GetSection("Consumers").Get<List<Consumer>>();
|
||||
return _consumers;
|
||||
}
|
||||
|
||||
public static async Task Builder<T>(Consumer consumer, Func<T, Task> received, Func<Task> shoped)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
//var receivedDelegate = new ReceivedDelegate<T>(ReceivedAsync);
|
||||
ThreadPool.QueueUserWorkItem(async task =>
|
||||
{
|
||||
await ReceivedAsync(consumer, received, shoped);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task BatchBuilder<T>(Consumer consumer, Func<List<T>, Task> received, Func<Task> shoped, int batchsize = 1000)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
//var receivedDelegate = new BatchReceivedDelegate<T>(BatchReceivedAsync);
|
||||
ThreadPool.QueueUserWorkItem(async task =>
|
||||
{
|
||||
await BatchReceivedAsync(consumer, received, shoped, batchsize);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public delegate Task ReceivedDelegate<T>(Consumer consumer, Func<T, Task> received);
|
||||
|
||||
public delegate Task BatchReceivedDelegate<T>(Consumer consumer, Func<List<T>, Task> received, int batchsize = 1000);
|
||||
|
||||
public static async Task ReceivedAsync<T>(Consumer consumer, Func<T, Task> received, Func<Task> shoped)
|
||||
{
|
||||
try {
|
||||
var consumerConfig = new ConsumerConfig
|
||||
{
|
||||
BootstrapServers = consumer.Host,
|
||||
GroupId = consumer.GroupId,
|
||||
AutoOffsetReset = AutoOffsetReset.Earliest,
|
||||
EnableAutoCommit = false
|
||||
};
|
||||
|
||||
var cancel = false;
|
||||
|
||||
using var consumerBuilder = new ConsumerBuilder<Ignore, string>(consumerConfig).Build();
|
||||
Console.WriteLine($"Kafka alone 连接成功,配置: {JsonSerializer.Serialize(consumerConfig)}");
|
||||
var topic = consumer.Topic;
|
||||
consumerBuilder.Subscribe(topic);
|
||||
while (!cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Shop)
|
||||
{
|
||||
await shoped();
|
||||
return;
|
||||
}
|
||||
var consumeResult = consumerBuilder.Consume(CancellationToken.None);
|
||||
Console.WriteLine($"Consumer message: {consumeResult.Message.Value} topic: {consumeResult.Topic} Partition: {consumeResult.Partition}");
|
||||
var message = JsonSerializer.Deserialize<T>(consumeResult.Message.Value);
|
||||
if (message != null)
|
||||
{
|
||||
await received(message);
|
||||
}
|
||||
try
|
||||
{
|
||||
consumerBuilder.Commit(consumeResult);
|
||||
}
|
||||
catch (KafkaException e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
await Task.Delay(1);
|
||||
}
|
||||
consumerBuilder.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task BatchReceivedAsync<T>(Consumer consumer, Func<List<T>, Task> received, Func<Task> shoped, int batchsize = 1000)
|
||||
{
|
||||
try
|
||||
{
|
||||
var consumerConfig = new ConsumerConfig
|
||||
{
|
||||
BootstrapServers = consumer.Host,
|
||||
GroupId = consumer.GroupId,
|
||||
AutoOffsetReset = AutoOffsetReset.Earliest,
|
||||
EnableAutoCommit = false
|
||||
};
|
||||
|
||||
var cancel = false;
|
||||
|
||||
|
||||
using var consumerBuilder = new ConsumerBuilder<Ignore, string>(consumerConfig).Build();
|
||||
Console.WriteLine($"Kafka batch 连接成功,配置: {JsonSerializer.Serialize(consumerConfig)}");
|
||||
var topic = consumer.Topic;
|
||||
consumerBuilder.Subscribe(topic);
|
||||
while (!cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Shop)
|
||||
{
|
||||
await shoped();
|
||||
return;
|
||||
}
|
||||
var batchRecords = new List<T>();
|
||||
var consumeResults = new List<ConsumeResult<Ignore, string>>();
|
||||
while (batchRecords.Count < batchsize)
|
||||
{
|
||||
var consumeResult = consumerBuilder.Consume(CancellationToken.None);
|
||||
Console.WriteLine($"Consumer message: {consumeResult.Message.Value} topic: {consumeResult.Topic} Partition: {consumeResult.Partition}");
|
||||
var message = JsonSerializer.Deserialize<T>(consumeResult.Message.Value);
|
||||
if (message == null)
|
||||
break; // 贤有更多的消启可供消裁
|
||||
consumeResults.Add(consumeResult);
|
||||
batchRecords.Add(message);
|
||||
}
|
||||
await received(batchRecords);
|
||||
foreach (var consumeResult in consumeResults)
|
||||
{
|
||||
consumerBuilder.Commit(consumeResult);
|
||||
}
|
||||
}
|
||||
catch (KafkaException e)
|
||||
{
|
||||
Console.WriteLine("KafkaException:" + e.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("KafkaException:" + ex.ToString());
|
||||
}
|
||||
await Task.Delay(1);
|
||||
}
|
||||
consumerBuilder.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("KafkaException:" + ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task SendMessage<TMessage>(Consumer consumer, TMessage message)
|
||||
{
|
||||
var config = new ProducerConfig
|
||||
{
|
||||
BootstrapServers = consumer.Host,
|
||||
};
|
||||
var topic = consumer.Topic;
|
||||
Action<DeliveryReport<Null, string>> handler = r =>
|
||||
Console.WriteLine(!r.Error.IsError
|
||||
? $"Delivered message to {r.TopicPartitionOffset}"
|
||||
: $"Delivery Error: {r.Error.Reason}");
|
||||
|
||||
using (var p = new ProducerBuilder<Null, string>(config).Build())
|
||||
{
|
||||
try
|
||||
{
|
||||
p.Produce(topic, new Message<Null, string> { Value = JsonSerializer.Serialize(message) });
|
||||
p.Flush(TimeSpan.FromSeconds(10));
|
||||
|
||||
}
|
||||
catch (ProduceException<Null, string> e)
|
||||
{
|
||||
Console.WriteLine($"Delivery failed: {e.Error.Reason}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using Confluent.Kafka;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using static Confluent.Kafka.ConfigPropertyNames;
|
||||
|
||||
namespace DG.Kafka
|
||||
{
|
||||
internal class KafkaProducer : IKafkaProducer
|
||||
{
|
||||
private static List<Consumer> _consumers { get; set; } = new List<Consumer>();
|
||||
private Dictionary<string, IProducer<Null, string>> _producers;
|
||||
public KafkaProducer()
|
||||
{
|
||||
_consumers = KafkaClient.Default.ConfigurationManager.GetSection("Consumers").Get<List<Consumer>>();
|
||||
_producers = new Dictionary<string, IProducer<Null, string>>();
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
var config = new ProducerConfig
|
||||
{
|
||||
BootstrapServers = consumer.Host,
|
||||
};
|
||||
var topic = consumer.Topic;
|
||||
Action<DeliveryReport<Null, string>> handler = r =>
|
||||
Console.WriteLine(!r.Error.IsError
|
||||
? $"Delivered message to {r.TopicPartitionOffset}"
|
||||
: $"Delivery Error: {r.Error.Reason}");
|
||||
_producers.Add(consumer.Topic, new ProducerBuilder<Null, string>(config).Build());
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ProduceAsync<TMessage>(string? topic, TMessage message)
|
||||
{
|
||||
var producer = _producers.First().Value;
|
||||
if (!string.IsNullOrEmpty(topic))
|
||||
{
|
||||
producer = _producers.GetValueOrDefault(topic);
|
||||
}
|
||||
await producer.ProduceAsync(topic, new Message<Null, string> { Value = JsonSerializer.Serialize(message) });
|
||||
producer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using DG.Kafka;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions method
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Redis service registered
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddKafka(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
KafkaClient.Default.ReadFromConfiguration(configuration);
|
||||
services = services.AddSingleton<IKafkaProducer, KafkaProducer>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EmployeeDepartmentDetailServices.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public string zxdCoreApi { get; set; }
|
||||
public string nodeWebApi { get; set; }
|
||||
public string crmCoreApi { get; set; }
|
||||
public int clearEDDHour { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.PreProduction.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.Production.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.PreProduction.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.0.143" />
|
||||
<PackageReference Include="DG.Core" Version="1.1.2" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.11" />
|
||||
<PackageReference Include="DG.Worker" Version="1.0.1" />
|
||||
<PackageReference Include="Exceptionless" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||
<PackageReference Include="Quartz" Version="3.7.0" />
|
||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
|
||||
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
using DG.EntityFramework;
|
||||
using EmployeeDepartmentDetailServices.Config;
|
||||
using Exceptionless;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Quartz.Impl;
|
||||
using Quartz.Spi;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
using Zxd.EntityFramework;
|
||||
using DG.Core;
|
||||
using EmployeeDepartmentDetailServices.Worker;
|
||||
|
||||
try
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Console.WriteLine($"Env: {env}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env ?? "Production"}.json", true)
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{env ?? "Production"}.json", true)
|
||||
.Build();
|
||||
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(config)
|
||||
.WriteTo.Exceptionless(config.GetValue<string>("Exceptionless:ApiKey"), config.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "WeworkUserWorker" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
Log.Information("Starting ResourceFlowWorker");
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog();
|
||||
});
|
||||
services.AddSingleton<IConfiguration>(config);
|
||||
services.AddOptions()
|
||||
.Configure<SystemConfig>(e => config.GetSection("SystemConfig").Bind(e));
|
||||
ExceptionlessClient.Default.Startup(config.GetValue<string>("Exceptionless:ApiKey"));
|
||||
ExceptionlessClient.Default.Configuration.ServerUrl = config.GetValue<string>("Exceptionless:ServerUrl");
|
||||
ExceptionlessClient.Default.Configuration.DefaultTags.Add("zxd-ResourceFlowWorker");
|
||||
//services.AddRedis(config);
|
||||
services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(config.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsbaseDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncmsbase"), ServerVersion.AutoDetect(config.GetConnectionString("dncmsbase")));
|
||||
});
|
||||
services.AddDGEntityFramework<UserCenterDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("usercenter"), ServerVersion.AutoDetect(config.GetConnectionString("usercenter")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncms"), ServerVersion.AutoDetect(config.GetConnectionString("dncms")));
|
||||
});
|
||||
services.AddDGEntityFramework<CompanyBaseConfDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("companyBaseConf"), ServerVersion.AutoDetect(config.GetConnectionString("companyBaseConf")));
|
||||
});
|
||||
//services.AddDGEntityFramework<HgActionDbContext>(options =>
|
||||
//{
|
||||
// options.UseMySql(config.GetConnectionString("hgaction"), ServerVersion.AutoDetect(config.GetConnectionString("hgaction")));
|
||||
//});
|
||||
services.AddDGEntityFramework<CrmCloudDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("crmcloud"), ServerVersion.AutoDetect(config.GetConnectionString("crmcloud")));
|
||||
});
|
||||
|
||||
services.AddWorker(config);
|
||||
services.AddDGHttpClient();
|
||||
services.AddRegisterWorker<SynchronousWorker>();
|
||||
var builder = new HostBuilder();
|
||||
await builder.RunConsoleAsync();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"WeworkUserWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,452 @@
|
|||
using DG.Core;
|
||||
using DG.EntityFramework;
|
||||
using DG.Worker;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Entity.Dncms;
|
||||
using Zxd.Entity;
|
||||
using Zxd.EntityFramework;
|
||||
using EmployeeDepartmentDetailServices.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static System.Formats.Asn1.AsnWriter;
|
||||
using Zxd.Entity.CompanyBaseConf;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using DG.Tool;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
using Zxd.Entity.Zxd;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Engineering;
|
||||
|
||||
namespace EmployeeDepartmentDetailServices.Worker
|
||||
{
|
||||
internal class SynchronousWorker : WorkerBase, IDisposable
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILogger<SynchronousWorker> _logger;
|
||||
private readonly SystemConfig? _systemConfig;
|
||||
private static bool IsFrist = true;
|
||||
|
||||
public SynchronousWorker(ILogger<SynchronousWorker> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
IHttpClient httpClient
|
||||
) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
_serviceProvider = serviceProvider;
|
||||
_systemConfig = configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Zxd.Entity.Zxd.EmployeeDepartmentDetail> changeEdd = new List<Zxd.Entity.Zxd.EmployeeDepartmentDetail>();
|
||||
List<Zxd.Entity.Zxd.EmployeeDepartmentFull> changeEd = new List<Zxd.Entity.Zxd.EmployeeDepartmentFull>();
|
||||
List<Zxd.Entity.Zxd.ZXDDepartment> changeDepart = new List<Zxd.Entity.Zxd.ZXDDepartment>();
|
||||
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var companyBaseConfRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<CompanyBaseConfDbContext>>();
|
||||
var zxdRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<ZxdDbContext>>();
|
||||
var crmCloudRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<CrmCloudDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
|
||||
//从员工系统同步数据
|
||||
var employeedepartmentdetail = companyBaseConfRepository.GetRepository<Zxd.Entity.CompanyBaseConf.EmployeeDepartmentDetail>().Query();
|
||||
var applicationpartment = companyBaseConfRepository.GetRepository<Zxd.Entity.CompanyBaseConf.ApplicationDepartment>().Query();
|
||||
var application = companyBaseConfRepository.GetRepository<Zxd.Entity.CompanyBaseConf.Application>().Query();
|
||||
var department = companyBaseConfRepository.GetRepository<Zxd.Entity.CompanyBaseConf.Department>().Query();
|
||||
|
||||
var employ = companyBaseConfRepository.GetRepository<Zxd.Entity.CompanyBaseConf.Employee>().Query();
|
||||
var deptment = await _httpClient.GetAsync<ApiResult<List<DeptmentDto>>>($"{_systemConfig.zxdCoreApi}/Api/Deptment/Depts");//员工系统部门关心
|
||||
if (DateTime.Now.Hour == _systemConfig.clearEDDHour)
|
||||
{ //固定时间
|
||||
//全量清空重新同步
|
||||
Log.Error("清空历史数据:"+ DateTime.Now.Hour);
|
||||
await zxdRepository.ExecuteSqlCommandNonQueryAsync(System.Data.CommandType.Text, "truncate table employee_department_detail");
|
||||
await crmCloudRepository.ExecuteSqlCommandNonQueryAsync(System.Data.CommandType.Text, "truncate table employee_department_detail");
|
||||
await dncmsbaseRepository.ExecuteSqlCommandNonQueryAsync(System.Data.CommandType.Text, "truncate table employee_department_detail");
|
||||
}
|
||||
|
||||
#region 处理数据
|
||||
var zxdEdd = zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentDetail>().Query();
|
||||
DateTime eddMaxUpDate = zxdEdd.Any() ? zxdEdd.Max(m => m.update_time) : new DateTime();
|
||||
|
||||
var newEmp = employeedepartmentdetail.Where(m => m.update_time > eddMaxUpDate).ToList();//需要入库的部分
|
||||
var eidDic = employ.ToDictionary(m => m.id, n => n.employee_id);
|
||||
var statusDic = employ.ToDictionary(m => m.id, n => n.status);
|
||||
var deptDic = department.ToDictionary(m => m.Id, n => n.DepartmentName);
|
||||
foreach (var item in newEmp)
|
||||
{
|
||||
Zxd.Entity.Zxd.EmployeeDepartmentDetail eddItem = new Zxd.Entity.Zxd.EmployeeDepartmentDetail();
|
||||
eddItem.id = item.id;
|
||||
eddItem.eid = 0;
|
||||
eddItem.empStatus = 4;
|
||||
if (eidDic.ContainsKey(item.emp_id))
|
||||
{
|
||||
eddItem.eid = eidDic[item.emp_id];//匹配eid
|
||||
eddItem.empStatus = statusDic[item.emp_id] ?? 0;
|
||||
}
|
||||
else
|
||||
{ //找不到工号
|
||||
continue;
|
||||
}
|
||||
if (deptDic.ContainsKey(item.department_id))
|
||||
{
|
||||
eddItem.department_name = deptDic[item.department_id];
|
||||
}
|
||||
eddItem.department_id = item.department_id;
|
||||
eddItem.department_type = item.department_type;
|
||||
eddItem.level = item.level;
|
||||
eddItem.is_deleted = item.is_deleted;
|
||||
eddItem.create_time = item.create_time;
|
||||
eddItem.update_time = item.update_time;
|
||||
changeEdd.Add(eddItem);
|
||||
}
|
||||
|
||||
var zxdEddIdList = zxdEdd.Select(m => m.id).ToList();
|
||||
var updateEdd = changeEdd.Where(m => zxdEddIdList.Contains(m.id)).ToList();
|
||||
var insertEdd = changeEdd.Where(m => !zxdEddIdList.Contains(m.id)).ToList();
|
||||
|
||||
#endregion 处理数据
|
||||
|
||||
#region 处理部门信息
|
||||
|
||||
var zxdDepart = zxdRepository.GetRepository<Zxd.Entity.Zxd.ZXDDepartment>().Query();
|
||||
DateTime DepartMaxUpDate = zxdDepart.Any() ? zxdDepart.Max(m => m.Update_Time) : new DateTime();
|
||||
var newDepart = department.Where(m => m.Update_Time > eddMaxUpDate).ToList();//需要入库的部分
|
||||
foreach (var item in newDepart)
|
||||
{
|
||||
Zxd.Entity.Zxd.ZXDDepartment depart = new Zxd.Entity.Zxd.ZXDDepartment();
|
||||
depart.Id = item.Id;
|
||||
depart.ParentId = item.ParentId;
|
||||
depart.DepartmentName = item.DepartmentName;
|
||||
depart.DepartmentCode = item.DepartmentCode;
|
||||
depart.DepartmentType = item.DepartmentType;
|
||||
depart.Status = item.Status;
|
||||
depart.IsDeleted = item.IsDeleted;
|
||||
depart.Create_Time = item.Create_Time;
|
||||
depart.Update_Time = item.Update_Time;
|
||||
changeDepart.Add(depart);
|
||||
}
|
||||
|
||||
var zxDepart = zxdDepart.Select(m => m.Id).ToList();
|
||||
var updateDepart = changeDepart.Where(m => zxDepart.Contains(m.Id)).ToList();
|
||||
var insertDepart = changeDepart.Where(m => !zxDepart.Contains(m.Id)).ToList();
|
||||
|
||||
#endregion 处理部门信息
|
||||
|
||||
#region 处理员工归属事业部关系
|
||||
|
||||
var zxdEDF = zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentFull>().Query().ToList();
|
||||
|
||||
List<Zxd.Entity.Zxd.EmployeeDepartmentFull> deleteEdf = new List<Zxd.Entity.Zxd.EmployeeDepartmentFull>();
|
||||
List<Zxd.Entity.Zxd.EmployeeDepartmentFull> insertEdf = new List<Zxd.Entity.Zxd.EmployeeDepartmentFull>();
|
||||
List<Zxd.Entity.Zxd.EmployeeDepartmentFull> allEdf = new List<Zxd.Entity.Zxd.EmployeeDepartmentFull>();
|
||||
var edList = await companyBaseConfRepository.ExecuteSqlToListAsync<EmpAppItem>(@"select a.emp_id,concat(c.app_id,'') app_id,c.application_name
|
||||
from employee_department_detail a
|
||||
left join application_department b on a.department_id=b.department_id
|
||||
left join application c on b.application_id=c.id
|
||||
where a.is_deleted =0 and b.is_deleted =0 and c.is_deleted =0
|
||||
group by a.emp_id,c.app_id");
|
||||
//拼接数据
|
||||
foreach (var item in edList)
|
||||
{
|
||||
Zxd.Entity.Zxd.EmployeeDepartmentFull edf = new Zxd.Entity.Zxd.EmployeeDepartmentFull();
|
||||
if (eidDic.ContainsKey(item.emp_id))
|
||||
{
|
||||
edf.eid = eidDic[item.emp_id];//匹配eid
|
||||
}
|
||||
else
|
||||
{ //找不到工号
|
||||
continue;
|
||||
}
|
||||
edf.appid = item.app_id;
|
||||
edf.app_name = item.application_name;
|
||||
edf.create_time = DateTime.Now;
|
||||
if (!zxdEDF.Any(n => n.appid == edf.appid && n.eid == edf.eid))
|
||||
{//不存在
|
||||
insertEdf.Add(edf);//新增
|
||||
}
|
||||
allEdf.Add(edf);
|
||||
}
|
||||
foreach (var item in zxdEDF)
|
||||
{
|
||||
if (!allEdf.Any(n => n.appid == item.appid && n.eid == item.eid))//全量数据中 不存在的旧数据
|
||||
{
|
||||
deleteEdf.Add(item);//新增
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 处理员工归属事业部关系
|
||||
|
||||
#region 同步到zxd
|
||||
|
||||
using var transaction = await zxdRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentDetail>().BatchUpdateAsync(updateEdd);
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentDetail>().BatchInsertAsync(insertEdd);
|
||||
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentFull>().BatchDeleteAsync(deleteEdf);
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.EmployeeDepartmentFull>().BatchInsertAsync(insertEdf);
|
||||
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.ZXDDepartment>().BatchUpdateAsync(updateDepart);
|
||||
await zxdRepository.GetRepository<Zxd.Entity.Zxd.ZXDDepartment>().BatchInsertAsync(insertDepart);
|
||||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "同步失败!");
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
}
|
||||
|
||||
#endregion 同步到zxd
|
||||
|
||||
#region 同步到crm_cloud
|
||||
|
||||
using var hgtransaction = await crmCloudRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.EmployeeDepartmentDetail>().BatchUpdateAsync(Mapping(updateEdd));
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.EmployeeDepartmentDetail>().BatchInsertAsync(Mapping(insertEdd));
|
||||
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.EmployeeDepartmentFull>().BatchDeleteAsync(Mapping(deleteEdf));
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.EmployeeDepartmentFull>().BatchInsertAsync(Mapping(insertEdf));
|
||||
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.HGDepartment>().BatchUpdateAsync(Mapping(updateDepart));
|
||||
await crmCloudRepository.GetRepository<Zxd.Entity.HgAction.HGDepartment>().BatchInsertAsync(Mapping(insertDepart));
|
||||
|
||||
await hgtransaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "同步失败!");
|
||||
await hgtransaction.RollbackAsync();
|
||||
await hgtransaction.DisposeAsync();
|
||||
}
|
||||
|
||||
#endregion 同步到hgaction
|
||||
|
||||
#region 同步到hncmsbase
|
||||
|
||||
using var dncmsbase = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.EmployeeDepartmentDetail>().BatchUpdateAsync(MappingToDncms(updateEdd));
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.EmployeeDepartmentDetail>().BatchInsertAsync(MappingToDncms(insertEdd));
|
||||
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.EmployeeDepartmentFull>().BatchDeleteAsync(MappingToDncms(deleteEdf));
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.EmployeeDepartmentFull>().BatchInsertAsync(MappingToDncms(insertEdf));
|
||||
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.Department>().BatchUpdateAsync(MappingToDncms(updateDepart));
|
||||
await dncmsbaseRepository.GetRepository<Zxd.Entity.Dncms.Department>().BatchInsertAsync(MappingToDncms(insertDepart));
|
||||
|
||||
await dncmsbase.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "同步失败!");
|
||||
await dncmsbase.RollbackAsync();
|
||||
await dncmsbase.DisposeAsync();
|
||||
}
|
||||
|
||||
#endregion 同步到hncmsbase
|
||||
|
||||
#region 推送到坐席
|
||||
|
||||
//var eddGup = changeEdd.GroupBy(m => m.department_id);
|
||||
//foreach (var item in eddGup)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// int psize = 10;
|
||||
// var dept = deptment.Data.FirstOrDefault(m => m.DepartmentId == item.Key);
|
||||
// if (dept != null)
|
||||
// {
|
||||
// var url = $"{_systemConfig?.crmCoreApi}/Api/Customer/SynchronousCustomer";
|
||||
// if (item.Count() < psize)
|
||||
// {
|
||||
// var data = await _httpClient.PostAsync<ApiResult<bool>>(url, new { eddList = item.ToList() }, dept.Appid);//
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //分页推送
|
||||
// int maxIndex = (item.Count() % psize) + 1;
|
||||
// int pindex = 1;
|
||||
// while (pindex <= maxIndex)
|
||||
// {
|
||||
// var list = item.ToList().Skip((pindex - 1) * psize).Take(psize).ToList();
|
||||
// var res = await _httpClient.PostAsync<ApiResult<bool>>(url, new { eddList = list }, dept.Appid);//
|
||||
// pindex++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Log.Error(ex, "推送失败!");
|
||||
// continue;
|
||||
// }
|
||||
//}
|
||||
|
||||
#endregion 推送到坐席
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "同步失败!");
|
||||
}
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.HgAction.EmployeeDepartmentDetail> Mapping(List<Zxd.Entity.Zxd.EmployeeDepartmentDetail> list)
|
||||
{
|
||||
List<Zxd.Entity.HgAction.EmployeeDepartmentDetail> res = new List<Zxd.Entity.HgAction.EmployeeDepartmentDetail>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.HgAction.EmployeeDepartmentDetail i = new Zxd.Entity.HgAction.EmployeeDepartmentDetail();
|
||||
i.id = item.id;
|
||||
i.eid = item.eid;
|
||||
i.department_id = item.department_id;
|
||||
i.department_name = item.department_name;
|
||||
i.department_type = item.department_type;
|
||||
i.empStatus = item.empStatus;
|
||||
i.level = item.level;
|
||||
i.is_deleted = item.is_deleted;
|
||||
i.create_time = item.create_time;
|
||||
i.update_time = item.update_time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.HgAction.EmployeeDepartmentFull> Mapping(List<Zxd.Entity.Zxd.EmployeeDepartmentFull> list)
|
||||
{
|
||||
List<Zxd.Entity.HgAction.EmployeeDepartmentFull> res = new List<Zxd.Entity.HgAction.EmployeeDepartmentFull>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.HgAction.EmployeeDepartmentFull i = new Zxd.Entity.HgAction.EmployeeDepartmentFull();
|
||||
i.id = item.id;
|
||||
i.eid = item.eid;
|
||||
i.appid = item.appid;
|
||||
i.app_name = item.app_name;
|
||||
i.create_time = item.create_time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.HgAction.HGDepartment> Mapping(List<Zxd.Entity.Zxd.ZXDDepartment> list)
|
||||
{
|
||||
List<Zxd.Entity.HgAction.HGDepartment> res = new List<Zxd.Entity.HgAction.HGDepartment>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.HgAction.HGDepartment i = new Zxd.Entity.HgAction.HGDepartment();
|
||||
i.Id = item.Id;
|
||||
i.ParentId = item.ParentId;
|
||||
i.DepartmentName = item.DepartmentName;
|
||||
i.DepartmentType = item.DepartmentType;
|
||||
i.DepartmentCode = item.DepartmentCode;
|
||||
i.IsDeleted = item.IsDeleted;
|
||||
i.Status = item.Status;
|
||||
i.Create_Time = item.Create_Time;
|
||||
i.Update_Time = item.Update_Time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.Dncms.EmployeeDepartmentDetail> MappingToDncms(List<Zxd.Entity.Zxd.EmployeeDepartmentDetail> list)
|
||||
{
|
||||
List<Zxd.Entity.Dncms.EmployeeDepartmentDetail> res = new List<Zxd.Entity.Dncms.EmployeeDepartmentDetail>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.Dncms.EmployeeDepartmentDetail i = new Zxd.Entity.Dncms.EmployeeDepartmentDetail();
|
||||
i.id = item.id;
|
||||
i.eid = item.eid;
|
||||
i.department_id = item.department_id;
|
||||
i.department_name = item.department_name;
|
||||
i.department_type = item.department_type;
|
||||
i.empStatus = item.empStatus;
|
||||
i.level = item.level;
|
||||
i.is_deleted = item.is_deleted;
|
||||
i.create_time = item.create_time;
|
||||
i.update_time = item.update_time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.Dncms.EmployeeDepartmentFull> MappingToDncms(List<Zxd.Entity.Zxd.EmployeeDepartmentFull> list)
|
||||
{
|
||||
List<Zxd.Entity.Dncms.EmployeeDepartmentFull> res = new List<Zxd.Entity.Dncms.EmployeeDepartmentFull>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.Dncms.EmployeeDepartmentFull i = new Zxd.Entity.Dncms.EmployeeDepartmentFull();
|
||||
i.id = item.id;
|
||||
i.eid = item.eid;
|
||||
i.appid = item.appid;
|
||||
i.app_name = item.app_name;
|
||||
i.create_time = item.create_time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private List<Zxd.Entity.Dncms.Department> MappingToDncms(List<Zxd.Entity.Zxd.ZXDDepartment> list)
|
||||
{
|
||||
List<Zxd.Entity.Dncms.Department> res = new List<Zxd.Entity.Dncms.Department>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
Zxd.Entity.Dncms.Department i = new Zxd.Entity.Dncms.Department();
|
||||
i.Id = item.Id;
|
||||
i.ParentId = item.ParentId;
|
||||
i.DepartmentName = item.DepartmentName;
|
||||
i.DepartmentType = item.DepartmentType;
|
||||
i.DepartmentCode = item.DepartmentCode;
|
||||
i.IsDeleted = item.IsDeleted;
|
||||
i.Status = item.Status;
|
||||
i.Create_Time = item.Create_Time;
|
||||
i.Update_Time = item.Update_Time;
|
||||
res.Add(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_logger.LogInformation("任务正在关闭");
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var configs = dncmsRepository.GetRepository<ResourceFlowConfig>().Query()
|
||||
.Where(x => x.Status == ResourceConfigStatus.执行中).ToList();
|
||||
|
||||
configs.ForEach(x => x.Status = ResourceConfigStatus.待重启);
|
||||
|
||||
dncmsRepository.GetRepository<ResourceFlowConfig>().BatchUpdateAsync(configs, x => new { x.Status });
|
||||
}
|
||||
}
|
||||
|
||||
public class EmpAppItem
|
||||
{
|
||||
public int emp_id { get; set; }
|
||||
public string? app_id { get; set; }
|
||||
public string? application_name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crm": "Server=192.168.11.141;Database=db_crm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crmcloud": "Server=192.168.11.141;Database=crm_cloud;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "DG.SynchronousWorker",
|
||||
"TaskRemarks": "DG.SynchronousWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 90
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "tmrp0GmwyTMe6UxJIw7LXAcIWYKEUgy2kprMiybd"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089",
|
||||
"nodeWebApi": "http://120.238.224.24:10034",
|
||||
"crmCoreApi": "http://192.168.11.81:8088",
|
||||
"clearEDDHour": "1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"crm": "Server=mysql98ff96c3dffa.rds.ivolces.com;Database=db_crm;UserId=qianbenjie;Password=Hcqianbenjie@123;port=3306;",
|
||||
"crmcloud": "Data Source=dgbigdata.mysql.rds.aliyuncs.com;Port=3306;Initial Catalog=crm_cloud;user id=crm_rd;password=K#RQ1TYx9my;SslMode=None;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "DG.SynchronousWorker",
|
||||
"TaskRemarks": "DG.SynchronousWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 3600
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "tmrp0GmwyTMe6UxJIw7LXAcIWYKEUgy2kprMiybd"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"nodeWebApi": "http://120.238.224.24:10034",
|
||||
"crmCoreApi": "http://api.crm.tcfortune.com:8282",
|
||||
"clearEDDHour": "1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crm": "Server=192.168.11.141;Database=db_crm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crmcloud": "Server=192.168.11.141;Database=crm_cloud;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "DG.SynchronousWorker",
|
||||
"TaskRemarks": "DG.SynchronousWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 60
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "tmrp0GmwyTMe6UxJIw7LXAcIWYKEUgy2kprMiybd"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089",
|
||||
"nodeWebApi": "http://120.238.224.24:10034",
|
||||
//"crmCoreApi": "https://localhost:7234"
|
||||
"crmCoreApi": "http://192.168.11.80:8088",
|
||||
"clearEDDHour": "1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"ResourceFlowWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ResourceFlowWorker.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public string zxdCoreApi { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["ResourceFlowWorker/ResourceFlowWorker.csproj", "ResourceFlowWorker/"]
|
||||
COPY ["Zxd.Core.Shared/Zxd.Core.Shared.csproj", "Zxd.Core.Shared/"]
|
||||
COPY ["Zxd.EntityFramework/Zxd.EntityFramework.csproj", "Zxd.EntityFramework/"]
|
||||
COPY ["Zxd.Entity/Zxd.Entity.csproj", "Zxd.Entity/"]
|
||||
RUN dotnet restore "ResourceFlowWorker/ResourceFlowWorker.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/ResourceFlowWorker"
|
||||
RUN dotnet build "ResourceFlowWorker.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "ResourceFlowWorker.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "ResourceFlowWorker.dll"]
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["WeworkUserWorker/WeworkUserWorker.csproj", "WeworkUserWorker/"]
|
||||
COPY ["Zxd.Core.Shared/Zxd.Core.Shared.csproj", "Zxd.Core.Shared/"]
|
||||
COPY ["Zxd.EntityFramework/Zxd.EntityFramework.csproj", "Zxd.EntityFramework/"]
|
||||
COPY ["Zxd.Entity/Zxd.Entity.csproj", "Zxd.Entity/"]
|
||||
RUN dotnet restore "WeworkUserWorker/WeworkUserWorker.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/WeworkUserWorker"
|
||||
RUN dotnet build "WeworkUserWorker.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "WeworkUserWorker.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "WeworkUserWorker.dll"]
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ResourceFlowWorker.Dto
|
||||
{
|
||||
internal class LivePageDto<TTableData>
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前页码
|
||||
/// </summary>
|
||||
[JsonPropertyName("currentPage")]
|
||||
public int? CurrentPage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每页记录数
|
||||
/// </summary>
|
||||
[JsonPropertyName("pageSize")]
|
||||
public int? PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列表数据
|
||||
/// </summary>
|
||||
[JsonPropertyName("tableData")]
|
||||
public List<TTableData> TableData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总记录数
|
||||
/// </summary>
|
||||
[JsonPropertyName("total")]
|
||||
public long Total { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ResourceFlowWorker.Dto
|
||||
{
|
||||
internal class ResourceFlowCustomerAndUserDto
|
||||
{
|
||||
public string? Appid { get; set; }
|
||||
|
||||
|
||||
public string? Userid { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Entity.Dncms;
|
||||
|
||||
namespace ResourceFlowWorker.Dto
|
||||
{
|
||||
internal class ResourceFlowWorkerDto
|
||||
{
|
||||
}
|
||||
|
||||
internal class ResourceFlowFromDto
|
||||
{
|
||||
public ResourceFlowFromDto(ResourceFlowConfig? config, ResourceFlowConfigFrom? from, List<ResourceCountReturnModel> sourceResources)
|
||||
{
|
||||
Config = config;
|
||||
From = from;
|
||||
SourceResources = sourceResources;
|
||||
OperateResources = JsonHelper.FromJson<List<ResourceCountReturnModel>>(sourceResources.ToJson());
|
||||
AssignedCount = 0;
|
||||
}
|
||||
|
||||
public ResourceFlowConfig Config { get; set; }
|
||||
|
||||
public ResourceFlowConfigFrom From { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 源人群包信息
|
||||
/// </summary>
|
||||
public List<ResourceCountReturnModel> SourceResources { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人群包信息
|
||||
/// </summary>
|
||||
public List<ResourceCountReturnModel> OperateResources { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已分配数量
|
||||
/// </summary>
|
||||
public int AssignedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权重
|
||||
/// </summary>
|
||||
public decimal Weight
|
||||
{
|
||||
get
|
||||
{
|
||||
return SourceResources.Count == 0 ? 0 : (SourceResources.Count - OperateResources.Count) / SourceResources.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ResourceCountQueryDto
|
||||
{
|
||||
public string groupids { get; set; }
|
||||
public string userids { get; set; }
|
||||
public string appid { get; set; }
|
||||
public int page { get; set; } = 1;
|
||||
public int limit { get; set; } = 100000;
|
||||
}
|
||||
|
||||
internal class ResourceCountReturnModel
|
||||
{
|
||||
public string? _nickname { get; set; }
|
||||
public string? _appuserid { get; set; }
|
||||
public string? _headimgurl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
try
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Console.WriteLine($"Env: {env}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env ?? "Production"}.json", true)
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{env ?? "Production"}.json", true)
|
||||
.Build();
|
||||
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(config)
|
||||
.WriteTo.Exceptionless(config.GetValue<string>("Exceptionless:ApiKey"), config.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "WeworkUserWorker" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
Log.Information("Starting ResourceFlowWorker");
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog();
|
||||
});
|
||||
services.AddSingleton<IConfiguration>(config);
|
||||
services.AddOptions()
|
||||
.Configure<SystemConfig>(e => config.GetSection("SystemConfig").Bind(e));
|
||||
ExceptionlessClient.Default.Startup(config.GetValue<string>("Exceptionless:ApiKey"));
|
||||
ExceptionlessClient.Default.Configuration.ServerUrl = config.GetValue<string>("Exceptionless:ServerUrl");
|
||||
ExceptionlessClient.Default.Configuration.DefaultTags.Add("zxd-ResourceFlowWorker");
|
||||
//services.AddRedis(config);
|
||||
services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(config.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsbaseDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncmsbase"), ServerVersion.AutoDetect(config.GetConnectionString("dncmsbase")));
|
||||
});
|
||||
services.AddDGEntityFramework<UserCenterDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("usercenter"), ServerVersion.AutoDetect(config.GetConnectionString("usercenter")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncms"), ServerVersion.AutoDetect(config.GetConnectionString("dncms")));
|
||||
});
|
||||
services.AddDGEntityFramework<CompanyBaseConfDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("companyBaseConf"), ServerVersion.AutoDetect(config.GetConnectionString("companyBaseConf")));
|
||||
});
|
||||
services.AddWorker(config);
|
||||
services.AddDGHttpClient();
|
||||
services.AddRegisterWorker<ResourceWorker>();
|
||||
var builder = new HostBuilder();
|
||||
await builder.RunConsoleAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"ResourceFlowWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.dockerignore" Link=".dockerignore">
|
||||
<DependentUpon>$(DockerDefaultDockerfile)</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DG.Core" Version="1.0.25" />
|
||||
<PackageReference Include="DG.Redis" Version="1.0.17" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.9" />
|
||||
<PackageReference Include="DG.Worker" Version="1.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Exceptionless" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
|
||||
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="DG.Tool" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="ResourceFlowWorker.Workers" />
|
||||
<Using Include="ResourceFlowWorker.Dto" />
|
||||
<Using Include="DG.Worker" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="DG.EntityFramework" />
|
||||
<Using Include="Zxd.Entity" />
|
||||
<Using Include="ResourceFlowWorker.Config" />
|
||||
<Using Include="Exceptionless" />
|
||||
<Using Include="Microsoft.Extensions.Hosting" />
|
||||
<Using Include="Zxd.EntityFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Disaster.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Warning",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
using Exceptionless.Utility;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using ResourceFlowWorker.Config;
|
||||
using ResourceFlowWorker.Dto;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Entity.Dncms;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
namespace ResourceFlowWorker.Workers
|
||||
{
|
||||
internal class ResourceWorker : WorkerBase, IDisposable
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ILogger<ResourceWorker> _logger;
|
||||
private readonly SystemConfig? _systemConfig;
|
||||
private static bool IsFrist = true;
|
||||
|
||||
public ResourceWorker(ILogger<ResourceWorker> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
IHttpClient httpClient
|
||||
) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
_serviceProvider = serviceProvider;
|
||||
_systemConfig = configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync()
|
||||
{
|
||||
var status = new List<ResourceConfigStatus> { ResourceConfigStatus.待执行 };
|
||||
if (IsFrist)
|
||||
{
|
||||
IsFrist = !IsFrist;
|
||||
status.Add(ResourceConfigStatus.执行中);
|
||||
status.Add(ResourceConfigStatus.待重启);
|
||||
}
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var configs = await dncmsRepository.GetRepository<ResourceFlowConfig>().Query()
|
||||
.Where(x => status.Contains(x.Status)).ToListAsync();
|
||||
if (configs.Any())
|
||||
{
|
||||
configs.ForEach(x => x.Status = ResourceConfigStatus.执行中);
|
||||
await dncmsRepository.GetRepository<ResourceFlowConfig>().BatchUpdateAsync(configs, x => new { x.Status });
|
||||
|
||||
foreach (var config in configs)
|
||||
{
|
||||
var fromList = await dncmsRepository.GetRepository<ResourceFlowConfigFrom>().Query()
|
||||
.Where(x => x.ConfigId == config.Id).ToListAsync();
|
||||
var toList = await dncmsRepository.GetRepository<ResourceFlowConfigTo>().Query()
|
||||
.Where(x => x.ConfigId == config.Id).ToListAsync();
|
||||
await DoDistribute(config, fromList, toList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行分配
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task DoDistribute(ResourceFlowConfig config, List<ResourceFlowConfigFrom> froms, List<ResourceFlowConfigTo> tos)
|
||||
{
|
||||
var flowFroms = new List<ResourceFlowFromDto>();
|
||||
foreach (var from in froms)
|
||||
{
|
||||
var sourceResourceResult = await _httpClient.GetAsync<ApiResult<LivePageDto<ResourceCountReturnModel>>>($"{_systemConfig.zxdCoreApi}/Api/WeWorkResource/KFResourceCount?groupids={config.GroupId}&userids={from.Userid}&appid={config.Appid}&page=1&limit=10000");
|
||||
if (sourceResourceResult.Code == 0)
|
||||
{
|
||||
var sourceResources = sourceResourceResult.Data.TableData;
|
||||
// 判断是否离职
|
||||
if (!sourceResources.Any())
|
||||
{
|
||||
sourceResourceResult = await _httpClient.GetAsync<ApiResult<LivePageDto<ResourceCountReturnModel>>>($"{_systemConfig.zxdCoreApi}/Api/WeWorkResource/KFResourceCount?groupids={config.GroupId}&userids={from.Userid}&appid={config.Appid}&page=1&limit=10000&status=0&subscribe=-4");
|
||||
if (sourceResourceResult.Code == 0)
|
||||
{
|
||||
sourceResources = sourceResourceResult.Data.TableData;
|
||||
}
|
||||
}
|
||||
flowFroms.Add(new ResourceFlowFromDto(config, from, sourceResources));
|
||||
}
|
||||
}
|
||||
var logs = new List<ResourceFlowLog>();
|
||||
|
||||
// 离职员工分配逻辑
|
||||
// 目标数量
|
||||
var flowCount = config.FlowCount;
|
||||
var assignedCount = 0;
|
||||
var fromUserids = froms.Select(x => x.Userid).ToList();
|
||||
var toUserids = tos.Select(n => n.Userid).ToList();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var dimissiones = await dncmsRepository.GetRepository<ResourceFlowDimission>().Query()
|
||||
.Where(x => x.Appid == config.Appid && fromUserids.Contains(x.FromUserid)).ToListAsync();
|
||||
if (dimissiones.Count > 0)
|
||||
{
|
||||
Log.Information("处理离职数据");
|
||||
|
||||
Log.Information($"处理离职数据{dimissiones.Count}条");
|
||||
foreach (var flowFrom in flowFroms)
|
||||
{
|
||||
var list = dimissiones.Where(x => x.FromUserid == flowFrom.From.Userid).ToList();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (flowFrom.OperateResources.Any(y => y._appuserid == item.Appuserid))
|
||||
{
|
||||
var resource = flowFrom.OperateResources.Where(y => y._appuserid == item.Appuserid).First();
|
||||
logs.Add(new ResourceFlowLog
|
||||
{
|
||||
Deptid = config.Deptid,
|
||||
Appid = config.Appid,
|
||||
Appuserid = item.Appuserid,
|
||||
FromUserid = flowFrom.From.Userid,
|
||||
ConfigId = config.Id,
|
||||
FlowTime = DateTime.Now,
|
||||
Status = ResourceFlowStatus.待转移,
|
||||
IsDimission = true,
|
||||
});
|
||||
flowFrom.AssignedCount++;
|
||||
assignedCount++;
|
||||
flowFrom.From.TransferCount++;
|
||||
flowFrom.OperateResources.Remove(resource);
|
||||
if (flowCount == assignedCount) break;
|
||||
}
|
||||
}
|
||||
if (flowCount == assignedCount) break;
|
||||
}
|
||||
}
|
||||
// 相同人群包 已分配日志
|
||||
var allOldFromLog = await dncmsRepository.GetRepository<ResourceFlowLog>().Query().Where(x => x.Appid == config.Appid && fromUserids.Contains(x.FromUserid) && x.Status != ResourceFlowStatus.转移成功).ToListAsync();
|
||||
var oldFromLog = new List<ResourceFlowLog>();
|
||||
if (config.GroupId > 0)
|
||||
{
|
||||
oldFromLog = allOldFromLog.Where(x => x.GroupId == config.GroupId).ToList();
|
||||
}
|
||||
//最近一天的 不让重新分配
|
||||
var notPassFromLog = allOldFromLog.Where(n => n.FlowTime >= DateTime.Now.AddDays(-1)).ToList();
|
||||
oldFromLog.AddRange(notPassFromLog);
|
||||
var oldToLog = await dncmsRepository.GetRepository<ResourceFlowLog>().Query()
|
||||
.Where(x => x.Appid == config.Appid && toUserids.Contains(x.ToUserid) && x.GroupId == config.GroupId).ToListAsync();
|
||||
|
||||
while (flowCount > assignedCount)
|
||||
{
|
||||
// 如果队列已经不够好友,跳出循环
|
||||
if (!flowFroms.Any()) { Log.Information("队列已经不够好友,跳出循环"); break; }
|
||||
// 确定权重
|
||||
var first = flowFroms.OrderByDescending(x => x.Weight).First();
|
||||
|
||||
// 如果客服无可分配资源,移除分配队列,重新选择客服
|
||||
if (first.OperateResources.Count == 0)
|
||||
{
|
||||
Log.Information($"客服{first.From.Ename}无可分配资源");
|
||||
flowFroms.Remove(first);
|
||||
continue;
|
||||
}
|
||||
// 随机指定用户
|
||||
var n = new Random().Next(first.OperateResources.Count);
|
||||
// 获取随机用户
|
||||
var resource = first.OperateResources[n];
|
||||
if (logs.Any(x => x.Appid == config.Appid && x.Appuserid == resource._appuserid))
|
||||
{
|
||||
Log.Information($"资源已分配,移除队列后重新分配");
|
||||
first.OperateResources.Remove(resource);
|
||||
continue;
|
||||
}
|
||||
if (oldFromLog.Any(x => x.Appuserid == resource._appuserid && x.FromUserid == first.From.Userid))
|
||||
{
|
||||
Log.Information($"同一个人群包内,已转移过的资源不可再次发起转移{config.Id}【{resource._appuserid}】");
|
||||
first.OperateResources.Remove(resource);
|
||||
continue;
|
||||
}
|
||||
logs.Add(new ResourceFlowLog
|
||||
{
|
||||
Deptid = config.Deptid,
|
||||
Appid = config.Appid,
|
||||
Appuserid = resource._appuserid,
|
||||
FromUserid = first.From.Userid,
|
||||
ConfigId = config.Id,
|
||||
FlowTime = DateTime.Now,
|
||||
Status = ResourceFlowStatus.待转移,
|
||||
IsDimission = false,
|
||||
GroupId = config.GroupId,
|
||||
});
|
||||
// 移除其他客服的相同好友
|
||||
foreach (var from in flowFroms)
|
||||
{
|
||||
var sameResource = from.OperateResources.FirstOrDefault(x => x._appuserid == resource._appuserid);
|
||||
if (sameResource != null)
|
||||
{
|
||||
if (from.From.Id != first.From.Id)
|
||||
{
|
||||
if (oldFromLog.Any(x => x.Appuserid == resource._appuserid && x.FromUserid == from.From.Userid))
|
||||
{
|
||||
Log.Information($"同一个人群包内,已转移过的资源不可再次发起转移{config.Id}【{resource._appuserid}】");
|
||||
first.OperateResources.Remove(sameResource);
|
||||
continue;
|
||||
}
|
||||
logs.Add(new ResourceFlowLog
|
||||
{
|
||||
Deptid = config.Deptid,
|
||||
Appid = config.Appid,
|
||||
Appuserid = resource._appuserid,
|
||||
FromUserid = from.From.Userid,
|
||||
ConfigId = config.Id,
|
||||
FlowTime = DateTime.Now,
|
||||
Status = ResourceFlowStatus.待转移,
|
||||
IsDimission = false,
|
||||
GroupId = config.GroupId,
|
||||
});
|
||||
from.AssignedCount++;
|
||||
from.From.TransferCount++;
|
||||
}
|
||||
from.OperateResources.Remove(sameResource);
|
||||
}
|
||||
}
|
||||
first.AssignedCount++;
|
||||
first.From.TransferCount++;
|
||||
assignedCount++;
|
||||
}
|
||||
//remove时候刷新不对
|
||||
/* foreach (var flowFrom in flowFroms)
|
||||
{
|
||||
flowFrom.From.TransferCount = flowFrom.SourceResources.Count - flowFrom.OperateResources.Count;
|
||||
Log.Information($"客服{flowFrom.From.Ename}转移数量{flowFrom.From.TransferCount}");
|
||||
}*/
|
||||
|
||||
// 分配新客服
|
||||
var toAssignedCount = 0;
|
||||
Log.Information($"分配新客服");
|
||||
//历史客户有转移的日志 则直接分配给目标人
|
||||
var besidesUser = oldToLog.Select(n => n.Appuserid).ToList();
|
||||
foreach (var to in tos)
|
||||
{
|
||||
//客户存在 转移历史 则直接把他装给历史转移对象 资源归一
|
||||
var oldToUser = oldToLog.Where(x => x.ToUserid == to.Userid).Select(n => n.Appuserid).ToList();
|
||||
var toLog = logs.Where(n => oldToUser.Contains(n.Appuserid)).Select(n => n.Appuserid).Distinct().ToList();
|
||||
var toflowCount = to.FlowCount;
|
||||
List<string> appuserList = new List<string>();
|
||||
if (toLog.Count > 0)
|
||||
{
|
||||
appuserList.AddRange(toLog);
|
||||
toflowCount = toLog.Count > toflowCount ? 0 : toflowCount - toLog.Count;
|
||||
}
|
||||
var otheruserid = logs.Where(n => !besidesUser.Contains(n.Appuserid))
|
||||
.Select(n => n.Appuserid).Distinct().Take(toflowCount).ToList();
|
||||
appuserList.AddRange(otheruserid);
|
||||
var resources = logs.Where(n => appuserList.Contains(n.Appuserid)).ToList();
|
||||
if (!resources.Any())
|
||||
{
|
||||
Log.Error("分配数量不足,跳出!");
|
||||
continue;
|
||||
}
|
||||
resources.ForEach(x =>
|
||||
{
|
||||
x.ToUserid = to.Userid;
|
||||
});
|
||||
Log.Information($"{to.Userid}_get_{string.Join(",", resources.Select(n => n.Appuserid))}");
|
||||
var allocationUser = resources.Select(n => n.Appuserid).Distinct().ToList();
|
||||
besidesUser.AddRange(appuserList);
|
||||
besidesUser = besidesUser.Distinct().ToList();
|
||||
}
|
||||
config.Status = ResourceConfigStatus.执行完成;
|
||||
using var transaction = await dncmsRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await dncmsRepository.GetRepository<ResourceFlowConfig>().UpdateAsync(config, x => new { x.Status });
|
||||
await dncmsRepository.GetRepository<ResourceFlowConfigFrom>().BatchUpdateAsync(froms, x => new { x.TransferCount });
|
||||
await dncmsRepository.GetRepository<ResourceFlowLog>().BatchInsertAsync(logs);
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "执行分配服务报错!");
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_logger.LogInformation("任务正在关闭");
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var configs = dncmsRepository.GetRepository<ResourceFlowConfig>().Query()
|
||||
.Where(x => x.Status == ResourceConfigStatus.执行中).ToList();
|
||||
|
||||
configs.ForEach(x => x.Status = ResourceConfigStatus.待重启);
|
||||
|
||||
dncmsRepository.GetRepository<ResourceFlowConfig>().BatchUpdateAsync(configs, x => new { x.Status });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=10.22.15.61;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=10.22.15.68;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=10.22.15.68;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd-ResourceWorker",
|
||||
"TaskRemarks": "Zxd-ResourceWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "UdbvVSdTs1i8lGsaO7hF7MkOil5ArONoTLaEJePn"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"nodeWebApi": "http://10.22.15.5:8080"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd-ResourceWorker",
|
||||
"TaskRemarks": "Zxd-ResourceWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "UdbvVSdTs1i8lGsaO7hF7MkOil5ArONoTLaEJePn"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd-ResourceWorker",
|
||||
"TaskRemarks": "Zxd-ResourceWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "AukFjLDBeABakHa1jS67DXoRFPh5J6TdVjDqFMwx"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public string zxdCoreApi { get; set; }
|
||||
public string BdMarkting { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["ResourceFlowWorker/ResourceFlowWorker.csproj", "ResourceFlowWorker/"]
|
||||
COPY ["Zxd.Core.Shared/Zxd.Core.Shared.csproj", "Zxd.Core.Shared/"]
|
||||
COPY ["Zxd.EntityFramework/Zxd.EntityFramework.csproj", "Zxd.EntityFramework/"]
|
||||
COPY ["Zxd.Entity/Zxd.Entity.csproj", "Zxd.Entity/"]
|
||||
RUN dotnet restore "ResourceFlowWorker/ResourceFlowWorker.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/ResourceFlowWorker"
|
||||
RUN dotnet build "ResourceFlowWorker.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "ResourceFlowWorker.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "ResourceFlowWorker.dll"]
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
using DG.EntityFramework;
|
||||
using DG.Redis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ToDoWorker.Helper;
|
||||
using Zxd.Core.Shared;
|
||||
using Zxd.Core.Shared.Helpers;
|
||||
using Zxd.Entity.Action;
|
||||
using Zxd.Entity.dim;
|
||||
using Zxd.Entity.Zxd;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
namespace ToDoWorker.Domain
|
||||
{
|
||||
public class EventDomain : IEventDomain
|
||||
{
|
||||
private readonly IBaseRepository<ZxdDbContext> _repository;
|
||||
|
||||
private readonly IBaseRepository<CrmCloudDbContext> _actRepository;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly SystemConfig? _systemConfig;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IRedisManager _redisManager;
|
||||
private static string _queueskey = "queue:todoItemQueues";
|
||||
private static string _cachekey = "queue:cacheItem";
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public EventDomain(
|
||||
IBaseRepository<ZxdDbContext> zxdRepository, IBaseRepository<CrmCloudDbContext> actRepository, IMapper mapper,
|
||||
IConfiguration configuration, IHttpClient httpClient, IRedisManager redisManager)
|
||||
{
|
||||
_repository = zxdRepository;
|
||||
_mapper = mapper;
|
||||
_actRepository = actRepository;
|
||||
_configuration = configuration;
|
||||
_systemConfig = _configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
_httpClient = httpClient;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
public async Task<bool> RunEvent(EventDto eventDto)
|
||||
{
|
||||
if (!eventDto.deptid.HasValue)
|
||||
{
|
||||
Log.Error($"无部门不处理{eventDto.ToJson()}");
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
var deptSet = await GetSetting(eventDto);
|
||||
if (deptSet == null)
|
||||
{
|
||||
Log.Error($"没找到相关的业务线配置{eventDto.ToJson()}");
|
||||
return false;
|
||||
}
|
||||
CustomerBehaviorLog newModel = new CustomerBehaviorLog
|
||||
{
|
||||
act_date = Convert.ToDateTime(eventDto.act_date),
|
||||
appid = eventDto.appid,
|
||||
umid = eventDto.umid,
|
||||
appuserid = eventDto.appuserid,
|
||||
resid = eventDto.resid,
|
||||
uid = eventDto.uid,
|
||||
unionid = eventDto.unionid,
|
||||
customerid = eventDto.customerid,
|
||||
user_type = eventDto.user_type,
|
||||
eventid = eventDto.eventid,
|
||||
eventname = eventDto.eventname,
|
||||
eventmemo = eventDto.eventmemo,
|
||||
others = eventDto.others,
|
||||
scenetype = eventDto.scenetype,
|
||||
scenetypename = eventDto.scenetypename,
|
||||
sceneid = eventDto.sceneid,
|
||||
sceneidname = eventDto.sceneidname,
|
||||
scenename = eventDto.scenename,
|
||||
sceneext = eventDto.sceneext,
|
||||
ip = eventDto.ip,
|
||||
channel = eventDto.channel,
|
||||
deptid = eventDto.deptid.GetValueOrDefault(),
|
||||
productplat = eventDto.productplat,
|
||||
productplatname = eventDto.productplatname,
|
||||
sinkClickhouseTable = eventDto.sinkClickhouseTable,
|
||||
updatetime = eventDto.update_time,
|
||||
ctime = DateTime.Now,
|
||||
eventtypename = deptSet.memo,
|
||||
neweventid = deptSet.neweventid,
|
||||
neweventname = deptSet.remark,
|
||||
};
|
||||
if (eventDto.act_time.HasValue)
|
||||
{
|
||||
newModel.act_time = ConvertHelper.JavaLongToDateTime(eventDto.act_time.Value);
|
||||
}
|
||||
if (eventDto.leavetime.HasValue)
|
||||
{
|
||||
newModel.leavetime = ConvertHelper.JavaLongToDateTime(eventDto.leavetime.Value);
|
||||
}
|
||||
newModel.Content = GetNoticeContent(newModel, deptSet);
|
||||
|
||||
//请求大数据接口获取用户昵称和头像
|
||||
// 新增优品信息
|
||||
using var transaction = await _actRepository.BeginTransactionAsync();
|
||||
var url = $"{_systemConfig.BdMarkting}/user/relations?uid={newModel.uid}";
|
||||
var empData = await _httpClient.GetAsync<CommonApiResult<List<CustomerEmployeeMap>>>(url);
|
||||
if (string.IsNullOrWhiteSpace(newModel.umid))
|
||||
{
|
||||
Log.Information($"bigdata: {newModel.uid} {empData.ToJson()}");
|
||||
//var resid = empData.data.FirstOrDefault(n => !string.IsNullOrWhiteSpace(n.resid))?.resid;
|
||||
var umid = empData.data.FirstOrDefault(n => !string.IsNullOrWhiteSpace(n.umid))?.umid;
|
||||
//newModel.resid = resid;
|
||||
newModel.umid = umid;
|
||||
if (string.IsNullOrWhiteSpace(newModel.umid))
|
||||
{
|
||||
// 任务重试入队
|
||||
// 只重试两次
|
||||
if (eventDto.RetryCount <= 1)
|
||||
{
|
||||
var setting = await GetDelaySec();
|
||||
var delaySec = setting == null ? 120 : setting.delaytime.Value;
|
||||
eventDto.RetryCount++;
|
||||
eventDto.TaskTime = DateTime.Now.AddSeconds(delaySec);
|
||||
await _redisManager.EnqueueAsync(_queueskey, eventDto);
|
||||
Log.Information($"reTry{eventDto.uid}【{umid}】");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
//插入行为日志
|
||||
await _actRepository.GetRepository<CustomerBehaviorLog>().InsertAsync(newModel);
|
||||
List<EmployeeTodoitem> todoItemList = new List<EmployeeTodoitem>();
|
||||
|
||||
if (empData != null && empData.code == 0)
|
||||
{
|
||||
var customerEmps = empData.data.Where(n => n.deptid == newModel.deptid).ToList();
|
||||
if (!deptSet.allNotice)
|
||||
{
|
||||
if (deptSet.firstCtime.HasValue && deptSet.firstCtime.Value)
|
||||
{
|
||||
var firemp = customerEmps.OrderBy(n => n.create_time).FirstOrDefault();
|
||||
if (firemp != null)
|
||||
{
|
||||
customerEmps = new List<CustomerEmployeeMap> { firemp };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (customerEmps.Count == 0)
|
||||
{
|
||||
if (deptSet.isforce.Value)
|
||||
{
|
||||
EmployeeTodoitem todoitem = new EmployeeTodoitem
|
||||
{
|
||||
logid = newModel.id,
|
||||
done = false,
|
||||
deptid = newModel.deptid,
|
||||
ctime = DateTime.Now,
|
||||
utime = DateTime.Now,
|
||||
act_date = Convert.ToDateTime(newModel.act_date),
|
||||
act_time = newModel.act_time,
|
||||
appid = newModel.appid,
|
||||
appuserid = newModel.appuserid,
|
||||
resid = newModel.resid,
|
||||
umid = newModel.umid,
|
||||
unionid = newModel.unionid,
|
||||
customerid = newModel.customerid,
|
||||
uid = newModel.uid,
|
||||
user_type = newModel.user_type,
|
||||
eventid = newModel.eventid,
|
||||
eventname = newModel.eventname,
|
||||
eventtypename = newModel.eventtypename,
|
||||
eventmemo = newModel.eventmemo,
|
||||
others = newModel.others,
|
||||
scenetype = newModel.scenetype,
|
||||
scenetypename = newModel.scenetypename,
|
||||
sceneid = newModel.sceneid,
|
||||
sceneidname = newModel.sceneidname,
|
||||
scenename = newModel.scenename,
|
||||
sceneext = newModel.sceneext,
|
||||
ip = newModel.ip,
|
||||
channel = newModel.channel,
|
||||
productplat = newModel.productplat,
|
||||
productplatname = newModel.productplatname,
|
||||
leavetime = newModel.leavetime,
|
||||
neweventid = newModel.neweventid,
|
||||
neweventname = newModel.neweventname,
|
||||
content = newModel.Content,
|
||||
isread = 0
|
||||
};
|
||||
await _actRepository.GetRepository<EmployeeTodoitem>().InsertAsync(todoitem);
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
return true;
|
||||
}
|
||||
//只通知 企微好友 归属关系
|
||||
List<CustomerEmployeeMap> resultEmp = new List<CustomerEmployeeMap>();
|
||||
if (deptSet.is_wework)
|
||||
{
|
||||
resultEmp.AddRange(customerEmps.Where(n => n.is_wework == 1).ToList());
|
||||
}
|
||||
if (deptSet.is_mobile)
|
||||
{
|
||||
resultEmp.AddRange(customerEmps.Where(n => n.is_mobile == 1).ToList());
|
||||
}
|
||||
if (deptSet.is_belong)
|
||||
{
|
||||
resultEmp.AddRange(customerEmps.Where(n => n.is_belong == 1).ToList());
|
||||
}
|
||||
resultEmp = resultEmp.Distinct().ToList();
|
||||
foreach (var item in resultEmp)
|
||||
{
|
||||
EmployeeTodoitem todoitem = new EmployeeTodoitem
|
||||
{
|
||||
logid = newModel.id,
|
||||
eid = item.eid.Value,
|
||||
ename = item.employee_name,
|
||||
done = false,
|
||||
deptid = newModel.deptid,
|
||||
ctime = DateTime.Now,
|
||||
utime = DateTime.Now,
|
||||
Nickname = !string.IsNullOrWhiteSpace(item.Username) ? item.Username : item.Nickname,
|
||||
Headimgurl = item.Headimgurl,
|
||||
act_date = Convert.ToDateTime(newModel.act_date),
|
||||
act_time = newModel.act_time,
|
||||
appid = newModel.appid,
|
||||
appuserid = newModel.appuserid,
|
||||
resid = newModel.resid,
|
||||
unionid = newModel.unionid,
|
||||
umid = newModel.umid,
|
||||
customerid = newModel.customerid,
|
||||
uid = newModel.uid,
|
||||
user_type = newModel.user_type,
|
||||
eventid = newModel.eventid,
|
||||
eventname = newModel.eventname,
|
||||
eventtypename = newModel.eventtypename,
|
||||
eventmemo = newModel.eventmemo,
|
||||
others = newModel.others,
|
||||
scenetype = newModel.scenetype,
|
||||
scenetypename = newModel.scenetypename,
|
||||
sceneid = newModel.sceneid,
|
||||
sceneidname = newModel.sceneidname,
|
||||
scenename = newModel.scenename,
|
||||
sceneext = newModel.sceneext,
|
||||
ip = newModel.ip,
|
||||
channel = newModel.channel,
|
||||
productplat = newModel.productplat,
|
||||
productplatname = newModel.productplatname,
|
||||
leavetime = newModel.leavetime,
|
||||
neweventid = newModel.neweventid,
|
||||
neweventname = newModel.neweventname,
|
||||
content = newModel.Content,
|
||||
isread = 0
|
||||
};
|
||||
|
||||
todoItemList.Add(todoitem);
|
||||
}
|
||||
if (todoItemList.Count > 0)
|
||||
{
|
||||
await _actRepository.GetRepository<EmployeeTodoitem>().BatchInsertAsync(todoItemList);
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"处理待办事项出错{ex.Message}【{eventDto.ToJson()}】");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<ToDoItemDeptMap> GetSetting(EventDto eventDto)
|
||||
|
||||
{
|
||||
var cacheKey = "ToDoItemSetting";
|
||||
var set = await _redisManager.GetAsync<ToDoItemSetting>(cacheKey);
|
||||
if (set == null)
|
||||
{
|
||||
var setting = await _repository.GetRepository<BAS_PARAMETER>().Query().FirstOrDefaultAsync(n => n.PARAKEY == "ToDoItemSetting");
|
||||
if (setting != null && !string.IsNullOrWhiteSpace(setting.PARAVALUE))
|
||||
{
|
||||
set = JsonHelper.FromJson<ToDoItemSetting>(setting.PARAVALUE);
|
||||
await _redisManager.SetAsync<ToDoItemSetting>(cacheKey, set);
|
||||
}
|
||||
}
|
||||
var deptSetList = set.setting.Where(n => n.eventid == eventDto.eventid).ToList();
|
||||
var deptSet = deptSetList.FirstOrDefault();
|
||||
foreach (var item in deptSetList)
|
||||
{
|
||||
deptSet = null;
|
||||
if (!string.IsNullOrWhiteSpace(item.source) && !item.source.Contains(eventDto.sinkClickhouseTable))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.scenetype.Count > 0 && !item.scenetype.Contains(eventDto.scenetype))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.sceneid.Count > 0 && !item.sceneid.Contains(eventDto.sceneid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.deptids.Count > 0 && !item.deptids.Contains(eventDto.deptid.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item.appids.Count > 0 && !item.appids.Contains(eventDto.appid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//找到了 看是否配置了场景
|
||||
deptSet = item;
|
||||
var sceneItem = deptSetList.FirstOrDefault(n => n.scenetype.Contains(eventDto.scenetype));
|
||||
if (sceneItem != null)
|
||||
{
|
||||
deptSet = sceneItem;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return deptSet;
|
||||
}
|
||||
|
||||
public async Task<ToDoItemSetting> GetDelaySec()
|
||||
{
|
||||
var cacheKey = "ToDoItemSetting";
|
||||
var set = await _redisManager.GetAsync<ToDoItemSetting>(cacheKey);
|
||||
if (set == null)
|
||||
{
|
||||
var setting = await _repository.GetRepository<BAS_PARAMETER>().Query().FirstOrDefaultAsync(n => n.PARAKEY == "ToDoItemSetting");
|
||||
if (setting != null && !string.IsNullOrWhiteSpace(setting.PARAVALUE))
|
||||
{
|
||||
set = JsonHelper.FromJson<ToDoItemSetting>(setting.PARAVALUE);
|
||||
await _redisManager.SetAsync(cacheKey, set);
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private string GetNoticeContent(CustomerBehaviorLog log, ToDoItemDeptMap set)
|
||||
{
|
||||
var content = set.template;
|
||||
Type type = typeof(CustomerBehaviorLog);
|
||||
PropertyInfo[] propertyInfo = type.GetProperties();
|
||||
foreach (var item in propertyInfo)
|
||||
{
|
||||
var value = item.GetValue(log);
|
||||
var setValue = value == null ? "" : value.ToString();
|
||||
var name = "{" + item.Name + "}";
|
||||
if (name == "{act_date}" && content.Contains(name))
|
||||
{
|
||||
content = content.Replace(name, Convert.ToDateTime(setValue).ToString("yyyy-MM-dd"));
|
||||
continue;
|
||||
}
|
||||
if (content.Contains(name))
|
||||
{
|
||||
content = content.Replace(name, setValue);
|
||||
}
|
||||
}
|
||||
content = content.Replace("----", "-").Replace("---", "-").Replace("--", "-").Trim('-');
|
||||
return content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过滤登录事件
|
||||
/// </summary>
|
||||
/// <param name="eventDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> FilterLogEvent(EventDto eventDto, ToDoItemDeptMap setting)
|
||||
{
|
||||
List<string> redisKey = new List<string>();
|
||||
|
||||
var residkey = setting.residkey;
|
||||
var useridkey = setting.key;
|
||||
if (string.IsNullOrWhiteSpace(useridkey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
redisKey.Add(useridkey);
|
||||
if (!string.IsNullOrWhiteSpace(residkey))
|
||||
{
|
||||
redisKey.Add(residkey);
|
||||
}
|
||||
if (eventDto.eventid == (int)EventEnum.登录 && eventDto.sceneid == "soft.login")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(eventDto.appuserid))
|
||||
{
|
||||
Log.Information($"appuserid为空{eventDto.uid}");
|
||||
return false;
|
||||
}
|
||||
foreach (var rkey in redisKey)
|
||||
{
|
||||
//resid缓存 resid不等于空才生效
|
||||
if (rkey.Contains("resid") && string.IsNullOrWhiteSpace(eventDto.resid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var key = rkey.ToString();
|
||||
Type type = typeof(EventDto);
|
||||
PropertyInfo[] propertyInfo = type.GetProperties();
|
||||
foreach (var item in propertyInfo)
|
||||
{
|
||||
var value = item.GetValue(eventDto);
|
||||
var setValue = value == null ? "" : value.ToString();
|
||||
var name = "{" + item.Name + "}";
|
||||
if (key.Contains(name))
|
||||
{
|
||||
key = key.Replace(name, setValue);
|
||||
}
|
||||
}
|
||||
if (key.Contains("date_"))
|
||||
{
|
||||
var replaceStr = key.Split("date_").LastOrDefault();
|
||||
var date = DateTime.Now.ToString(replaceStr.Trim('}').ToString());
|
||||
var dateStr = "{date_" + replaceStr;
|
||||
key = key.Replace(dateStr, date);
|
||||
}
|
||||
//如果redis存在对应的键值 则只出现一次通知
|
||||
if (await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
await _redisManager.SetAsync(key, 1, TimeSpan.FromDays(1));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> Repairdata()
|
||||
{
|
||||
var sql = @"select * from eventdwd";
|
||||
var data = await _actRepository.ExecuteSqlToListAsync<Eventdwd>(sql);
|
||||
foreach (var item in data)
|
||||
{
|
||||
EventDto eventDto = new EventDto()
|
||||
{
|
||||
act_date = item.act_date.ToString(),
|
||||
appid = item.appid,
|
||||
appuserid = item.appuserid,
|
||||
resid = item.resid,
|
||||
unionid = item.unionid,
|
||||
channel = item.channel,
|
||||
customerid = item.customerid,
|
||||
deptid = item.deptid,
|
||||
eventid = item.eventid,
|
||||
eventmemo = item.eventmemo,
|
||||
eventname = item.eventname,
|
||||
ip = item.ip,
|
||||
others = item.others,
|
||||
productplat = item.productplat,
|
||||
productplatname = item.productplatname,
|
||||
sceneext = item.sceneext,
|
||||
sceneid = item.sceneid,
|
||||
sceneidname = item.sceneidname,
|
||||
scenetype = item.scenetype,
|
||||
scenetypename = item.scenetypename,
|
||||
sinkClickhouseTable = "手工推送",
|
||||
uid = item.uid,
|
||||
user_type = item.user_type,
|
||||
with_eid = item.with_eid,
|
||||
with_groupid = item.with_groupid,
|
||||
with_orgid = item.with_orgid
|
||||
};
|
||||
if (item.act_time.HasValue)
|
||||
{
|
||||
eventDto.act_time = ConvertDataTimeLong(item.act_time.Value);
|
||||
}
|
||||
if (item.leavetime.HasValue)
|
||||
{
|
||||
eventDto.leavetime = ConvertDataTimeLong(item.leavetime.Value);
|
||||
}
|
||||
await RunEvent(eventDto);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将DateTime类型转换为long类型
|
||||
/// </summary>
|
||||
/// <param name="dt">时间</param>
|
||||
/// <returns></returns>
|
||||
public static long ConvertDataTimeLong(DateTime dt)
|
||||
{
|
||||
//dateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000
|
||||
DateTime dtBase = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
TimeSpan toNow = dt.ToUniversalTime().Subtract(dtBase);
|
||||
long timeStamp = toNow.Ticks / 10000;
|
||||
return timeStamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Domain
|
||||
{
|
||||
public interface IEventDomain : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取活动名称
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> RunEvent(EventDto request);
|
||||
|
||||
/// <summary>
|
||||
/// 修复数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> Repairdata();
|
||||
|
||||
Task<ToDoItemDeptMap> GetSetting(EventDto eventDto);
|
||||
|
||||
Task<ToDoItemSetting> GetDelaySec();
|
||||
|
||||
/// <summary>
|
||||
/// 过滤登录事件
|
||||
/// </summary>
|
||||
/// <param name="eventDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> FilterLogEvent(EventDto eventDto, ToDoItemDeptMap setting);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Dto
|
||||
{
|
||||
public class CustomerEmployeeMap
|
||||
{
|
||||
public int? customerid { get; set; }
|
||||
public int? eid { get; set; }
|
||||
public int? deptid { get; set; }
|
||||
public int? groupid { get; set; }
|
||||
public string? resid { get; set; }
|
||||
public string? umid { get; set; }
|
||||
public string? employee_name { get; set; }
|
||||
public string? create_time { get; set; }
|
||||
public int? is_wework { get; set; }
|
||||
public int? is_mobile { get; set; }
|
||||
public int? is_belong { get; set; }
|
||||
|
||||
public string? Nickname { get; set; }
|
||||
public string? Username { get; set; }
|
||||
|
||||
public string? Headimgurl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Dto
|
||||
{
|
||||
public class KafkaEvent
|
||||
{
|
||||
public string? data { get; set; }
|
||||
public string? tableName { get; set; }
|
||||
}
|
||||
|
||||
public class TestDto
|
||||
{
|
||||
public string? act_date { get; set; }
|
||||
}
|
||||
|
||||
public class EventDto
|
||||
{
|
||||
public string? act_date { get; set; }
|
||||
public long? act_time { get; set; }
|
||||
public string? appid { get; set; }
|
||||
public string? appuserid { get; set; }
|
||||
public int? channel { get; set; }
|
||||
public int? customerid { get; set; }
|
||||
public int? deptid { get; set; }
|
||||
public string? env { get; set; }
|
||||
public int eventid { get; set; }
|
||||
public string? eventmemo { get; set; }
|
||||
public string? eventname { get; set; }
|
||||
public string? ip { get; set; }
|
||||
public string? others { get; set; }
|
||||
public string? productplat { get; set; }
|
||||
public string? productplatname { get; set; }
|
||||
public string? resid { get; set; }
|
||||
public string? umid { get; set; }
|
||||
public string? sceneext { get; set; }
|
||||
public string? sceneid { get; set; }
|
||||
public string? sceneidname { get; set; }
|
||||
public string? scenename { get; set; }
|
||||
public int? scenetype { get; set; }
|
||||
public string? scenetypename { get; set; }
|
||||
public string? sinkClickhouseTable { get; set; }
|
||||
|
||||
public int? uid { get; set; }
|
||||
public string? unionid { get; set; }
|
||||
public int? user_type { get; set; }
|
||||
public int? with_eid { get; set; }
|
||||
public int? with_groupid { get; set; }
|
||||
public int? with_orgid { get; set; }
|
||||
public long? leavetime { get; set; }
|
||||
public DateTime? update_time { get; set; }
|
||||
public DateTime TaskTime { get; set; }
|
||||
public int RetryCount { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Dto
|
||||
{
|
||||
public class ToDoItemSetting
|
||||
{
|
||||
/// <summary>
|
||||
/// 延迟时间 默认120秒
|
||||
/// </summary>
|
||||
public int? delaytime { get; set; }
|
||||
|
||||
public int? batchSize { get; set; } = 100;
|
||||
public List<ToDoItemDeptMap> setting { get; set; }
|
||||
}
|
||||
|
||||
public class ToDoItemDeptMap
|
||||
{
|
||||
public int? neweventid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件id
|
||||
/// </summary>
|
||||
public int? eventid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 大类
|
||||
/// </summary>
|
||||
|
||||
public string? remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 小类
|
||||
/// </summary>
|
||||
public string? memo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板
|
||||
/// </summary>
|
||||
public string? template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 场景
|
||||
/// </summary>
|
||||
public List<int?> scenetype { get; set; } = new List<int?>();
|
||||
|
||||
/// <summary>
|
||||
/// 具体场景
|
||||
/// </summary>
|
||||
public List<string?> sceneid { get; set; } = new List<string?>();
|
||||
|
||||
/// <summary>
|
||||
/// 是否通知所有好友
|
||||
/// </summary>
|
||||
public bool allNotice { set; get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 用户类型
|
||||
/// </summary>
|
||||
public List<SByte> userType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 只通知最早的那个客服
|
||||
/// </summary>
|
||||
public bool? firstCtime { get; set; } = true;
|
||||
|
||||
public List<int> deptids { get; set; } = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 通知好友关系
|
||||
/// </summary>
|
||||
public bool is_wework { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 通知归属关系
|
||||
/// </summary>
|
||||
public bool is_mobile { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 通知成交关系
|
||||
/// </summary>
|
||||
public bool is_belong { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Appid
|
||||
/// </summary>
|
||||
public List<string> appids { get; set; } = new List<string>();
|
||||
|
||||
public string? source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当日唯一健值
|
||||
/// </summary>
|
||||
public string? key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当日唯一健值 (resid)
|
||||
/// </summary>
|
||||
public string? residkey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 没有归属强制插入
|
||||
/// </summary>
|
||||
public bool? isforce { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ToDoWorker.Helper
|
||||
{
|
||||
public enum EventEnum : int
|
||||
{
|
||||
[Description("点击")]
|
||||
点击 = 1,
|
||||
|
||||
[Description("报名")]
|
||||
报名 = 2,
|
||||
|
||||
[Description("登录")]
|
||||
登录 = 6,
|
||||
|
||||
[Description("关注")]
|
||||
关注 = 7,
|
||||
|
||||
[Description("取关")]
|
||||
取关 = 8,
|
||||
|
||||
[Description("听课")]
|
||||
听课 = 17,
|
||||
|
||||
[Description("聊天")]
|
||||
聊天 = 20,
|
||||
|
||||
[Description("互动精选")]
|
||||
互动精选 = 45,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.SqlSugar;
|
||||
|
||||
namespace ToDoWorker.Helper
|
||||
{
|
||||
public class SeqIdGen
|
||||
{
|
||||
//起始的时间戳 2020-01-01 00 00 00 开始
|
||||
private static long START_STMP = 1577808000000L;
|
||||
|
||||
//每一部分占用的位数
|
||||
private static int SEQUENCE_BIT = 12; //序列号占用的位数
|
||||
|
||||
private static int MACHINE_BIT = 6; //机器标识占用的位数
|
||||
private static int DATACENTER_BIT = 3;//数据中心占用的位数
|
||||
|
||||
//每一部分的最大值
|
||||
private static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
|
||||
|
||||
private static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
|
||||
private static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
|
||||
|
||||
//每一部分向左的位移
|
||||
private static int MACHINE_LEFT = SEQUENCE_BIT;
|
||||
|
||||
private static int DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
|
||||
private static int TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
|
||||
|
||||
private long datacenterId = 1; //数据中心
|
||||
private long machineId = 1; //机器标识
|
||||
private long sequence = 0L; //序列号
|
||||
private long lastStmp = -1L;//上一次时间戳
|
||||
|
||||
private static Random r = new Random();
|
||||
|
||||
private static readonly object _locker = new object();
|
||||
private static readonly object _Idlocker = new object();
|
||||
private static SeqIdGen _instance = (SeqIdGen)null;
|
||||
|
||||
public static SeqIdGen Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new SeqIdGen();
|
||||
}
|
||||
}
|
||||
return SeqIdGen._instance;
|
||||
}
|
||||
}
|
||||
|
||||
private SeqIdGen()
|
||||
{
|
||||
// SeqIdGenInitRedis();
|
||||
SeqIdGenInitConfig(); //从appsetting取
|
||||
}
|
||||
|
||||
public void SeqIdGenInitConfig()
|
||||
{
|
||||
var _machineId = long.Parse(InitConfiguration.GetSection("machineId").Value.ToString());
|
||||
var _datacenterId = long.Parse(InitConfiguration.GetSection("datacenterId").Value.ToString());
|
||||
SeqIdGenInit(_machineId, _datacenterId);
|
||||
}
|
||||
|
||||
/* public void SeqIdGenInitRedis()
|
||||
{
|
||||
var cpukey = getCpu();
|
||||
var rdc = RedisManager.GetRedisClient2();
|
||||
var mechineSeq = rdc.GetValueFromHash("Num:MechineSeq", cpukey);
|
||||
if (string.IsNullOrEmpty(mechineSeq))
|
||||
{
|
||||
mechineSeq = rdc.IncrementValue("Num:MSeq").ToString();
|
||||
rdc.SetEntryInHash("Num:MechineSeq", cpukey, mechineSeq);
|
||||
}
|
||||
SeqIdGenInit(long.Parse(mechineSeq), datacenterId);
|
||||
}*/
|
||||
|
||||
public string GetDiskVolumeSerialNumber()
|
||||
{
|
||||
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
|
||||
ManagementObject disk = new ManagementObject("win32_LogHelpericaldisk.deviceid=\"c:\"");
|
||||
disk.Get();
|
||||
return disk.GetPropertyValue("VolumeSerialNumber").ToString();
|
||||
}
|
||||
|
||||
//获得CPU的序列号
|
||||
public string getCpu()
|
||||
{
|
||||
string strCpu = null;
|
||||
ManagementClass myCpu = new ManagementClass("win32_Processor");
|
||||
ManagementObjectCollection myCpuConnection = myCpu.GetInstances();
|
||||
foreach (ManagementObject myObject in myCpuConnection)
|
||||
{
|
||||
strCpu = myObject.Properties["Processorid"].Value.ToString();
|
||||
break;
|
||||
}
|
||||
return strCpu;
|
||||
}
|
||||
|
||||
public void SeqIdGenInit(long cid, long mid)
|
||||
{
|
||||
if (cid > MAX_DATACENTER_NUM || cid < 0) throw new Exception($"中心Id应在(0,{MAX_DATACENTER_NUM})之间");
|
||||
if (mid > MAX_MACHINE_NUM || mid < 0) throw new Exception($"机器Id应在(0,{MAX_MACHINE_NUM})之间");
|
||||
datacenterId = cid;
|
||||
machineId = mid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 产生下一个ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long nextId()
|
||||
{
|
||||
lock (_Idlocker)
|
||||
{
|
||||
long currStmp = getNewstmp();
|
||||
if (currStmp < lastStmp) throw new Exception("时钟倒退,Id生成失败!");
|
||||
|
||||
if (currStmp == lastStmp)
|
||||
{
|
||||
//相同毫秒内,序列号自增
|
||||
sequence = (sequence + 1) & MAX_SEQUENCE;
|
||||
//同一毫秒的序列数已经达到最大
|
||||
if (sequence == 0L) currStmp = getNextMill();
|
||||
}
|
||||
else
|
||||
{
|
||||
//不同毫秒内,序列号置为0
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
lastStmp = currStmp;
|
||||
|
||||
return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
|
||||
| datacenterId << DATACENTER_LEFT //数据中心部分
|
||||
| machineId << MACHINE_LEFT //机器标识部分
|
||||
| sequence; //序列号部分
|
||||
}
|
||||
}
|
||||
|
||||
private long getNextMill()
|
||||
{
|
||||
long mill = getNewstmp();
|
||||
while (mill <= lastStmp)
|
||||
{
|
||||
mill = getNewstmp();
|
||||
}
|
||||
return mill;
|
||||
}
|
||||
|
||||
private long getNewstmp()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
using ClickHouse.EntityFrameworkCore.Extensions;
|
||||
using DG.EntityFramework;
|
||||
using DG.Kafka;
|
||||
using Exceptionless;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using ToDoWorker;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
try
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Console.WriteLine($"Env: {env}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env ?? "Production"}.json", true)
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{env ?? "Production"}.json", true)
|
||||
.Build();
|
||||
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(config)
|
||||
.WriteTo.Exceptionless(config.GetValue<string>("Exceptionless:ApiKey"), config.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "WeworkUserWorker" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
Log.Information("Starting ToDoWorker");
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog();
|
||||
});
|
||||
services.AddSingleton<IConfiguration>(config);
|
||||
services.AddOptions()
|
||||
.Configure<SystemConfig>(e => config.GetSection("SystemConfig").Bind(e));
|
||||
ExceptionlessClient.Default.Startup(config.GetValue<string>("Exceptionless:ApiKey"));
|
||||
ExceptionlessClient.Default.Configuration.ServerUrl = config.GetValue<string>("Exceptionless:ServerUrl");
|
||||
ExceptionlessClient.Default.Configuration.DefaultTags.Add("Zxd-ToDoWorker");
|
||||
services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(config.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
services.AddDGEntityFramework<CrmCloudDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("crmcloud"), ServerVersion.AutoDetect(config.GetConnectionString("hgaction")));
|
||||
});
|
||||
/* services.AddDGEntityFramework<DimDbContext>(options =>
|
||||
{
|
||||
options.UseClickHouse(config.GetConnectionString("dim"));
|
||||
});*/
|
||||
services.AddAutoIoc(typeof(IScopedDependency), LifeCycle.Scoped)
|
||||
.AddAutoIoc(typeof(ISingletonDependency), LifeCycle.Singleton)
|
||||
.AddAutoIoc(typeof(ITransientDependency), LifeCycle.Transient)
|
||||
.AddMapper();
|
||||
services.AddKafkaWorker(config);
|
||||
services.AddWorker(config);
|
||||
services.AddRedis(config);
|
||||
services.AddDGHttpClient();
|
||||
services.AddRegisterWorker<ActionConsumeWorker>();
|
||||
//services.AddRegisterWorker<RepairDataWorker>();
|
||||
services.AddRegisterBatchWorker<ToDoWorker.Workers.ToDoWorker, KafkaEvent>();
|
||||
|
||||
//构建容器
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var workerManager = serviceProvider.GetRequiredService<IKafkaWorkerManager>();
|
||||
var consumers = config.GetSection("Consumers").Get<List<Consumer>>(); ;
|
||||
await workerManager.RegisterBatchWorker<ToDoWorker.Workers.ToDoWorker, KafkaEvent>(consumers?.FirstOrDefault()?.Topic, 1);
|
||||
var builder = new HostBuilder();
|
||||
await builder.RunConsoleAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"ToDoWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Warning",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.dockerignore" Link=".dockerignore">
|
||||
<DependentUpon>$(DockerDefaultDockerfile)</DependentUpon>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DG.Core" Version="1.1.3" />
|
||||
<PackageReference Include="DG.Redis" Version="1.0.17" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.11" />
|
||||
<PackageReference Include="DG.Kafka.Worker" Version="1.0.12" />
|
||||
<PackageReference Include="DG.Worker" Version="1.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Exceptionless" Version="6.0.1" />
|
||||
<PackageReference Include="System.Management" Version="7.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
|
||||
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\Zxd.SqlSugar\Zxd.SqlSugar.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="DG.Tool" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="ToDoWorker.Workers" />
|
||||
<Using Include="ToDoWorker.Dto" />
|
||||
<Using Include="ToDoWorker.Config" />
|
||||
<Using Include="DG.Kafka.Worker" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="Serilog" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Event\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
using DG.EntityFramework;
|
||||
using DG.Redis;
|
||||
using DG.Worker;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ToDoWorker.Domain;
|
||||
using ToDoWorker.Dto;
|
||||
using ToDoWorker.Helper;
|
||||
using Zxd.Core.Shared.Helpers;
|
||||
using Zxd.Entity.Action;
|
||||
using Zxd.Entity.dim;
|
||||
using Zxd.Entity.Zxd;
|
||||
using Zxd.EntityFramework;
|
||||
using Zxd.SqlSugar;
|
||||
|
||||
namespace ToDoWorker.Workers
|
||||
{
|
||||
/// <summary>
|
||||
/// 消费队列
|
||||
/// </summary>
|
||||
internal class ActionConsumeWorker : WorkerBase
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ActionConsumeWorker> _logger;
|
||||
private readonly IRedisManager _redisManager;
|
||||
private static string _oldQueueskey = "queue:todoqueues";
|
||||
private static string _queueskey = "queue:todoItemQueues";
|
||||
private static string _cachekey = "queue:cacheItem";
|
||||
|
||||
public ActionConsumeWorker(ILogger<ActionConsumeWorker> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
IHttpClient httpClient,
|
||||
IRedisManager redisManager
|
||||
) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync()
|
||||
{
|
||||
//
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var setting = await scope.ServiceProvider.GetRequiredService<IEventDomain>().GetDelaySec();
|
||||
var batchSize = setting == null ? 100 : setting.batchSize.Value;
|
||||
for (var i = 0; i < batchSize; i++)
|
||||
{
|
||||
//ToDoEventSingleton.Instance.TryDequeue(delaySec, out EventDto? kafkaEvent);
|
||||
var kafkaEvent = await Dequeue();
|
||||
if (kafkaEvent != null)
|
||||
{
|
||||
//需要新注册实体
|
||||
await scope.ServiceProvider.GetRequiredService<IEventDomain>().RunEvent(kafkaEvent);
|
||||
// 任务处理完,移除缓存数据
|
||||
await RemoveCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
//如果拿出为null 则跳出
|
||||
break;
|
||||
}
|
||||
}
|
||||
stopwatch.Stop();
|
||||
}
|
||||
|
||||
private async Task test()
|
||||
{
|
||||
var ss = "{\"act_date\":\"2023-08-18\",\"act_time\":1692351466000,\"appid\":\"wx1d0e531a680d947b\",\"appuserid\":\"olxOo6KlSg_QP5PL42skLpozzelI\",\"channel\":0,\"customerid\":7729244,\"deptid\":40,\"env\":\"prod\",\"eventid\":17,\"eventmemo\":\"六维共振\",\"eventname\":\"听课\",\"ip\":\"223.106.130.63\",\"others\":\"86\",\"productplat\":\"\",\"productplatname\":null,\"resid\":\"436799775507061617\",\"sceneext\":\"\",\"sceneid\":\"156\",\"sceneidname\":null,\"scenename\":null,\"scenetype\":6,\"scenetypename\":\"直播间\",\"sinkClickhouseTable\":\"act_action_event\",\"uid\":7750620,\"unionid\":\"o5bj2wWFzxBwWj4eIepDE8OISFs0\",\"user_type\":1,\"with_eid\":0,\"with_groupid\":0,\"with_orgid\":0,\"leavetime\":null,\"update_time\":null,\"TaskTime\":\"2023-08-18T17:39:50.3985639+08:00\",\"RetryCount\":0}";
|
||||
var kafkaEvent = JsonHelper.FromJson<EventDto>(ss);
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
await scope.ServiceProvider.GetRequiredService<IEventDomain>().RunEvent(kafkaEvent);
|
||||
//await _redisManager.EnqueueAsync(_queueskey, kafkaEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务出队
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<EventDto?> Dequeue()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var kafkaEvent = default(EventDto?);
|
||||
|
||||
// 是否存旧队列数据(兼容旧版)
|
||||
if (await _redisManager.ExistsAsync(_oldQueueskey))
|
||||
{
|
||||
var data = await _redisManager.GetListAsync<EventDto>(_oldQueueskey);
|
||||
data = data.OrderByDescending(x => x.TaskTime).ToList();
|
||||
|
||||
foreach (var item in data)
|
||||
{
|
||||
// 任务入队
|
||||
item.TaskTime = DateTime.Now.AddSeconds(120);
|
||||
item.RetryCount = 0;
|
||||
await _redisManager.EnqueueAsync(_queueskey, item);
|
||||
}
|
||||
await _redisManager.RemoveAsync(_oldQueueskey);
|
||||
}
|
||||
// 判断是否存在缓存处理数据
|
||||
if (await _redisManager.ExistsAsync(_cachekey))
|
||||
{
|
||||
kafkaEvent = await _redisManager.GetAsync<EventDto>(_cachekey);
|
||||
if (kafkaEvent.TaskTime >= now)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//Log.Information($"任务出队处理, uid: [{kafkaEvent.uid}], resid: [{kafkaEvent.resid}]");
|
||||
return kafkaEvent;
|
||||
}
|
||||
|
||||
// 判断是否存在队列数据
|
||||
if (await _redisManager.ExistsAsync(_queueskey))
|
||||
{
|
||||
kafkaEvent = await _redisManager.BlockingDequeueAsync<EventDto>(_queueskey);
|
||||
if (kafkaEvent != null)
|
||||
{
|
||||
// 写入处理缓存
|
||||
await _redisManager.SetAsync(_cachekey, kafkaEvent);
|
||||
if (kafkaEvent.TaskTime >= now)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return kafkaEvent;
|
||||
}
|
||||
}
|
||||
|
||||
return kafkaEvent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除缓存处理数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveCache()
|
||||
{
|
||||
if (await _redisManager.ExistsAsync(_cachekey))
|
||||
{
|
||||
var kafkaEvent = await _redisManager.GetAsync<EventDto>(_cachekey);
|
||||
await _redisManager.RemoveAsync(_cachekey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using DG.EntityFramework;
|
||||
using DG.Redis;
|
||||
using DG.Worker;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ToDoWorker.Domain;
|
||||
using ToDoWorker.Dto;
|
||||
using ToDoWorker.Helper;
|
||||
using Zxd.Core.Shared.Helpers;
|
||||
using Zxd.Entity.Action;
|
||||
using Zxd.Entity.dim;
|
||||
using Zxd.Entity.Zxd;
|
||||
using Zxd.EntityFramework;
|
||||
using Zxd.SqlSugar;
|
||||
|
||||
namespace ToDoWorker.Workers
|
||||
{
|
||||
/// <summary>
|
||||
/// 消费队列
|
||||
/// </summary>
|
||||
internal class RepairDataWorker : WorkerBase
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ActionConsumeWorker> _logger;
|
||||
private readonly IRedisManager _redisManager;
|
||||
private static string _oldQueueskey = "queue:todoqueues";
|
||||
private static string _queueskey = "queue:todoItemQueues";
|
||||
private static string _cachekey = "queue:cacheItem";
|
||||
|
||||
public RepairDataWorker(ILogger<ActionConsumeWorker> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
IHttpClient httpClient,
|
||||
IRedisManager redisManager
|
||||
) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync()
|
||||
{
|
||||
//
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var isRepairData = await _redisManager.GetAsync<int>("RepairData");
|
||||
if (isRepairData != 1)
|
||||
{
|
||||
await _redisManager.SetAsync("RepairData", 1);
|
||||
try
|
||||
{
|
||||
await scope.ServiceProvider.GetRequiredService<IEventDomain>().Repairdata();
|
||||
stopwatch.Stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"初始化数据出错{ex.Message}");
|
||||
}
|
||||
}
|
||||
await Task.Delay(100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
using DG.Redis;
|
||||
using DG.Worker;
|
||||
using Exceptionless.Utility;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ToDoWorker.Domain;
|
||||
using ToDoWorker.Helper;
|
||||
using Zxd.Entity.Dncms;
|
||||
|
||||
namespace ToDoWorker.Workers
|
||||
{
|
||||
internal class ToDoWorker : BatchKafkaWorkerBase<KafkaEvent>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ToDoWorker> _logger;
|
||||
private readonly IRedisManager _redisManager;
|
||||
private static string _queueskey = "queue:todoItemQueues";
|
||||
private static string _cachekey = "queue:cacheItem";
|
||||
|
||||
public ToDoWorker(ILogger<ToDoWorker> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IRedisManager redisManager
|
||||
) : base(logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync(List<KafkaEvent> eventDtos)
|
||||
{
|
||||
foreach (var eventDto in eventDtos)
|
||||
{
|
||||
//Log.Information($"eventDtos:{eventDto.ToJson()}");
|
||||
if (eventDto.tableName == "act_action_event" && !string.IsNullOrEmpty(eventDto.data))
|
||||
{
|
||||
try
|
||||
{
|
||||
EventDto model = JsonHelper.FromJson<EventDto>(eventDto.data);
|
||||
//需要新注册实体
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var eventService = scope.ServiceProvider.GetRequiredService<IEventDomain>();
|
||||
var setting = await scope.ServiceProvider.GetRequiredService<IEventDomain>().GetDelaySec();
|
||||
var delaySec = setting == null ? 120 : setting.delaytime.Value;
|
||||
var deptSet = await eventService.GetSetting(model);
|
||||
|
||||
if (deptSet != null && model.uid > 0)
|
||||
{
|
||||
//登录特殊处理 一天同一个人只出现一次
|
||||
if (!await eventService.FilterLogEvent(model, deptSet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (model != null)
|
||||
{
|
||||
// 任务入队
|
||||
model.TaskTime = DateTime.Now.AddSeconds(delaySec);
|
||||
await _redisManager.EnqueueAsync(_queueskey, model);
|
||||
}
|
||||
}
|
||||
/* else
|
||||
{
|
||||
Log.Information($"Event跳过{model.eventname}【{model.sceneid}】{model.uid}");
|
||||
}*/
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"DoWorkAsync处理失败{eventDto.ToJson()},{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"hgaction": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=hgaction;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"crmcloud": "Server=dgbigdata.mysql.rds.aliyuncs.com;Database=crm_cloud;UserId=crm_rd;Password=K#RQ1TYx9my;port=3306;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "ToDoWorker",
|
||||
"TaskRemarks": "ToDoWorker",
|
||||
"Enable": true,
|
||||
"MilliSecondsDelay": 200
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "h6SHsDDLmWnC9E9WeEnRU7Sm3Em5RUuSKFVbSUWT"
|
||||
},
|
||||
"machineId": 1,
|
||||
"datacenterId": 1,
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092,172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd_act_user_event_alert"
|
||||
}
|
||||
],
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"BdMarkting": "http://172.18.11.55:28065"
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "Hg",
|
||||
"HostName": "172.18.11.63",
|
||||
"Port": "6379",
|
||||
"Password": "sa123456.",
|
||||
"Defaultdatabase": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"hgaction": "Server=192.168.11.141;Database=hgaction;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crmcloud": "Server=192.168.11.141;Database=crm_cloud;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"TaskConfig": {
|
||||
"TaskName": "ToDoWorker",
|
||||
"TaskRemarks": "ToDoWorker",
|
||||
"Enable": true,
|
||||
"MilliSecondsDelay": 500
|
||||
},
|
||||
"machineId": 1,
|
||||
"datacenterId": 1,
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "192.168.11.104:9092,192.168.11.104:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd_act_user_alert_test1"
|
||||
}
|
||||
],
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "AukFjLDBeABakHa1jS67DXoRFPh5J6TdVjDqFMwx"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089",
|
||||
"BdMarkting": "http://bd-markting.soft.dn8188.com"
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "ZXD",
|
||||
"HostName": "192.168.11.81",
|
||||
"Port": "6379",
|
||||
"Password": "Abc@123456",
|
||||
"Defaultdatabase": "1"
|
||||
},
|
||||
{
|
||||
"Name": "UserCenter",
|
||||
"HostName": "192.168.11.103",
|
||||
"Port": "6379",
|
||||
"Password": "123",
|
||||
"Defaultdatabase": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WeworkUserWorker.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public string zxdCoreApi { get; set; }
|
||||
public string nodeWebApi { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["WeworkUserWorker/WeworkUserWorker.csproj", "WeworkUserWorker/"]
|
||||
COPY ["Zxd.Core.Shared/Zxd.Core.Shared.csproj", "Zxd.Core.Shared/"]
|
||||
COPY ["Zxd.EntityFramework/Zxd.EntityFramework.csproj", "Zxd.EntityFramework/"]
|
||||
COPY ["Zxd.Entity/Zxd.Entity.csproj", "Zxd.Entity/"]
|
||||
RUN dotnet restore "WeworkUserWorker/WeworkUserWorker.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/WeworkUserWorker"
|
||||
RUN dotnet build "WeworkUserWorker.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "WeworkUserWorker.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "WeworkUserWorker.dll"]
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WeworkUserWorker.Dto
|
||||
{
|
||||
public class ZXDApiResult<T> where T : class
|
||||
{
|
||||
public int code { get; set; }
|
||||
public string? message { get; set; }
|
||||
public T data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
using DG.EntityFramework;
|
||||
using DG.Kafka.Worker;
|
||||
using Exceptionless;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using WeworkUserWorker.Config;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
using Zxd.EntityFramework;
|
||||
|
||||
try
|
||||
{
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Console.WriteLine($"Env: {env}");
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env ?? "Production"}.json", true)
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{env ?? "Production"}.json", true)
|
||||
.Build();
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(config)
|
||||
.WriteTo.Exceptionless(config.GetValue<string>("Exceptionless:ApiKey"), config.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "WeworkUserWorker" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
Log.Information("Starting WeworkUserWorker");
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog();
|
||||
});
|
||||
services.AddSingleton(config);
|
||||
services.AddOptions()
|
||||
.Configure<SystemConfig>(e => config.GetSection("SystemConfig").Bind(e));
|
||||
ExceptionlessClient.Default.Startup(config.GetValue<string>("Exceptionless:ApiKey"));
|
||||
ExceptionlessClient.Default.Configuration.ServerUrl = config.GetValue<string>("Exceptionless:ServerUrl");
|
||||
//services.AddRedis(config);
|
||||
services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(config.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsbaseDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncmsbase"), ServerVersion.AutoDetect(config.GetConnectionString("dncmsbase")));
|
||||
});
|
||||
services.AddDGEntityFramework<UserCenterDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("usercenter"), ServerVersion.AutoDetect(config.GetConnectionString("usercenter")));
|
||||
});
|
||||
services.AddDGEntityFramework<DncmsDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("dncms"), ServerVersion.AutoDetect(config.GetConnectionString("dncms")));
|
||||
});
|
||||
services.AddDGEntityFramework<CrmDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("crm"), ServerVersion.AutoDetect(config.GetConnectionString("crm")));
|
||||
});
|
||||
services.AddDGEntityFramework<CompanyBaseConfDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(config.GetConnectionString("companyBaseConf"), ServerVersion.AutoDetect(config.GetConnectionString("companyBaseConf")));
|
||||
});
|
||||
services.AddKafkaWorker(config);
|
||||
services.AddRedis(config);
|
||||
services.AddDGHttpClient();
|
||||
services.AddRegisterWorker<WeworkWorker, WeworkWorkerDto>();
|
||||
//构建容器
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
var workerManager = serviceProvider.GetRequiredService<IKafkaWorkerManager>();
|
||||
await workerManager.RegisterWorker<WeworkWorker, WeworkWorkerDto>("crm-topic");
|
||||
await workerManager.RegisterWorker<WeworkWorker, WeworkWorkerDto>("crm-topic");
|
||||
await workerManager.RegisterWorker<WeworkWorker, WeworkWorkerDto>("crm-topic");
|
||||
await workerManager.RegisterWorker<WeworkWorker, WeworkWorkerDto>("crm-topic");
|
||||
await workerManager.RegisterWorker<WeworkWorker, WeworkWorkerDto>("crm-topic");
|
||||
var builder = new HostBuilder();
|
||||
await builder.RunConsoleAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"profiles": {
|
||||
"WeworkUserWorker": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Warning",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"System": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"System.Net.Http.HttpClient": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"encoding": "System.Text.Encoding::UTF8",
|
||||
"path": "logs/log.log",
|
||||
"rollingInterval": "3",
|
||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DG.Core" Version="1.0.25" />
|
||||
<PackageReference Include="DG.Redis" Version="1.0.17" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.9" />
|
||||
<PackageReference Include="DG.Kafka" Version="1.0.3" />
|
||||
<PackageReference Include="DG.Kafka.Worker" Version="1.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Exceptionless" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
|
||||
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="DG.Tool" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="WeworkUserWorker.Workers" />
|
||||
<Using Include="WeworkUserWorker.Dto" />
|
||||
<Using Include="DG.Kafka.Worker" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="DG.EntityFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.Disaster.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="appsettings.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Serilog.Production.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,723 @@
|
|||
using DG.EntityFramework;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WeworkUserWorker.Config;
|
||||
using Zxd.Entity.Dncms;
|
||||
using Zxd.Entity.UserCenter;
|
||||
using Zxd.EntityFramework;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DG.Kafka;
|
||||
using MySqlConnector;
|
||||
using System.Diagnostics;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
using DG.Redis;
|
||||
using Zxd.Entity.Zxd;
|
||||
|
||||
namespace WeworkUserWorker.Workers
|
||||
{
|
||||
internal class WeworkTagWorker : KafkaWorkerBase<WeWorkTagDto>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<WeworkTagWorker> _logger;
|
||||
private readonly IOptionsSnapshot<SystemConfig> _systemConfig;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IRedisManager _redisManager;
|
||||
|
||||
public WeworkTagWorker(
|
||||
IServiceProvider serviceProvider,
|
||||
IOptionsSnapshot<SystemConfig> systemConfig,
|
||||
ILogger<WeworkTagWorker> logger,
|
||||
IHttpClient httpClient, IRedisManager redisManager
|
||||
) : base(logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_httpClient = httpClient;
|
||||
_systemConfig = systemConfig;
|
||||
_logger = logger;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理好友最终关系
|
||||
/// 数据逻辑
|
||||
/// 1、通过appid和appuserid去usercenter.userinfo中找出customerid,并通过customerid查出userinfo中所有用户数据,
|
||||
/// 2、假如数据中没有resid、忽略不处理。
|
||||
/// 3、假如有resid去dncms.weworkexternaluser中查找数据,subscribe = 1筛选数据,用subscribetime去 res_resid_weworkuser
|
||||
/// 表中appid、appuserid数据取firsttime和最早的subscribetime 对比,有变动就修正,假如res_resid_weworkuser 中的在刚刚查找出来没有关注数据了,
|
||||
/// 将status改成0 。假如res_resid_weworkuser 没有数据,插入一条数据。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync(WeWorkTagDto t)
|
||||
{
|
||||
IList<ResResidWeworkUser> resResids = new List<ResResidWeworkUser>();
|
||||
IList<UserInfoReq> users = new List<UserInfoReq>();
|
||||
List<ResResidWeworkUser> rrWeworkUser = new List<ResResidWeworkUser>();
|
||||
List<WeworkExternalUser> mainExternalUsers = new List<WeworkExternalUser>();
|
||||
List<WeworkExternalUser> secExternalUsers = new List<WeworkExternalUser>();
|
||||
try
|
||||
{
|
||||
await EventLog(t);
|
||||
switch (t.type?.ToLower())
|
||||
{
|
||||
case "subscribe"://关注
|
||||
case "unsubscribe"://取关
|
||||
_logger.LogWarning("开始处理取关!");
|
||||
users = await GetUser(t.appid, t.appuserid); //请求此用户的所有用户信息
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//查询当前客户好友关系
|
||||
foreach (var item in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
_logger.LogWarning("结束处理取关!");
|
||||
break;
|
||||
|
||||
case "merge"://合并
|
||||
_logger.LogWarning("开始处理合并!");
|
||||
if (int.TryParse(t.cid, out int incid))
|
||||
{
|
||||
users = await GetUser(incid);//请求此用户的所有用户信息
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//查询当前客户好友关系
|
||||
foreach (var item in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
}
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
_logger.LogWarning("结束处理合并!");
|
||||
break;
|
||||
|
||||
case "unmerge"://解绑
|
||||
_logger.LogWarning("开始处理解绑!");
|
||||
var cidarry = t.cid?.Trim().Split(',');
|
||||
if (cidarry != null && cidarry.Count() == 2)
|
||||
{
|
||||
var scid = cidarry[0];
|
||||
var ecid = cidarry[1];
|
||||
var susers = await GetUser(int.Parse(scid));//分别查询出两个cid对应的客户信息
|
||||
var eusers = await GetUser(int.Parse(ecid));//
|
||||
var swu = await BindWeworkUser(susers, mainExternalUsers);//查询当前客户好友关系
|
||||
//await SetSourcePassInfo(mainExternalUsers, susers, t);
|
||||
var ewu = await BindWeworkUser(eusers, secExternalUsers);//查询当前客户好友关系
|
||||
//await SetSourcePassInfo(secExternalUsers, eusers, t);
|
||||
foreach (var item in swu)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
foreach (var item in ewu)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
var unlist = await UnBindWeworkUser(susers, eusers);//拼接两个cid的 重叠部分
|
||||
foreach (var item in unlist)
|
||||
{
|
||||
//事业部不发生变化
|
||||
await ChangeWeworkUser(item, false);//解绑匹配的新数据不入库,旧数据标记删除
|
||||
}
|
||||
}
|
||||
_logger.LogWarning("结束处理解绑!");
|
||||
break;
|
||||
|
||||
case "eidbind"://跨部门换绑工号 300秒超时
|
||||
if (t.olddeptid.HasValue && t.deptid.HasValue && t.olddeptid != t.deptid)
|
||||
{
|
||||
var kfuser = await GetKFUser(t.appid, t.userid); //请求此用户的所有用户信息
|
||||
if (kfuser.Count() > 300)
|
||||
{//给队列逐条处理
|
||||
IList<string> appidStr = new List<string>();
|
||||
IList<string> euseridStr = new List<string>();
|
||||
foreach (var item in kfuser)
|
||||
{
|
||||
appidStr.Add(item.Appid_ext);
|
||||
euseridStr.Add(item.Externaluserid);
|
||||
if (appidStr.Count() > 9)
|
||||
{
|
||||
WeworkWorkerDto dto = new WeworkWorkerDto();
|
||||
dto.type = "inner_eidbind_item";
|
||||
dto.appuserid = String.Join(",", euseridStr);
|
||||
dto.appid = String.Join(",", appidStr);
|
||||
dto.deptid = t.deptid;
|
||||
dto.olddeptid = t.olddeptid;
|
||||
PushKafKa(dto);
|
||||
appidStr = new List<string>();
|
||||
euseridStr = new List<string>();
|
||||
}
|
||||
}
|
||||
//循环结束验证是否有未完成
|
||||
if (euseridStr.Any())
|
||||
{
|
||||
WeworkWorkerDto lastdto = new WeworkWorkerDto();
|
||||
lastdto.type = "inner_eidbind_item";
|
||||
lastdto.appuserid = String.Join(",", euseridStr);
|
||||
lastdto.appid = String.Join(",", appidStr);
|
||||
lastdto.deptid = t.deptid;
|
||||
lastdto.olddeptid = t.olddeptid;
|
||||
PushKafKa(lastdto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{//直接批量处理
|
||||
foreach (var item in kfuser)//逐个好友处理数据
|
||||
{
|
||||
var iusers = await GetUser(item.Appid, item.Externaluserid);
|
||||
List<WeworkExternalUser> kfExternal = new List<WeworkExternalUser>();
|
||||
rrWeworkUser = await BindWeworkUser(iusers, kfExternal);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(kfExternal, iusers, t);
|
||||
foreach (var rritem in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(rritem);//更新和插入 事业部变更后的好友关系
|
||||
if (rritem.deptid == t.deptid)
|
||||
{
|
||||
rritem.deptid = t.olddeptid.Value;
|
||||
await ChangeWheorkUserDeptid(rritem);//查找 事业部变更前的好友关系,有则标记删除
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "inner_eidbind_item"://逐个处理换绑资源
|
||||
if (!string.IsNullOrEmpty(t.appid) && !string.IsNullOrEmpty(t.appuserid) && t.olddeptid.HasValue && t.deptid.HasValue)
|
||||
{
|
||||
var appidList = t.appid.Split(',').ToList();
|
||||
var appuseridList = t.appuserid.Split(',').ToList();
|
||||
if (appidList.Count() == appuseridList.Count())
|
||||
{//一次性处理9个
|
||||
int index = 0;
|
||||
foreach (var appid in appidList)
|
||||
{
|
||||
var appuserid = appuseridList[index];
|
||||
users = await GetUser(appid, appuserid);
|
||||
List<WeworkExternalUser> kfExternal = new List<WeworkExternalUser>();
|
||||
rrWeworkUser = await BindWeworkUser(users, kfExternal);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(kfExternal, users, t);
|
||||
foreach (var rritem in rrWeworkUser)
|
||||
{
|
||||
await ChangeDeptWeworkUser(rritem, t.olddeptid.Value);//更新和插入 事业部变更后的好友关系
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "register":
|
||||
users = await GetUser(t.appid, t.appuserid);
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询客服名下所有客户
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<WeworkExternalUser>> GetKFUser(string appid, string userid)
|
||||
{
|
||||
MySqlParameter[] param = new MySqlParameter[] {
|
||||
new MySqlParameter(){ DbType=System.Data.DbType.String,Value=appid,ParameterName="appid"},
|
||||
new MySqlParameter(){ DbType=System.Data.DbType.String,Value=userid,ParameterName="userid"}
|
||||
};
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var extUser = await dncmsRepository.ExecuteSqlToListAsync<WeworkExternalUser>($"select appid,userid,appid_ext,externaluserid,deptid,unionid,subscribe,subscribetime from WeworkExternalUser where appid=@appid and userid=@userid", param);
|
||||
return extUser;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户当前 resid数据
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<UserInfoReq>> GetUser(string appid, string appuserid)
|
||||
{
|
||||
IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
var url = $"{_systemConfig.Value.zxdCoreApi}/Api/UserInfo/list";
|
||||
var resModel = await _httpClient.GetAsync<ZXDApiResult<IList<UserInfoReq>>>($"{url}?appid={appid}&appuserid={appuserid}");
|
||||
if (resModel.code == 0)
|
||||
{
|
||||
res = resModel.data;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户当前 resid数据
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<UserInfoReq>> GetUser(int? customerid)
|
||||
{
|
||||
IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
if (customerid.HasValue)
|
||||
{
|
||||
var url = $"{_systemConfig.Value.zxdCoreApi}/Api/UserInfo/list";
|
||||
//var req = HttpHelper.GetData(url, $"?cid={customerid}", Encoding.UTF8);
|
||||
//var resModel = JsonHelper.FromJson<ZXDApiResult<IList<UserInfoReq>>>(req);
|
||||
|
||||
var resModel = await _httpClient.GetAsync<ZXDApiResult<IList<UserInfoReq>>>($"{url}?cid={customerid}");
|
||||
if (resModel.code == 0)
|
||||
{
|
||||
res = resModel.data;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 匹配两个好友解绑时的所有情况
|
||||
/// </summary>
|
||||
/// <param name="userInfo1"></param>
|
||||
/// <param name="userInfo2"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<ResResidWeworkUser>> UnBindWeworkUser(IList<UserInfoReq> userInfo1, IList<UserInfoReq> userInfo2)
|
||||
{
|
||||
IList<ResResidWeworkUser> res = new List<ResResidWeworkUser>();
|
||||
//var userGup1 = userInfo1.Where(m => !string.IsNullOrEmpty(m.resid)).GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.ToList());
|
||||
//var userGup2 = userInfo2.Where(m => !string.IsNullOrEmpty(m.resid)).GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.ToList());
|
||||
List<WeworkExternalUser> mainExternalUsers = new List<WeworkExternalUser>();
|
||||
List<WeworkExternalUser> secExternalUsers = new List<WeworkExternalUser>();
|
||||
//获取当前解绑后的 rrwu数据
|
||||
var wwuser1 = await BindWeworkUser(userInfo1, mainExternalUsers);
|
||||
var wwuser2 = await BindWeworkUser(userInfo2, secExternalUsers);
|
||||
//拼接两个数据的交集
|
||||
foreach (var u1 in wwuser1)
|
||||
{
|
||||
foreach (var u2 in wwuser2)
|
||||
{
|
||||
ResResidWeworkUser r = new ResResidWeworkUser();
|
||||
r.resid = u1.resid;
|
||||
r.unionid = u1.unionid;
|
||||
r.deptid = u1.deptid;
|
||||
r.first_subscribetime = u1.first_subscribetime;
|
||||
r.last_subscribetime = u1.last_subscribetime;
|
||||
r.status = u1.status;
|
||||
//删除集合1与集合2的 交集
|
||||
r.appid = u2.appid;
|
||||
r.appuserid = u2.appuserid;
|
||||
r.isdelete = 1;
|
||||
r.utime = DateTime.Now;
|
||||
res.Add(r);
|
||||
}
|
||||
}
|
||||
//cid2 与1的交集数据
|
||||
foreach (var u1 in wwuser2)
|
||||
{
|
||||
foreach (var u2 in wwuser1)
|
||||
{
|
||||
ResResidWeworkUser r = new ResResidWeworkUser();
|
||||
r.resid = u1.resid;
|
||||
r.unionid = u1.unionid;
|
||||
r.deptid = u1.deptid;
|
||||
r.first_subscribetime = u1.first_subscribetime;
|
||||
r.last_subscribetime = u1.last_subscribetime;
|
||||
r.status = u1.status;
|
||||
//删除集合1与集合2的 交集
|
||||
r.appid = u2.appid;
|
||||
r.appuserid = u2.appuserid;
|
||||
r.isdelete = 1;
|
||||
r.utime = DateTime.Now;
|
||||
res.Add(r);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 匹配当前用户最终好友状态
|
||||
/// </summary>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<ResResidWeworkUser>> BindWeworkUser(IList<UserInfoReq> userInfo, List<WeworkExternalUser> weworkExternalUsers)
|
||||
{
|
||||
List<ResResidWeworkUser> resResidWeworkUsers = new List<ResResidWeworkUser>();
|
||||
if (userInfo.Count == 0)
|
||||
{
|
||||
return resResidWeworkUsers;
|
||||
}
|
||||
var extuserfilter = userInfo.Select(n => $"'{n.appuserid}'").Distinct().ToList();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
MySqlParameter[] param = new MySqlParameter[] { };
|
||||
var extUserList = await dncmsRepository.ExecuteSqlToListAsync<WeworkExternalUser>($"select appid,userid,appid_ext,externaluserid,deptid,unionid,subscribe,subscribetime,regdate from WeworkExternalUser where externaluserid in ({string.Join(",", extuserfilter)})", param);
|
||||
foreach (var item in extUserList)
|
||||
{
|
||||
var userinfoItem = userInfo.FirstOrDefault(n => n.appid == item.Appid_ext && n.appuserid == item.Externaluserid && n.appid.EndsWith("_1"));
|
||||
if (userinfoItem != null)
|
||||
{
|
||||
weworkExternalUsers.Add(item);
|
||||
}
|
||||
}
|
||||
if (weworkExternalUsers.Any())
|
||||
{
|
||||
//好友关系分组
|
||||
var weworkExternalUsersGup = weworkExternalUsers.GroupBy(m => m.deptid + ";" + m.Appid + ";" + m.Externaluserid)
|
||||
.ToDictionary(m => m.Key, n => n.ToList());
|
||||
//resid分组
|
||||
var residGup = userInfo.Where(m => !string.IsNullOrEmpty(m.resid))
|
||||
.GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.Min(i => i.uid));
|
||||
//组合关系数据
|
||||
foreach (var resid in residGup)
|
||||
{
|
||||
foreach (var wwe in weworkExternalUsersGup)
|
||||
{
|
||||
var deptid = wwe.Key.Split(';')[0];
|
||||
var appid = wwe.Key.Split(';')[1];
|
||||
var extuserid = wwe.Key.Split(';')[2];
|
||||
var extList = wwe.Value;
|
||||
var extSubList = extList.Where(m => m.subscribe == 1);
|
||||
ResResidWeworkUser res = new ResResidWeworkUser();
|
||||
res.uid = int.Parse(resid.Value);
|
||||
res.deptid = int.Parse(deptid);
|
||||
res.resid = resid.Key;
|
||||
res.appid = appid;
|
||||
res.appuserid = extuserid;
|
||||
res.unionid = extList.Where(m => !string.IsNullOrEmpty(m.unionid)).FirstOrDefault()?.unionid;//unionid有则取
|
||||
if (extSubList.Any())
|
||||
{
|
||||
res.first_subscribetime = extSubList.Min(m => m.subscribetime ?? m.regdate);
|
||||
res.last_subscribetime = extSubList.Max(m => m.subscribetime ?? m.regdate);
|
||||
res.status = 1;//最终关注状态
|
||||
}
|
||||
else
|
||||
{
|
||||
res.first_subscribetime = null;
|
||||
res.last_subscribetime = null;
|
||||
res.status = 0;//最终关注状态
|
||||
}
|
||||
res.ctime = DateTime.Now;
|
||||
res.isdelete = 0;
|
||||
res.utime = DateTime.Now;
|
||||
resResidWeworkUsers.Add(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resResidWeworkUsers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入库ResResidWeworkUser
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeWeworkUser(ResResidWeworkUser model, bool add = true)
|
||||
{
|
||||
if (model == null) return;
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query()
|
||||
.FirstOrDefault(m => m.resid == model.resid && m.appuserid == model.appuserid && m.appid == model.appid && m.deptid == model.deptid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (tag != null)
|
||||
{
|
||||
tag.status = model.status;
|
||||
tag.first_subscribetime = model.first_subscribetime;
|
||||
tag.last_subscribetime = model.last_subscribetime;
|
||||
tag.isdelete = model.isdelete;
|
||||
//更新已有好友关系
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
//PushKafKa(MappingTolog(tag));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));
|
||||
}
|
||||
else if (add)
|
||||
{
|
||||
//插入新的好友关系
|
||||
var outModel = await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().InsertAsync(model);
|
||||
//PushKafKa(MappingTolog(outModel));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(outModel));
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
_logger.LogError($"入库ResResidWeworkUser报错:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 换事业部
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeDeptWeworkUser(ResResidWeworkUser model, int olddeptid)
|
||||
{
|
||||
if (model == null) return;
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query()
|
||||
.FirstOrDefault(m => m.resid == model.resid && m.appuserid == model.appuserid && m.appid == model.appid && m.deptid == olddeptid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (tag != null)
|
||||
{
|
||||
tag.status = model.status;
|
||||
tag.first_subscribetime = model.first_subscribetime;
|
||||
tag.last_subscribetime = model.last_subscribetime;
|
||||
tag.isdelete = model.isdelete;
|
||||
tag.deptid = model.deptid;//更新事业部
|
||||
//更新已有好友关系
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
//插入新数据
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));
|
||||
//删除旧数据
|
||||
var delTag = MappingTolog(tag);
|
||||
delTag.isdelete = 1;
|
||||
delTag.deptid = olddeptid;
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(delTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
//插入新的好友关系
|
||||
var outModel = await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().InsertAsync(model);
|
||||
//PushKafKa(MappingTolog(outModel));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(outModel));
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
_logger.LogError($"换事业部报错:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事业部替换
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeWheorkUserDeptid(ResResidWeworkUser oldrrw)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query().FirstOrDefault(m => m.appuserid == oldrrw.appuserid && m.appid == oldrrw.appid && m.deptid == oldrrw.deptid);
|
||||
if (tag != null && tag.isdelete == 0)
|
||||
{
|
||||
//await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));//旧事业部数据删除
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐射对象
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private ResResidWeworkUserLog MappingTolog(ResResidWeworkUser model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
ResResidWeworkUserLog res = new ResResidWeworkUserLog();
|
||||
res.mainid = model.id;
|
||||
res.uid = model.uid;
|
||||
res.appid = model.appid;
|
||||
res.appuserid = model.appuserid;
|
||||
res.resid = model.resid;
|
||||
res.deptid = model.deptid;
|
||||
res.unionid = model.unionid;
|
||||
res.status = model.status;
|
||||
res.isdelete = model.isdelete;
|
||||
res.first_subscribetime = model.first_subscribetime;
|
||||
res.last_subscribetime = model.last_subscribetime;
|
||||
res.ctime = model.ctime;
|
||||
res.utime = model.utime;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 推送队列
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
/// <returns></returns>
|
||||
private async Task PushKafKa(WeworkWorkerDto log)
|
||||
{
|
||||
//IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
//var url = $"{_systemConfig.Value.zxdCoreApi}/Api/WeWork/SyncBinding";
|
||||
//var req = HttpHelper.PostAjaxData(url, JsonHelper.ToJson(log), Encoding.UTF8);
|
||||
|
||||
//var resModel = JsonHelper.FromJson<ZXDApiResult<string>>(req);
|
||||
//if (resModel.code != 0)
|
||||
//{
|
||||
// Log.Write(Serilog.Events.LogEventLevel.Error, req);
|
||||
//}
|
||||
var consumers = KafkaClient.GetConsumers();
|
||||
await KafkaClient.SendMessage(consumers.FirstOrDefault(n => n.Topic == "crm-topic"), log);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录日志
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task EventLog(WeworkWorkerDto t)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
ResResidWeworkEventLog log = new ResResidWeworkEventLog();
|
||||
log.appid = t.appid;
|
||||
log.userid = t.userid;
|
||||
log.appuserid = t.appuserid;
|
||||
log.type = t.type;
|
||||
log.deptid = t.deptid;
|
||||
log.olddeptid = t.olddeptid;
|
||||
log.eventJson = JsonHelper.ToJson(t);
|
||||
log.cid = t.cid;
|
||||
log.ctime = DateTime.Now;
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkEventLog>().InsertAsync(log);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人 赋值资源进线时间
|
||||
/// </summary>
|
||||
/// <param name="extUser"></param>
|
||||
/// <param name="userInfoList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SetSourcePassInfo(List<WeworkExternalUser> extUser, IList<UserInfoReq> userInfoList, WeworkWorkerDto t)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (extUser.Count == 0 || userInfoList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var uidFilter = userInfoList.Select(n => Convert.ToInt32(n.uid)).Distinct().ToList();
|
||||
var regdate = await GetRegDate(userInfoList);
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var dbList = await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().Query().Where(n => uidFilter.Contains(n.uid)).ToListAsync();
|
||||
var groupdeptid = extUser.GroupBy(n => n.deptid).ToList();
|
||||
List<ResourceProtectInfo> insertList = new List<ResourceProtectInfo>();
|
||||
List<ResourceProtectInfo> updateList = new List<ResourceProtectInfo>();
|
||||
List<ResourceProtectInfo> delList = new List<ResourceProtectInfo>();
|
||||
var customerid = 0;
|
||||
Int32.TryParse(userInfoList.FirstOrDefault().customerid, out customerid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
foreach (var deptid in groupdeptid)
|
||||
{
|
||||
var deptUser = extUser.Where(n => n.deptid == deptid.Key).ToList();
|
||||
var subItem = deptUser.OrderBy(n => n.subscribetime).OrderBy(n => n.regdate).FirstOrDefault();
|
||||
var dbItem = dbList.FirstOrDefault(n => n.deptid == deptid.Key && n.customerid == customerid);
|
||||
var useritem = userInfoList.FirstOrDefault(n => n.appid == subItem.Appid_ext && n.appuserid == subItem.Externaluserid);
|
||||
if (useritem == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var uid = 0;
|
||||
Int32.TryParse(useritem.uid, out uid);
|
||||
|
||||
if (dbItem == null)
|
||||
{
|
||||
ResourceProtectInfo model = new ResourceProtectInfo
|
||||
{
|
||||
uid = uid,
|
||||
appid = useritem.appid,
|
||||
appuserid = useritem.appuserid,
|
||||
resid = useritem.resid,
|
||||
unionid = useritem.unionid,
|
||||
customerid = customerid,
|
||||
deptid = subItem.deptid,
|
||||
firstfollowtime = deptUser.Min(m => m.subscribetime ?? m.regdate),
|
||||
followtime = deptUser.Where(n => n.subscribe == 1).Min(m => m.subscribetime ?? m.regdate),
|
||||
ctime = DateTime.Now,
|
||||
regtime = regdate,
|
||||
eventtype = t.type,
|
||||
};
|
||||
if (!model.followtime.HasValue)
|
||||
{
|
||||
model.isdelete = 1;
|
||||
}
|
||||
insertList.Add(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbItem.deptid = subItem.deptid;
|
||||
dbItem.uid = uid;
|
||||
dbItem.resid = useritem.resid;
|
||||
dbItem.unionid = useritem.unionid;
|
||||
dbItem.customerid = customerid;
|
||||
dbItem.deptid = subItem.deptid;
|
||||
dbItem.firstfollowtime = deptUser.Min(m => m.subscribetime ?? m.regdate);
|
||||
dbItem.followtime = deptUser.Where(n => n.subscribe == 1).Min(m => m.subscribetime ?? m.regdate);
|
||||
dbItem.utime = DateTime.Now;
|
||||
dbItem.regtime = regdate;
|
||||
dbItem.eventtype = t.type;
|
||||
if (!dbItem.followtime.HasValue)
|
||||
{
|
||||
dbItem.isdelete = 1;
|
||||
}
|
||||
updateList.Add(dbItem);
|
||||
}
|
||||
}
|
||||
bool update = false;
|
||||
if (updateList.Count > 0)
|
||||
{
|
||||
update = true;
|
||||
await SetDeptInfo(updateList);
|
||||
await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().BatchUpdateAsync(updateList);
|
||||
}
|
||||
if (insertList.Count > 0)
|
||||
{
|
||||
update = true;
|
||||
await SetDeptInfo(insertList);
|
||||
await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().BatchInsertAsync(insertList);
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
transaction.Commit();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"计算资源进线时间错误{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<DateTime?> GetRegDate(IList<UserInfoReq> userInfoList)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var zxdRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<ZxdDbContext>>();
|
||||
var userList = userInfoList.Select(n => n.appuserid).Distinct().ToList();
|
||||
var softuser = await zxdRepository.GetRepository<SOFT_USER>().Query().Where(n => userList.Contains(n.USERNAME)).ToListAsync();
|
||||
return softuser.Min(n => n.REGDATE);
|
||||
}
|
||||
|
||||
private async Task SetDeptInfo(List<ResourceProtectInfo> model)
|
||||
{
|
||||
var key = "deptment_list_new";
|
||||
var deptInfo = new List<DeptmentDto>();
|
||||
if (await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
deptInfo = await _redisManager.GetListAsync<DeptmentDto>(key);
|
||||
}
|
||||
if (deptInfo != null && deptInfo.Count > 0)
|
||||
{
|
||||
foreach (var item in model)
|
||||
{
|
||||
var dept = deptInfo.FirstOrDefault(n => n.Id == item.deptid);
|
||||
item.deptname = dept?.Title;
|
||||
item.groupid = dept?.GroupId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,723 @@
|
|||
using DG.EntityFramework;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WeworkUserWorker.Config;
|
||||
using Zxd.Entity.Dncms;
|
||||
using Zxd.Entity.UserCenter;
|
||||
using Zxd.EntityFramework;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DG.Kafka;
|
||||
using MySqlConnector;
|
||||
using System.Diagnostics;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
using DG.Redis;
|
||||
using Zxd.Entity.Zxd;
|
||||
|
||||
namespace WeworkUserWorker.Workers
|
||||
{
|
||||
internal class WeworkWorker : KafkaWorkerBase<WeworkWorkerDto>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<WeworkWorker> _logger;
|
||||
private readonly IOptionsSnapshot<SystemConfig> _systemConfig;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IRedisManager _redisManager;
|
||||
|
||||
public WeworkWorker(
|
||||
IServiceProvider serviceProvider,
|
||||
IOptionsSnapshot<SystemConfig> systemConfig,
|
||||
ILogger<WeworkWorker> logger,
|
||||
IHttpClient httpClient, IRedisManager redisManager
|
||||
) : base(logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_httpClient = httpClient;
|
||||
_systemConfig = systemConfig;
|
||||
_logger = logger;
|
||||
_redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理好友最终关系
|
||||
/// 数据逻辑
|
||||
/// 1、通过appid和appuserid去usercenter.userinfo中找出customerid,并通过customerid查出userinfo中所有用户数据,
|
||||
/// 2、假如数据中没有resid、忽略不处理。
|
||||
/// 3、假如有resid去dncms.weworkexternaluser中查找数据,subscribe = 1筛选数据,用subscribetime去 res_resid_weworkuser
|
||||
/// 表中appid、appuserid数据取firsttime和最早的subscribetime 对比,有变动就修正,假如res_resid_weworkuser 中的在刚刚查找出来没有关注数据了,
|
||||
/// 将status改成0 。假如res_resid_weworkuser 没有数据,插入一条数据。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
protected override async Task DoWorkAsync(WeworkWorkerDto t)
|
||||
{
|
||||
IList<ResResidWeworkUser> resResids = new List<ResResidWeworkUser>();
|
||||
IList<UserInfoReq> users = new List<UserInfoReq>();
|
||||
List<ResResidWeworkUser> rrWeworkUser = new List<ResResidWeworkUser>();
|
||||
List<WeworkExternalUser> mainExternalUsers = new List<WeworkExternalUser>();
|
||||
List<WeworkExternalUser> secExternalUsers = new List<WeworkExternalUser>();
|
||||
try
|
||||
{
|
||||
await EventLog(t);
|
||||
switch (t.type?.ToLower())
|
||||
{
|
||||
case "subscribe"://关注
|
||||
case "unsubscribe"://取关
|
||||
_logger.LogWarning("开始处理取关!");
|
||||
users = await GetUser(t.appid, t.appuserid); //请求此用户的所有用户信息
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//查询当前客户好友关系
|
||||
foreach (var item in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
_logger.LogWarning("结束处理取关!");
|
||||
break;
|
||||
|
||||
case "merge"://合并
|
||||
_logger.LogWarning("开始处理合并!");
|
||||
if (int.TryParse(t.cid, out int incid))
|
||||
{
|
||||
users = await GetUser(incid);//请求此用户的所有用户信息
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//查询当前客户好友关系
|
||||
foreach (var item in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
}
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
_logger.LogWarning("结束处理合并!");
|
||||
break;
|
||||
|
||||
case "unmerge"://解绑
|
||||
_logger.LogWarning("开始处理解绑!");
|
||||
var cidarry = t.cid?.Trim().Split(',');
|
||||
if (cidarry != null && cidarry.Count() == 2)
|
||||
{
|
||||
var scid = cidarry[0];
|
||||
var ecid = cidarry[1];
|
||||
var susers = await GetUser(int.Parse(scid));//分别查询出两个cid对应的客户信息
|
||||
var eusers = await GetUser(int.Parse(ecid));//
|
||||
var swu = await BindWeworkUser(susers, mainExternalUsers);//查询当前客户好友关系
|
||||
//await SetSourcePassInfo(mainExternalUsers, susers, t);
|
||||
var ewu = await BindWeworkUser(eusers, secExternalUsers);//查询当前客户好友关系
|
||||
//await SetSourcePassInfo(secExternalUsers, eusers, t);
|
||||
foreach (var item in swu)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
foreach (var item in ewu)
|
||||
{
|
||||
await ChangeWeworkUser(item);//入库
|
||||
}
|
||||
var unlist = await UnBindWeworkUser(susers, eusers);//拼接两个cid的 重叠部分
|
||||
foreach (var item in unlist)
|
||||
{
|
||||
//事业部不发生变化
|
||||
await ChangeWeworkUser(item, false);//解绑匹配的新数据不入库,旧数据标记删除
|
||||
}
|
||||
}
|
||||
_logger.LogWarning("结束处理解绑!");
|
||||
break;
|
||||
|
||||
case "eidbind"://跨部门换绑工号 300秒超时
|
||||
if (t.olddeptid.HasValue && t.deptid.HasValue && t.olddeptid != t.deptid)
|
||||
{
|
||||
var kfuser = await GetKFUser(t.appid, t.userid); //请求此用户的所有用户信息
|
||||
if (kfuser.Count() > 300)
|
||||
{//给队列逐条处理
|
||||
IList<string> appidStr = new List<string>();
|
||||
IList<string> euseridStr = new List<string>();
|
||||
foreach (var item in kfuser)
|
||||
{
|
||||
appidStr.Add(item.Appid_ext);
|
||||
euseridStr.Add(item.Externaluserid);
|
||||
if (appidStr.Count() > 9)
|
||||
{
|
||||
WeworkWorkerDto dto = new WeworkWorkerDto();
|
||||
dto.type = "inner_eidbind_item";
|
||||
dto.appuserid = String.Join(",", euseridStr);
|
||||
dto.appid = String.Join(",", appidStr);
|
||||
dto.deptid = t.deptid;
|
||||
dto.olddeptid = t.olddeptid;
|
||||
PushKafKa(dto);
|
||||
appidStr = new List<string>();
|
||||
euseridStr = new List<string>();
|
||||
}
|
||||
}
|
||||
//循环结束验证是否有未完成
|
||||
if (euseridStr.Any())
|
||||
{
|
||||
WeworkWorkerDto lastdto = new WeworkWorkerDto();
|
||||
lastdto.type = "inner_eidbind_item";
|
||||
lastdto.appuserid = String.Join(",", euseridStr);
|
||||
lastdto.appid = String.Join(",", appidStr);
|
||||
lastdto.deptid = t.deptid;
|
||||
lastdto.olddeptid = t.olddeptid;
|
||||
PushKafKa(lastdto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{//直接批量处理
|
||||
foreach (var item in kfuser)//逐个好友处理数据
|
||||
{
|
||||
var iusers = await GetUser(item.Appid, item.Externaluserid);
|
||||
List<WeworkExternalUser> kfExternal = new List<WeworkExternalUser>();
|
||||
rrWeworkUser = await BindWeworkUser(iusers, kfExternal);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(kfExternal, iusers, t);
|
||||
foreach (var rritem in rrWeworkUser)
|
||||
{
|
||||
await ChangeWeworkUser(rritem);//更新和插入 事业部变更后的好友关系
|
||||
if (rritem.deptid == t.deptid)
|
||||
{
|
||||
rritem.deptid = t.olddeptid.Value;
|
||||
await ChangeWheorkUserDeptid(rritem);//查找 事业部变更前的好友关系,有则标记删除
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "inner_eidbind_item"://逐个处理换绑资源
|
||||
if (!string.IsNullOrEmpty(t.appid) && !string.IsNullOrEmpty(t.appuserid) && t.olddeptid.HasValue && t.deptid.HasValue)
|
||||
{
|
||||
var appidList = t.appid.Split(',').ToList();
|
||||
var appuseridList = t.appuserid.Split(',').ToList();
|
||||
if (appidList.Count() == appuseridList.Count())
|
||||
{//一次性处理9个
|
||||
int index = 0;
|
||||
foreach (var appid in appidList)
|
||||
{
|
||||
var appuserid = appuseridList[index];
|
||||
users = await GetUser(appid, appuserid);
|
||||
List<WeworkExternalUser> kfExternal = new List<WeworkExternalUser>();
|
||||
rrWeworkUser = await BindWeworkUser(users, kfExternal);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(kfExternal, users, t);
|
||||
foreach (var rritem in rrWeworkUser)
|
||||
{
|
||||
await ChangeDeptWeworkUser(rritem, t.olddeptid.Value);//更新和插入 事业部变更后的好友关系
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "register":
|
||||
users = await GetUser(t.appid, t.appuserid);
|
||||
rrWeworkUser = await BindWeworkUser(users, mainExternalUsers);//重新计算当前客户好友关系
|
||||
//await SetSourcePassInfo(mainExternalUsers, users, t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询客服名下所有客户
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<WeworkExternalUser>> GetKFUser(string appid, string userid)
|
||||
{
|
||||
MySqlParameter[] param = new MySqlParameter[] {
|
||||
new MySqlParameter(){ DbType=System.Data.DbType.String,Value=appid,ParameterName="appid"},
|
||||
new MySqlParameter(){ DbType=System.Data.DbType.String,Value=userid,ParameterName="userid"}
|
||||
};
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
var extUser = await dncmsRepository.ExecuteSqlToListAsync<WeworkExternalUser>($"select appid,userid,appid_ext,externaluserid,deptid,unionid,subscribe,subscribetime from WeworkExternalUser where appid=@appid and userid=@userid", param);
|
||||
return extUser;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户当前 resid数据
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<UserInfoReq>> GetUser(string appid, string appuserid)
|
||||
{
|
||||
IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
var url = $"{_systemConfig.Value.zxdCoreApi}/Api/UserInfo/list";
|
||||
var resModel = await _httpClient.GetAsync<ZXDApiResult<IList<UserInfoReq>>>($"{url}?appid={appid}&appuserid={appuserid}");
|
||||
if (resModel.code == 0)
|
||||
{
|
||||
res = resModel.data;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取客户当前 resid数据
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<UserInfoReq>> GetUser(int? customerid)
|
||||
{
|
||||
IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
if (customerid.HasValue)
|
||||
{
|
||||
var url = $"{_systemConfig.Value.zxdCoreApi}/Api/UserInfo/list";
|
||||
//var req = HttpHelper.GetData(url, $"?cid={customerid}", Encoding.UTF8);
|
||||
//var resModel = JsonHelper.FromJson<ZXDApiResult<IList<UserInfoReq>>>(req);
|
||||
|
||||
var resModel = await _httpClient.GetAsync<ZXDApiResult<IList<UserInfoReq>>>($"{url}?cid={customerid}");
|
||||
if (resModel.code == 0)
|
||||
{
|
||||
res = resModel.data;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 匹配两个好友解绑时的所有情况
|
||||
/// </summary>
|
||||
/// <param name="userInfo1"></param>
|
||||
/// <param name="userInfo2"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IList<ResResidWeworkUser>> UnBindWeworkUser(IList<UserInfoReq> userInfo1, IList<UserInfoReq> userInfo2)
|
||||
{
|
||||
IList<ResResidWeworkUser> res = new List<ResResidWeworkUser>();
|
||||
//var userGup1 = userInfo1.Where(m => !string.IsNullOrEmpty(m.resid)).GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.ToList());
|
||||
//var userGup2 = userInfo2.Where(m => !string.IsNullOrEmpty(m.resid)).GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.ToList());
|
||||
List<WeworkExternalUser> mainExternalUsers = new List<WeworkExternalUser>();
|
||||
List<WeworkExternalUser> secExternalUsers = new List<WeworkExternalUser>();
|
||||
//获取当前解绑后的 rrwu数据
|
||||
var wwuser1 = await BindWeworkUser(userInfo1, mainExternalUsers);
|
||||
var wwuser2 = await BindWeworkUser(userInfo2, secExternalUsers);
|
||||
//拼接两个数据的交集
|
||||
foreach (var u1 in wwuser1)
|
||||
{
|
||||
foreach (var u2 in wwuser2)
|
||||
{
|
||||
ResResidWeworkUser r = new ResResidWeworkUser();
|
||||
r.resid = u1.resid;
|
||||
r.unionid = u1.unionid;
|
||||
r.deptid = u1.deptid;
|
||||
r.first_subscribetime = u1.first_subscribetime;
|
||||
r.last_subscribetime = u1.last_subscribetime;
|
||||
r.status = u1.status;
|
||||
//删除集合1与集合2的 交集
|
||||
r.appid = u2.appid;
|
||||
r.appuserid = u2.appuserid;
|
||||
r.isdelete = 1;
|
||||
r.utime = DateTime.Now;
|
||||
res.Add(r);
|
||||
}
|
||||
}
|
||||
//cid2 与1的交集数据
|
||||
foreach (var u1 in wwuser2)
|
||||
{
|
||||
foreach (var u2 in wwuser1)
|
||||
{
|
||||
ResResidWeworkUser r = new ResResidWeworkUser();
|
||||
r.resid = u1.resid;
|
||||
r.unionid = u1.unionid;
|
||||
r.deptid = u1.deptid;
|
||||
r.first_subscribetime = u1.first_subscribetime;
|
||||
r.last_subscribetime = u1.last_subscribetime;
|
||||
r.status = u1.status;
|
||||
//删除集合1与集合2的 交集
|
||||
r.appid = u2.appid;
|
||||
r.appuserid = u2.appuserid;
|
||||
r.isdelete = 1;
|
||||
r.utime = DateTime.Now;
|
||||
res.Add(r);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 匹配当前用户最终好友状态
|
||||
/// </summary>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<ResResidWeworkUser>> BindWeworkUser(IList<UserInfoReq> userInfo, List<WeworkExternalUser> weworkExternalUsers)
|
||||
{
|
||||
List<ResResidWeworkUser> resResidWeworkUsers = new List<ResResidWeworkUser>();
|
||||
if (userInfo.Count == 0)
|
||||
{
|
||||
return resResidWeworkUsers;
|
||||
}
|
||||
var extuserfilter = userInfo.Select(n => $"'{n.appuserid}'").Distinct().ToList();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsDbContext>>();
|
||||
MySqlParameter[] param = new MySqlParameter[] { };
|
||||
var extUserList = await dncmsRepository.ExecuteSqlToListAsync<WeworkExternalUser>($"select appid,userid,appid_ext,externaluserid,deptid,unionid,subscribe,subscribetime,regdate from WeworkExternalUser where externaluserid in ({string.Join(",", extuserfilter)})", param);
|
||||
foreach (var item in extUserList)
|
||||
{
|
||||
var userinfoItem = userInfo.FirstOrDefault(n => n.appid == item.Appid_ext && n.appuserid == item.Externaluserid && n.appid.EndsWith("_1"));
|
||||
if (userinfoItem != null)
|
||||
{
|
||||
weworkExternalUsers.Add(item);
|
||||
}
|
||||
}
|
||||
if (weworkExternalUsers.Any())
|
||||
{
|
||||
//好友关系分组
|
||||
var weworkExternalUsersGup = weworkExternalUsers.GroupBy(m => m.deptid + ";" + m.Appid + ";" + m.Externaluserid)
|
||||
.ToDictionary(m => m.Key, n => n.ToList());
|
||||
//resid分组
|
||||
var residGup = userInfo.Where(m => !string.IsNullOrEmpty(m.resid))
|
||||
.GroupBy(m => m.resid).ToDictionary(m => m.Key, n => n.Min(i => i.uid));
|
||||
//组合关系数据
|
||||
foreach (var resid in residGup)
|
||||
{
|
||||
foreach (var wwe in weworkExternalUsersGup)
|
||||
{
|
||||
var deptid = wwe.Key.Split(';')[0];
|
||||
var appid = wwe.Key.Split(';')[1];
|
||||
var extuserid = wwe.Key.Split(';')[2];
|
||||
var extList = wwe.Value;
|
||||
var extSubList = extList.Where(m => m.subscribe == 1);
|
||||
ResResidWeworkUser res = new ResResidWeworkUser();
|
||||
res.uid = int.Parse(resid.Value);
|
||||
res.deptid = int.Parse(deptid);
|
||||
res.resid = resid.Key;
|
||||
res.appid = appid;
|
||||
res.appuserid = extuserid;
|
||||
res.unionid = extList.Where(m => !string.IsNullOrEmpty(m.unionid)).FirstOrDefault()?.unionid;//unionid有则取
|
||||
if (extSubList.Any())
|
||||
{
|
||||
res.first_subscribetime = extSubList.Min(m => m.subscribetime ?? m.regdate);
|
||||
res.last_subscribetime = extSubList.Max(m => m.subscribetime ?? m.regdate);
|
||||
res.status = 1;//最终关注状态
|
||||
}
|
||||
else
|
||||
{
|
||||
res.first_subscribetime = null;
|
||||
res.last_subscribetime = null;
|
||||
res.status = 0;//最终关注状态
|
||||
}
|
||||
res.ctime = DateTime.Now;
|
||||
res.isdelete = 0;
|
||||
res.utime = DateTime.Now;
|
||||
resResidWeworkUsers.Add(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resResidWeworkUsers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入库ResResidWeworkUser
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeWeworkUser(ResResidWeworkUser model, bool add = true)
|
||||
{
|
||||
if (model == null) return;
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query()
|
||||
.FirstOrDefault(m => m.resid == model.resid && m.appuserid == model.appuserid && m.appid == model.appid && m.deptid == model.deptid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (tag != null)
|
||||
{
|
||||
tag.status = model.status;
|
||||
tag.first_subscribetime = model.first_subscribetime;
|
||||
tag.last_subscribetime = model.last_subscribetime;
|
||||
tag.isdelete = model.isdelete;
|
||||
//更新已有好友关系
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
//PushKafKa(MappingTolog(tag));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));
|
||||
}
|
||||
else if (add)
|
||||
{
|
||||
//插入新的好友关系
|
||||
var outModel = await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().InsertAsync(model);
|
||||
//PushKafKa(MappingTolog(outModel));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(outModel));
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
_logger.LogError($"入库ResResidWeworkUser报错:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 换事业部
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeDeptWeworkUser(ResResidWeworkUser model, int olddeptid)
|
||||
{
|
||||
if (model == null) return;
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query()
|
||||
.FirstOrDefault(m => m.resid == model.resid && m.appuserid == model.appuserid && m.appid == model.appid && m.deptid == olddeptid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (tag != null)
|
||||
{
|
||||
tag.status = model.status;
|
||||
tag.first_subscribetime = model.first_subscribetime;
|
||||
tag.last_subscribetime = model.last_subscribetime;
|
||||
tag.isdelete = model.isdelete;
|
||||
tag.deptid = model.deptid;//更新事业部
|
||||
//更新已有好友关系
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
//插入新数据
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));
|
||||
//删除旧数据
|
||||
var delTag = MappingTolog(tag);
|
||||
delTag.isdelete = 1;
|
||||
delTag.deptid = olddeptid;
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(delTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
//插入新的好友关系
|
||||
var outModel = await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().InsertAsync(model);
|
||||
//PushKafKa(MappingTolog(outModel));
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(outModel));
|
||||
}
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
_logger.LogError($"换事业部报错:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事业部替换
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task ChangeWheorkUserDeptid(ResResidWeworkUser oldrrw)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var tag = dncmsbaseRepository.GetRepository<ResResidWeworkUser>().Query().FirstOrDefault(m => m.appuserid == oldrrw.appuserid && m.appid == oldrrw.appid && m.deptid == oldrrw.deptid);
|
||||
if (tag != null && tag.isdelete == 0)
|
||||
{
|
||||
//await dncmsbaseRepository.GetRepository<ResResidWeworkUser>().UpdateAsync(tag);
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkUserLog>().InsertAsync(MappingTolog(tag));//旧事业部数据删除
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐射对象
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private ResResidWeworkUserLog MappingTolog(ResResidWeworkUser model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
ResResidWeworkUserLog res = new ResResidWeworkUserLog();
|
||||
res.mainid = model.id;
|
||||
res.uid = model.uid;
|
||||
res.appid = model.appid;
|
||||
res.appuserid = model.appuserid;
|
||||
res.resid = model.resid;
|
||||
res.deptid = model.deptid;
|
||||
res.unionid = model.unionid;
|
||||
res.status = model.status;
|
||||
res.isdelete = model.isdelete;
|
||||
res.first_subscribetime = model.first_subscribetime;
|
||||
res.last_subscribetime = model.last_subscribetime;
|
||||
res.ctime = model.ctime;
|
||||
res.utime = model.utime;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 推送队列
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
/// <returns></returns>
|
||||
private async Task PushKafKa(WeworkWorkerDto log)
|
||||
{
|
||||
//IList<UserInfoReq> res = new List<UserInfoReq>();
|
||||
//var url = $"{_systemConfig.Value.zxdCoreApi}/Api/WeWork/SyncBinding";
|
||||
//var req = HttpHelper.PostAjaxData(url, JsonHelper.ToJson(log), Encoding.UTF8);
|
||||
|
||||
//var resModel = JsonHelper.FromJson<ZXDApiResult<string>>(req);
|
||||
//if (resModel.code != 0)
|
||||
//{
|
||||
// Log.Write(Serilog.Events.LogEventLevel.Error, req);
|
||||
//}
|
||||
var consumers = KafkaClient.GetConsumers();
|
||||
await KafkaClient.SendMessage(consumers.FirstOrDefault(n => n.Topic == "crm-topic"), log);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录日志
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task EventLog(WeworkWorkerDto t)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
ResResidWeworkEventLog log = new ResResidWeworkEventLog();
|
||||
log.appid = t.appid;
|
||||
log.userid = t.userid;
|
||||
log.appuserid = t.appuserid;
|
||||
log.type = t.type;
|
||||
log.deptid = t.deptid;
|
||||
log.olddeptid = t.olddeptid;
|
||||
log.eventJson = JsonHelper.ToJson(t);
|
||||
log.cid = t.cid;
|
||||
log.ctime = DateTime.Now;
|
||||
await dncmsbaseRepository.GetRepository<ResResidWeworkEventLog>().InsertAsync(log);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人 赋值资源进线时间
|
||||
/// </summary>
|
||||
/// <param name="extUser"></param>
|
||||
/// <param name="userInfoList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SetSourcePassInfo(List<WeworkExternalUser> extUser, IList<UserInfoReq> userInfoList, WeworkWorkerDto t)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (extUser.Count == 0 || userInfoList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var uidFilter = userInfoList.Select(n => Convert.ToInt32(n.uid)).Distinct().ToList();
|
||||
var regdate = await GetRegDate(userInfoList);
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var dbList = await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().Query().Where(n => uidFilter.Contains(n.uid)).ToListAsync();
|
||||
var groupdeptid = extUser.GroupBy(n => n.deptid).ToList();
|
||||
List<ResourceProtectInfo> insertList = new List<ResourceProtectInfo>();
|
||||
List<ResourceProtectInfo> updateList = new List<ResourceProtectInfo>();
|
||||
List<ResourceProtectInfo> delList = new List<ResourceProtectInfo>();
|
||||
var customerid = 0;
|
||||
Int32.TryParse(userInfoList.FirstOrDefault().customerid, out customerid);
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
foreach (var deptid in groupdeptid)
|
||||
{
|
||||
var deptUser = extUser.Where(n => n.deptid == deptid.Key).ToList();
|
||||
var subItem = deptUser.OrderBy(n => n.subscribetime).OrderBy(n => n.regdate).FirstOrDefault();
|
||||
var dbItem = dbList.FirstOrDefault(n => n.deptid == deptid.Key && n.customerid == customerid);
|
||||
var useritem = userInfoList.FirstOrDefault(n => n.appid == subItem.Appid_ext && n.appuserid == subItem.Externaluserid);
|
||||
if (useritem == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var uid = 0;
|
||||
Int32.TryParse(useritem.uid, out uid);
|
||||
|
||||
if (dbItem == null)
|
||||
{
|
||||
ResourceProtectInfo model = new ResourceProtectInfo
|
||||
{
|
||||
uid = uid,
|
||||
appid = useritem.appid,
|
||||
appuserid = useritem.appuserid,
|
||||
resid = useritem.resid,
|
||||
unionid = useritem.unionid,
|
||||
customerid = customerid,
|
||||
deptid = subItem.deptid,
|
||||
firstfollowtime = deptUser.Min(m => m.subscribetime ?? m.regdate),
|
||||
followtime = deptUser.Where(n => n.subscribe == 1).Min(m => m.subscribetime ?? m.regdate),
|
||||
ctime = DateTime.Now,
|
||||
regtime = regdate,
|
||||
eventtype = t.type,
|
||||
};
|
||||
if (!model.followtime.HasValue)
|
||||
{
|
||||
model.isdelete = 1;
|
||||
}
|
||||
insertList.Add(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbItem.deptid = subItem.deptid;
|
||||
dbItem.uid = uid;
|
||||
dbItem.resid = useritem.resid;
|
||||
dbItem.unionid = useritem.unionid;
|
||||
dbItem.customerid = customerid;
|
||||
dbItem.deptid = subItem.deptid;
|
||||
dbItem.firstfollowtime = deptUser.Min(m => m.subscribetime ?? m.regdate);
|
||||
dbItem.followtime = deptUser.Where(n => n.subscribe == 1).Min(m => m.subscribetime ?? m.regdate);
|
||||
dbItem.utime = DateTime.Now;
|
||||
dbItem.regtime = regdate;
|
||||
dbItem.eventtype = t.type;
|
||||
if (!dbItem.followtime.HasValue)
|
||||
{
|
||||
dbItem.isdelete = 1;
|
||||
}
|
||||
updateList.Add(dbItem);
|
||||
}
|
||||
}
|
||||
bool update = false;
|
||||
if (updateList.Count > 0)
|
||||
{
|
||||
update = true;
|
||||
await SetDeptInfo(updateList);
|
||||
await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().BatchUpdateAsync(updateList);
|
||||
}
|
||||
if (insertList.Count > 0)
|
||||
{
|
||||
update = true;
|
||||
await SetDeptInfo(insertList);
|
||||
await dncmsbaseRepository.GetRepository<ResourceProtectInfo>().BatchInsertAsync(insertList);
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
transaction.Commit();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"计算资源进线时间错误{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<DateTime?> GetRegDate(IList<UserInfoReq> userInfoList)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var zxdRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<ZxdDbContext>>();
|
||||
var userList = userInfoList.Select(n => n.appuserid).Distinct().ToList();
|
||||
var softuser = await zxdRepository.GetRepository<SOFT_USER>().Query().Where(n => userList.Contains(n.USERNAME)).ToListAsync();
|
||||
return softuser.Min(n => n.REGDATE);
|
||||
}
|
||||
|
||||
private async Task SetDeptInfo(List<ResourceProtectInfo> model)
|
||||
{
|
||||
var key = "deptment_list_new";
|
||||
var deptInfo = new List<DeptmentDto>();
|
||||
if (await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
deptInfo = await _redisManager.GetListAsync<DeptmentDto>(key);
|
||||
}
|
||||
if (deptInfo != null && deptInfo.Count > 0)
|
||||
{
|
||||
foreach (var item in model)
|
||||
{
|
||||
var dept = deptInfo.FirstOrDefault(n => n.Id == item.deptid);
|
||||
item.deptname = dept?.Title;
|
||||
item.groupid = dept?.GroupId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=10.22.15.61;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=10.22.15.68;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=10.22.15.68;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=10.22.15.68;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092,172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "crm-topic"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd.WeworkUserWorker",
|
||||
"TaskRemarks": "Zxd.WeworkUserWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "w8ktfSOJalWw6jZWjTs8qSOoLteO7WTSRdgIvja8"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"nodeWebApi": "http://10.22.15.5:8080"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"dncmsbase": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncmsbase;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"dncms": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=dncms;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None",
|
||||
"companyBaseConf": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=db_company_base_conf;user id=dn_cms;password=dn3EdxCms@8zsw_2Wkm;SslMode=None"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092,172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "crm-topic"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "Zxd.WeworkUserWorker",
|
||||
"TaskRemarks": "Zxd.WeworkUserWorker",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "w8ktfSOJalWw6jZWjTs8qSOoLteO7WTSRdgIvja8"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://120.77.165.155:8089",
|
||||
"nodeWebApi": "https://r2.soft.dn8188.com"
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "ZXD",
|
||||
"HostName": "redis-cngzdnddztrevahsz.redis.ivolces.com",
|
||||
"Port": "6379",
|
||||
"Password": "dn8sCe@mxTvzx",
|
||||
"Defaultdatabase": "0"
|
||||
},
|
||||
{
|
||||
"Name": "UserCenter",
|
||||
"HostName": "redis-cngzdnddztrevahsz.redis.ivolces.com",
|
||||
"Port": "6379",
|
||||
"Password": "dn8sCe@mxTvzx",
|
||||
"Defaultdatabase": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=root;Password=sa123456.;port=3306;",
|
||||
"dncms": "Server=192.168.11.41;Database=dncms;UserId=root;Password=sa123456.;port=3306;",
|
||||
"companyBaseConf": "Server=192.168.11.141;Database=db_company_base_conf;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crm": "Server=192.168.11.141;Database=db_crm;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "192.168.11.101:9092,192.168.11.104:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "crm-topic"
|
||||
},
|
||||
{
|
||||
"Host": "192.168.11.104:9092,192.168.11.104:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "ResPassTime"
|
||||
}
|
||||
],
|
||||
"TaskConfig": {
|
||||
"TaskName": "DG.Worker.Sample",
|
||||
"TaskRemarks": "DG.Worker.Sample",
|
||||
"Enable": true,
|
||||
"SecondsDelay": 5
|
||||
},
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "tmrp0GmwyTMe6UxJIw7LXAcIWYKEUgy2kprMiybd"
|
||||
},
|
||||
"SystemConfig": {
|
||||
"zxdCoreApi": "http://192.168.11.81:8089",
|
||||
"nodeWebApi": "http://120.238.224.24:10034"
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "ZXD",
|
||||
"HostName": "192.168.11.81",
|
||||
"Port": "6379",
|
||||
"Password": "Abc@123456",
|
||||
"Defaultdatabase": "1"
|
||||
},
|
||||
{
|
||||
"Name": "UserCenter",
|
||||
"HostName": "192.168.11.103",
|
||||
"Port": "6379",
|
||||
"Password": "123",
|
||||
"Defaultdatabase": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using Zxd.Core.Domain.Dto.Activity;
|
||||
|
||||
namespace Zxd.Core.Domain
|
||||
{
|
||||
public class ActivityDomain : IActivityDomain
|
||||
{
|
||||
private readonly IBaseRepository<DncmsbaseDbContext> _cmsRepository;
|
||||
|
||||
public ActivityDomain(
|
||||
IBaseRepository<DncmsbaseDbContext> cmsRepository)
|
||||
{
|
||||
_cmsRepository = cmsRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取活动名称
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetActivityNameAsync(GetActivityNameRequest request)
|
||||
{
|
||||
var tag = await _cmsRepository.GetRepository<resourcetag>().Query().Where(w => w.remark == request.Code).FirstOrDefaultAsync();
|
||||
if (tag == null)
|
||||
{
|
||||
throw new ArgumentException($"活动编码无效:{request.Code}");
|
||||
}
|
||||
|
||||
return tag.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Zxd.Domain
|
||||
{
|
||||
internal class CacheDomain : ICacheDomain
|
||||
{
|
||||
private readonly IRedisManager _redisManager;
|
||||
private readonly IBaseRepository<ZxdDbContext> _repository;
|
||||
|
||||
public CacheDomain(IRedisManager redisManager,
|
||||
IBaseRepository<ZxdDbContext> repository)
|
||||
{
|
||||
_redisManager = redisManager;
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
private async Task<List<BAS_PARAMETER>> GetParameterList()
|
||||
{
|
||||
if (!await _redisManager.ExistsAsync(CacheKeys.ParameterList))
|
||||
{
|
||||
var list = await _repository.GetRepository<BAS_PARAMETER>().QueryListAsync();
|
||||
await _redisManager.SetAsync(CacheKeys.ParameterList, list, new TimeSpan(0, 5, 0));//15分钟过期
|
||||
return list;
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _redisManager.GetListAsync<BAS_PARAMETER>(CacheKeys.ParameterList);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetValueParameter(string key)
|
||||
{
|
||||
var list = await GetParameterList();
|
||||
return list.FirstOrDefault(x => x.PARAKEY == key)?.PARAVALUE ?? "";
|
||||
}
|
||||
|
||||
public async Task<int> GetEarlyWarningValue()
|
||||
{
|
||||
var data = await GetValueParameter("EarlyWarningValue");
|
||||
if (string.IsNullOrEmpty(data) || int.TryParse(data, out int value))
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public async Task<List<SsoUserTokenInfo>> GetTokens()
|
||||
{
|
||||
var key = CacheKeys.TokenList;
|
||||
if (await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
return await _redisManager.GetListAsync<SsoUserTokenInfo>(key);
|
||||
}
|
||||
return new List<SsoUserTokenInfo>();
|
||||
}
|
||||
|
||||
public async Task AddToken(SsoUserTokenInfo token)
|
||||
{
|
||||
var key = CacheKeys.TokenList;
|
||||
if (!await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
await _redisManager.SetAsync(key, new List<SsoUserTokenInfo>() { token });
|
||||
}
|
||||
else
|
||||
{
|
||||
var list = await _redisManager.GetListAsync<SsoUserTokenInfo>(key);
|
||||
list.Add(token);
|
||||
await _redisManager.SetAsync(key, list, TimeSpan.FromDays(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Zxd.Domain.Config
|
||||
{
|
||||
internal class CacheKeys
|
||||
{
|
||||
public const string ProductModuleList = "product_module_list";
|
||||
|
||||
public const string ProductGroupList = "product_group_list";
|
||||
|
||||
public const string ProductTypeList = "product_type_list";
|
||||
|
||||
public const string ProductTeacherList = "product_teacher_list";
|
||||
|
||||
public const string ProductList = "product_list";
|
||||
|
||||
public const string StandardType = "standard_product_type";
|
||||
|
||||
public const string StandardWay = "standard_product_way";
|
||||
|
||||
public const string DeptmentList = "deptment_list_new";
|
||||
|
||||
public const string ModuleList = "module_list";
|
||||
|
||||
public const string ParameterList = "cache_parameter_list";
|
||||
|
||||
public const string TokenList = "cache_token_list";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
namespace Zxd.Domain.Config
|
||||
{
|
||||
public class ClientKey
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string AccessKey { get; set; }
|
||||
public string Vi { get; set; }
|
||||
public string NewAccessKey { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Zxd.Domain.Config
|
||||
{
|
||||
#region 注册,认证码表
|
||||
|
||||
public enum EnumInterfaceErrcode
|
||||
{
|
||||
调用成功 = 10000,
|
||||
调用成功且有数据 = 10001,//新增的code
|
||||
用户名已存在 = 10002,
|
||||
参数错误 = 10003,
|
||||
手机号码错误 = 10004,
|
||||
系统错误 = 10005,
|
||||
用户已经认证 = 10006,
|
||||
验证码过期 = 10007,
|
||||
该订单已开通不能撤销 = 10008,
|
||||
用户无手机号码 = 10009,
|
||||
手机号码已认证 = 10010,
|
||||
用户付款失败 = 10011,
|
||||
无手机号码不能重置密码 = 10012,
|
||||
订单已开通只充值 = 10013,
|
||||
订单不存在账户充值成功 = 10014,
|
||||
非法请求 = 10015,
|
||||
支付金额不足开通失败 = 10016,
|
||||
数据不存在 = 10017,
|
||||
类型已存在不能重复添加 = 10018,
|
||||
非认证用户 = 10019,
|
||||
该用户没有手机号码 = 10020,
|
||||
十五分钟已连续发送三次 = 10021,
|
||||
积分不够业务失败 = 10022,
|
||||
验证码错误 = 10023,
|
||||
已提交不同身份证开户信息请联系客服处理 = 10024,
|
||||
该资源已被他人认领 = 10025,
|
||||
资源无须覆盖 = 10026,
|
||||
该客户的身份证已存在不能重复提交 = 10027,
|
||||
此申请已经授权 = 10028,
|
||||
不存在此代理商 = 10029,
|
||||
不存在此用户 = 10030,
|
||||
平台信息出错请审核数据 = 10031,
|
||||
此号码的已被使用 = 10032,
|
||||
该渠道禁止申请 = 10033,
|
||||
已拥有相同或更高版本 = 10034,
|
||||
开通则撤销之前低版本 = 10035,
|
||||
正在处理 = 10036,
|
||||
交易商号已注册好视通 = 10037,
|
||||
好视通用户名不能重复注册 = 10038,
|
||||
好视通注册失败 = 10039,
|
||||
好视通授权失败 = 10040,
|
||||
不能重复提交 = 10041,
|
||||
无效产品大类 = 10042,
|
||||
无效产品小类 = 10043,
|
||||
订单已开通 = 10044,
|
||||
订单已取消 = 10045,
|
||||
支付步骤出错 = 10046,
|
||||
订单未开通 = 10047,
|
||||
订单不可取消 = 10048,
|
||||
该openID已存在绑定 = 10049,
|
||||
密码不正确 = 10050,
|
||||
该UP账号已存在绑定 = 10051,
|
||||
验证码不能重复使用 = 10052,
|
||||
该UP账号已被管理员禁止修改密码 = 10053,
|
||||
调用成功但有错误 = 10054,
|
||||
找不到订单 = 10055,
|
||||
此订单状态不能再开通 = 10056,
|
||||
文件路径不能为空 = 10057
|
||||
}
|
||||
|
||||
#endregion 注册,认证码表
|
||||
|
||||
#region 系统参数配置
|
||||
|
||||
public enum Parameter
|
||||
{
|
||||
资源, 转换, 导出资源, 是否开启加密,
|
||||
ORD_MemoStatistics_01, //工单统计
|
||||
ORD_MemoStatistics_ZhenGu, //诊股资源工单统计
|
||||
|
||||
Sys_Environment_DeptCode,//当前系统部门编码
|
||||
Sys_ExlceImport_PhoneRule,//手机号码生成规则
|
||||
Sys_ExcelImport_SkipOran,//是否跳过机构验证导入等于配置的机构数据
|
||||
Sys_IsShowFXH,//是否显示渤海信息
|
||||
Sys_RetrievePwd_Name,//找回密码短信配置 您好,密码找回短信配置:{0}是密码,{1}是帐号
|
||||
Is_ShowCustomerMobileArea,//是否显示号码地区
|
||||
Sys_HomeTab_Javascript,//系统home页面的主题框架脚本 主页面的js,Tab打开风格JS
|
||||
Sys_IsFreeze_Wdzm,//是否冻结我的桌面 默认是不冻结可以关闭的true=冻结,false=可以关闭
|
||||
Sys_IsMiniCustomerInfo,//显示简单详细资料
|
||||
ISVR_AD_CheckUserNameCompetence,
|
||||
ISVR_AD_upAgentCreateActiveOrder,
|
||||
ISVR_AD_upAgentOpenOrder,
|
||||
ISVR_AD_CancelActiveOrder,
|
||||
ISVR_AD_HstRegUser,
|
||||
ISVR_AD_HstDelUserName,
|
||||
ISVR_AD_HstRoomConfig,
|
||||
ISVR_AD_HstBatchAddUserRight,
|
||||
ISVR_AD_HstAddUserPower,
|
||||
ISVR_AD_TbHstRegUser,
|
||||
ISVR_AD_TbHstRight,
|
||||
ISVR_AD_TGHstRoomConfig,
|
||||
ISVR_AD_HstBlackConfig,
|
||||
|
||||
ISVR_IAD_localhostOpenOrder,
|
||||
ISVR_IAD_localhostSimpleOpenOrder,
|
||||
ISVR_IAD_localhostCanclOrder,
|
||||
ISVR_IAD_localhostHstBatchAddUserRight,
|
||||
ISVR_IAD_localhostHstRoomConfig,
|
||||
ISVR_IAD_localhostHstDelUserName,
|
||||
ISVR_IAD_localhostHstRegUser,
|
||||
ISVR_IAD_localhostHstAddUserPower,
|
||||
|
||||
HQ_RiaService_ActiveMaunl,
|
||||
|
||||
Sms_TencentResetPwdTid, //腾讯云重置密码模板ID
|
||||
Sms_TencentHgMsgTid, //腾讯云合规消息模板ID
|
||||
Sms_TencentOpenOrderTid,
|
||||
Sms_TencentRegisterTid,//腾讯云用户注册模板ID
|
||||
Sms_TencentOpenOrderDonateTid,
|
||||
Sms_TencentSign, //腾讯云短信签名
|
||||
Sms_TencentPayMsgTid, //腾讯云在线支付消息模板ID
|
||||
|
||||
CustomerCheckData,//质检抓取时间
|
||||
Res_EffectAnalysis_01, //资源效果分析
|
||||
ISVR_AD_UpdateManager,
|
||||
|
||||
Sys_Bussiness_Code, //营业部Code
|
||||
Sys_Environment_LogOn, //当前系统部门编码
|
||||
WeiXin_OrderCountShowColumn, //微信订单统计产品小类展示列
|
||||
WeiXin_WorkAccountInitCount, //客服工作微信号数量
|
||||
WeiXIn_SzzyOrderUnPayDayInterval, //上证综研未支付订单间隔天数
|
||||
UserCenter_RiaService_AddOrderOpen,//创建订单
|
||||
UserCenter_RiaService_OpenOrder,//开通订单
|
||||
UserCenter_RiaService_AddOrderOpenFree,//免费订单
|
||||
UserCenter_RiaService_refund,//退款接口
|
||||
UserCenter_RiaService_closeFreeOrder,//关闭活动免费订单
|
||||
UserCenter_RiaService_ResetPwd,//重置密码接口
|
||||
UserCenter_RiaService_ResetMobile,//重置手机号接口
|
||||
UserCenter_RiaService_UnBindQW,//软件和企业微信关系解绑
|
||||
UserCenter_RiaService_ContractSign,//签订合同
|
||||
UserCenter_RiaService_Settlement,//和解协议
|
||||
UserCenter_RiaService_CancelComplaint,//撤销投诉协议
|
||||
UserCenter_RiaService_SignPdf,//合同pdf地址
|
||||
UserCenter_RiaService_OrderGet,//订单信息获取
|
||||
UserCenter_RiaService_ForceMerge,//调用Node用户中心进行客户合并
|
||||
UserCenter_RiaService_UnBind,//调用Node用户中心进行客户解绑
|
||||
UserCenter_RiaService_Risk,//获取风险评测信息
|
||||
UserCenter_RiaService_Flag,//获取是否适合信息
|
||||
|
||||
//UserCenter_RiaService_Riske,//风控URL
|
||||
Sys_ProjectType, //项目类型,1:证券之星广州 2:南京鼎迈
|
||||
|
||||
Sys_OrderOpenCountByTimeType, //订单开通统计的时间周期 otime:开通时间 arrivaltime:到账时间
|
||||
Sys_ShowMobileStartDate, //为空:就都不显示手机 日期:从该日期之后的资源,显示电话
|
||||
Sys_UserComBoxAllShow, //员工分组下拉菜单显示所有员工 0:不显示离职 1:显示全部
|
||||
WeiXin_GroupLeaderPasueReceiveRes, //主管是否暂停接收资源 1:暂停 0:接收
|
||||
WeiXin_TotalPauseReceiveRes, //微信总资源客户数较多暂停接收资源 1:暂停 0:接收
|
||||
Sys_CanExportAllocate, //是否能导出资源
|
||||
Sys_OrderClientIdKey, //订单加密客户端ID的键名
|
||||
Sys_CanShowResMobile, //是否在资源页面显示手机号
|
||||
WeiXin_TotalPauseUserNum, //总资源暂停客服人数
|
||||
WeiXin_OrderUserNameRequired, //订单用户微信用户名必填项
|
||||
WeiXin_IllegalKewords, //合规关键词词配置
|
||||
MonthCommission, //月份提成
|
||||
WeiXin_CrossDBSzzyOrder, //跨库订单数据
|
||||
Sys_QHData, //期货业务
|
||||
WeiXin_OfflineResTypeIds, //线下资源类型id
|
||||
Sys_IsShowMobileOfContent, //是否显示内容中的手机号
|
||||
WeiXin_IsShowOpenOrderTip, //是否显示我的微信客户开通订单提示
|
||||
Sys_SaleDeptId_Three, //三部的SaleDeptId
|
||||
Sys_SaleDeptId_OneAndTwo, //一二部的SaleDeptId
|
||||
Sys_rpt_json_config,//业绩预测配置
|
||||
UserCenter_RiaService_RefundContract, //退款合同
|
||||
WeiXin_IllegalKewordsDeptConfig,//合规关键词推送deptcode
|
||||
UserCenter_UserEnter,//用户中心注册接口
|
||||
UserCenter_HandelLabel,//用户中心写标签接口
|
||||
HG_Level,//合规类型等级
|
||||
AI_CallTaskConfig //回访机器人配置
|
||||
}
|
||||
|
||||
public enum ParameterGroup
|
||||
{
|
||||
ORD_MemoStatistics,
|
||||
FavoritesCustType,
|
||||
SystemConfig,//系统配置
|
||||
ExternalInterfaceAddress,
|
||||
SMS_CONFIG,
|
||||
OrderPayType
|
||||
}
|
||||
|
||||
#endregion 系统参数配置
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
namespace Zxd.Domain.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统参数
|
||||
/// </summary>
|
||||
public class SystemConfig
|
||||
{
|
||||
public List<App> Apps { get; set; }
|
||||
|
||||
public string Appid { get; set; }
|
||||
|
||||
public string AppSecret { get; set; }
|
||||
|
||||
public string SsoUrl { get; set; }
|
||||
public string ZxdCroeUrl { get; set; }
|
||||
|
||||
public string SsoOrganizationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 销售线索URL
|
||||
/// </summary>
|
||||
public string? SalesLeadUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CRM号码加密key(clientKey)
|
||||
/// </summary>
|
||||
public string? CRMClientKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推送部门编码
|
||||
/// </summary>
|
||||
|
||||
public string? DataClientCode { get; set; }
|
||||
|
||||
public string WeworkSendUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 深海捷固定坐席
|
||||
/// </summary>
|
||||
public string? Shj { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端密钥
|
||||
/// </summary>
|
||||
public List<ClientKey>? ClientKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public string DataSyncApiUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 短信注册信息
|
||||
/// </summary>
|
||||
public string SoftRegisterMsg { get; set; }
|
||||
|
||||
public string SsoTokenUrl { get; set; }
|
||||
|
||||
public string CrmBaseUrl { get; set; }
|
||||
|
||||
public string AddStandardProduct { get; set; }
|
||||
|
||||
public string AddStandardPackage { get; set; }
|
||||
|
||||
public string AddVirtualProduct { get; set; }
|
||||
|
||||
public string AddVirtualPackage { get; set; }
|
||||
public string ActiveProduct { get; set; }
|
||||
public string ActivePackage { get; set; }
|
||||
public string UserGroupList { get; set; }
|
||||
public string GroupUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据中台
|
||||
/// </summary>
|
||||
public string BdMarkting { get; set; }
|
||||
|
||||
public string KfUserCount { get; set; }
|
||||
|
||||
|
||||
public string UsercenterUrl { get; set; }
|
||||
|
||||
public string GetAddStandardProduct()
|
||||
{
|
||||
return $"{CrmBaseUrl}{AddStandardProduct}";
|
||||
}
|
||||
|
||||
public string GetActiveProduct()
|
||||
{
|
||||
return $"{CrmBaseUrl}{ActiveProduct}";
|
||||
}
|
||||
|
||||
public string GetUserGroupList()
|
||||
{
|
||||
return $"{GroupUrl}{UserGroupList}";
|
||||
}
|
||||
|
||||
public string GetKFSourceCount()
|
||||
{
|
||||
return $"{BdMarkting}{KfUserCount}";
|
||||
}
|
||||
|
||||
public string GetActivePackage()
|
||||
{
|
||||
return $"{CrmBaseUrl}{ActivePackage}";
|
||||
}
|
||||
|
||||
public string GetAddStandardPackage()
|
||||
{
|
||||
return $"{CrmBaseUrl}{AddStandardPackage}";
|
||||
}
|
||||
|
||||
public string GetAddVirtualProduct()
|
||||
{
|
||||
return $"{CrmBaseUrl}{AddVirtualProduct}";
|
||||
}
|
||||
|
||||
public string GetAddVirtualPackage()
|
||||
{
|
||||
return $"{CrmBaseUrl}{AddVirtualPackage}";
|
||||
}
|
||||
|
||||
public string CrmCoreUrl { get; set; }
|
||||
|
||||
public string GetSsoOrganizationUrl()
|
||||
{
|
||||
return $"{SsoUrl}{SsoOrganizationUrl}";
|
||||
}
|
||||
public string GetZxdCroeUrl() {
|
||||
return $"{ZxdCroeUrl}/Api/Deptment/Depts";
|
||||
}
|
||||
public string GetSsoTokenUrl()
|
||||
{
|
||||
return $"{SsoUrl}{SsoTokenUrl}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 资源系统ip地址
|
||||
/// </summary>
|
||||
public string CmsUrl { get; set; }
|
||||
|
||||
public string[] ClearCacheUrls { get; set; }
|
||||
|
||||
public string GetAccessKey(string id)
|
||||
{
|
||||
return ClientKey?.First(x => x.Id == id).AccessKey ?? "";
|
||||
}
|
||||
|
||||
public string GetUserList()
|
||||
{
|
||||
return $"{UsercenterUrl}usercenter/cgi/getUserList";
|
||||
}
|
||||
}
|
||||
|
||||
public class App
|
||||
{
|
||||
public List<decimal> Deptids { get; set; }
|
||||
|
||||
public string AppName { get; set; }
|
||||
|
||||
public string Appid { get; set; }
|
||||
|
||||
public string AppSecret { get; set; }
|
||||
|
||||
public string CrmUrl { get; set; }
|
||||
}
|
||||
|
||||
public class PayCallbackConfig
|
||||
{
|
||||
public string AppId { get; set; }
|
||||
|
||||
public string Secret { get; set; }
|
||||
|
||||
public string PushUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
using MySqlConnector;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Core.Domain.Dto.Wework;
|
||||
using Zxd.EntityFramework;
|
||||
using static Zxd.Domain.Impl.ICustomerDomain;
|
||||
|
||||
namespace Zxd.Domain
|
||||
{
|
||||
public class CustomerDomain : ICustomerDomain
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly ICacheDomain _cacheDomain;
|
||||
private readonly IBaseRepository<ZxdDbContext> _repository;
|
||||
private readonly IBaseRepository<DncmsDbContext> _dncmsbaseRepository;
|
||||
|
||||
public CustomerDomain(IConfiguration configuration,
|
||||
IHttpClient httpClient,
|
||||
ICacheDomain cacheDomain,
|
||||
IBaseRepository<DncmsDbContext> dncmsbaseRepository,
|
||||
IBaseRepository<ZxdDbContext> repository)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_httpClient = httpClient;
|
||||
_cacheDomain = cacheDomain;
|
||||
_repository = repository;
|
||||
_dncmsbaseRepository = dncmsbaseRepository;
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加标签数据
|
||||
/// </summary>
|
||||
/// <param name="resid"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ApiException"></exception>
|
||||
public async Task<bool> AddTag(string resid, string tag,int ceid)
|
||||
{
|
||||
tag = tag.Trim();
|
||||
resid = resid.Trim();
|
||||
if (string.IsNullOrEmpty(tag))
|
||||
throw new ApiException("参数错误");
|
||||
if (string.IsNullOrEmpty(resid))
|
||||
throw new ApiException("参数错误");
|
||||
var info = await _repository.GetRepository<Res_Tag>().Query().Where(m => m.resid == resid && m.tag == tag && m.isdelete==0).FirstOrDefaultAsync();
|
||||
if (info != null)
|
||||
throw new ApiException("已存在此标签");
|
||||
|
||||
await _repository.GetRepository<Res_Tag>().InsertAsync(new Res_Tag()
|
||||
{
|
||||
resid = resid,
|
||||
tag = tag,
|
||||
ceid = ceid
|
||||
});
|
||||
return true;
|
||||
}
|
||||
public async Task<bool> DelTag(int id,int deleteeid)
|
||||
{
|
||||
var info = await _repository.GetRepository<Res_Tag>().Query().Where(m => m.id == id).FirstOrDefaultAsync();
|
||||
if (info == null)
|
||||
throw new ApiException("找不到这个标签");
|
||||
info.deleteeid = deleteeid;
|
||||
info.isdelete = 1;
|
||||
await _repository.GetRepository<Res_Tag>().UpdateAsync(info);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取标签列表
|
||||
/// </summary>
|
||||
/// <param name="resid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<Res_Tag>> GetTag(string resid)
|
||||
{
|
||||
resid = resid.Trim();
|
||||
return await _repository.GetRepository<Res_Tag>().Query().Where(m => m.resid == resid && m.isdelete==0).ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<List<string>> GetUsernames(string? resid)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resid)) return new List<string>();
|
||||
var usernames = await _repository.GetRepository<RES_CUSTOMERUSER>().Query()
|
||||
.Where(x => x.RESID == resid)
|
||||
.Select(x => x.USERNAME)
|
||||
.ToListAsync();
|
||||
return usernames;
|
||||
}
|
||||
|
||||
public async Task<List<userRet>> GetUsernamesByOrderid(string orderidListIn)
|
||||
{
|
||||
if (orderidListIn == null) return new List<userRet> { };
|
||||
var orderidList = orderidListIn.Split(";").ToList();
|
||||
if (orderidList.Count == 0) return new List<userRet>();
|
||||
|
||||
var usernamesList = await _repository.GetRepository<WX_SZZYORDER>().Query()
|
||||
.Where(x => orderidList.Contains(x.ORDERID.ToString()))
|
||||
.Select(x => new userRet { orderid = x.ORDERID.ToString(), softwarename = x.SOFTUSERNAME })
|
||||
.ToListAsync();
|
||||
|
||||
var res = new List<userRet>();
|
||||
|
||||
orderidList.ForEach(orderid =>
|
||||
{
|
||||
var findOder = usernamesList.Find(u => u.orderid == orderid);
|
||||
if (findOder != null)
|
||||
{
|
||||
res.Add(findOder);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<CreateCustomerRes> CreateCustomer(string MOBILE, string ResId, string CustomerFrom)
|
||||
{
|
||||
CreateCustomerRes res = new CreateCustomerRes();
|
||||
var customer = await _repository.GetRepository<RES_CUSTOMER>().Query().FirstOrDefaultAsync(x => x.RESID == ResId);
|
||||
if (customer == null)
|
||||
{
|
||||
//开始创建
|
||||
var mobile = MOBILE.Replace("+86", "");
|
||||
if (mobile.StartsWith("01") && mobile.Length == 12)
|
||||
{
|
||||
mobile = mobile.Substring(1);
|
||||
}
|
||||
var systemConfig = _configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
var key = systemConfig.GetAccessKey(systemConfig.CRMClientKey);
|
||||
var CNumber = SecurityHelper.EncyptData(mobile, key);
|
||||
var param = new List<MySqlParameter>
|
||||
{
|
||||
new MySqlParameter() { ParameterName = "p_CNumber", DbType = DbType.String, Value =CNumber},
|
||||
new MySqlParameter() { ParameterName = "p_ResId", DbType = DbType.String, Value = ResId },
|
||||
new MySqlParameter() { ParameterName = "p_CustomerFrom", DbType = DbType.String, Value = CustomerFrom }
|
||||
};
|
||||
param.Add(!string.IsNullOrEmpty(mobile) ? new MySqlParameter() { ParameterName = "p_ECNumber", DbType = DbType.String, Value = NumberFormat(mobile) } : new MySqlParameter() { ParameterName = "p_ECNumber", DbType = DbType.String, Value = DBNull.Value });
|
||||
|
||||
var i = await _repository.ExecuteSqlCommandNonQueryAsync(System.Data.CommandType.StoredProcedure, "res_ResgisterCustomer", param.ToArray());
|
||||
res.code = CCenum.成功;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.code = CCenum.客户存在;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<List<WwUserFollowOutDto>> GetFollow(List<WwUserFollowInDto> queryList)
|
||||
{
|
||||
var extuseridList = queryList.Select(s => s.extuserid).ToList();
|
||||
// 依据appid userid extuserid 找出表中对应的数据,并根据subscribe判断是否关注
|
||||
var temp = await _dncmsbaseRepository.GetRepository<WeworkExternalUser>().Query()
|
||||
.Where(w => extuseridList.Contains(w.Externaluserid))
|
||||
.Select(x => new WwUserFollowOutDto()
|
||||
{
|
||||
appid = x.Appid,
|
||||
userid = x.Userid,
|
||||
extuserid = x.Externaluserid,
|
||||
isFollow = x.subscribe
|
||||
})
|
||||
.ToListAsync();
|
||||
List<WwUserFollowOutDto> res = new List<WwUserFollowOutDto>();
|
||||
queryList.ForEach(q =>
|
||||
{
|
||||
var t = temp.Find(f => f.appid == q.appid && f.userid == q.userid && f.extuserid == q.extuserid);
|
||||
if (t != null)
|
||||
{
|
||||
res.Add(new WwUserFollowOutDto
|
||||
{
|
||||
appid = t.appid,
|
||||
userid = t.userid,
|
||||
extuserid = t.extuserid,
|
||||
isFollow = t.isFollow
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async Task<List<SalesLeadDto>> GetSalesLeadList(string? resId)
|
||||
{
|
||||
var systemConfig = _configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
var result = new List<SalesLeadDto>();
|
||||
var url = systemConfig.SalesLeadUrl;
|
||||
var key = systemConfig.GetAccessKey(systemConfig.CRMClientKey);
|
||||
var reslist = await _repository.GetRepository<RES_RESOURCEMOBILE>().Query()
|
||||
.Where(x => x.RESID == resId).ToListAsync();
|
||||
var mobiles = new List<string>();
|
||||
foreach (var res in reslist)
|
||||
{
|
||||
if (res == null) continue;
|
||||
mobiles.Add(SecurityHelper.DecyptData(res.MOBILE, key));
|
||||
}
|
||||
|
||||
if (mobiles == null || !mobiles.Any())
|
||||
{
|
||||
throw new ApiException("暂无销售线索!", -1);
|
||||
}
|
||||
|
||||
var parameter = await _cacheDomain.GetValueParameter("ISVR_Saleclus_Get");
|
||||
if (string.IsNullOrEmpty(parameter)) return result;
|
||||
var response = await _httpClient.PostAsync<SaleClusResult<SaleRelation>>(parameter, new { mobiles });
|
||||
if (response.Ret != 0 || response.List == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
foreach (var saleRelation in response.List)
|
||||
{
|
||||
if (result.Any(x => x.Appuserid == saleRelation.Appuserid && x.Appid == saleRelation.Appid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var name = saleRelation.Appuserid.Length > 10 ?
|
||||
saleRelation.Appuserid[..10] + "*****" :
|
||||
saleRelation.Appuserid;
|
||||
|
||||
result.Add(new SalesLeadDto
|
||||
{
|
||||
Name = name,
|
||||
Appid = saleRelation.Appid,
|
||||
Appuserid = saleRelation.Appuserid,
|
||||
Url = $"{url}?appid={saleRelation.Appid}&appuserid={saleRelation.Appuserid}"
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string NumberFormat(string number)
|
||||
{
|
||||
if (string.IsNullOrEmpty(number) || number.Length <= 6)
|
||||
{
|
||||
return number;
|
||||
}
|
||||
return number.Substring(0, 3) + new string('*', number.Length - 6) + number.Substring(number.Length - 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="resId"></param>
|
||||
/// <param name="DeptCode"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ExUserModel>> GetWorkWXUserSelectAsync(string? resId, string? DeptCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resId))
|
||||
{
|
||||
return new List<ExUserModel>();
|
||||
}
|
||||
var customerQuery = _repository.GetRepository<RES_CUSTOMER>().Query();
|
||||
var allCustomer = (from a in customerQuery
|
||||
join b in customerQuery on a.CUSTOMERID equals b.CUSTOMERID
|
||||
where b.RESID == resId
|
||||
select a.RESID).ToList();
|
||||
var data = await _repository.GetRepository<WW_EXTUSER_RESID>().Query()
|
||||
.Where(x => allCustomer.Contains(x.Resid) || x.Resid == resId)
|
||||
.ToListAsync();
|
||||
var result = new List<ExUserModel>();
|
||||
var unameList = data.Select(n => n.Userid).Distinct().ToList();
|
||||
foreach (var name in unameList)
|
||||
{
|
||||
ExUserModel newModel = new ExUserModel
|
||||
{
|
||||
Userid = name,
|
||||
};
|
||||
var names = data.Where(n => n.Userid == name).OrderByDescending(n => n.Ctime).ToList();
|
||||
var seftItem = names.FirstOrDefault(n => n.Deptcode == DeptCode);
|
||||
if (seftItem != null)
|
||||
{
|
||||
newModel.Ctime = seftItem.Ctime;
|
||||
newModel.Deptcode = seftItem.Deptcode;
|
||||
newModel.Resid = seftItem.Resid;
|
||||
}
|
||||
else
|
||||
{
|
||||
newModel.Ctime = names.FirstOrDefault().Ctime;
|
||||
newModel.Deptcode = names.FirstOrDefault().Deptcode;
|
||||
newModel.Resid = names.FirstOrDefault().Resid;
|
||||
}
|
||||
result.Add(newModel);
|
||||
}
|
||||
return result.OrderByDescending(n => n.Ctime).ToList();
|
||||
}
|
||||
|
||||
public async Task<List<string>> ExtUserBandGetAsync(string? resId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resId))
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
var customerQuery = _repository.GetRepository<RES_CUSTOMER>().Query();
|
||||
var allCustomer = (from a in customerQuery
|
||||
join b in customerQuery on a.CUSTOMERID equals b.CUSTOMERID
|
||||
where b.RESID == resId
|
||||
select a.RESID).ToList();
|
||||
var userList = await _repository.GetRepository<WW_EXTUSER_RESID>().Query().Where(n => allCustomer.Contains(n.Resid) || n.Resid == resId).ToListAsync();
|
||||
List<string> result = new List<string>();
|
||||
foreach (var item in userList)
|
||||
{
|
||||
result.Add(item.Userid);
|
||||
}
|
||||
result = result.Distinct().ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetResidByExtuser(List<string> extUser)
|
||||
{
|
||||
if (!extUser.Any()) return new List<string>();
|
||||
var resids = await _repository.GetRepository<WW_EXTUSER_RESID>().Query()
|
||||
.Where(x => extUser.Contains(x.Userid))
|
||||
.Select(x => x.Userid + ":" + x.Resid)
|
||||
.ToListAsync();
|
||||
return resids;
|
||||
}
|
||||
|
||||
public async Task<IList<string>> GetPhoneByUnionid(string unionid)
|
||||
{
|
||||
IList<string> mobiles = new List<string>();
|
||||
var unionlist = await _repository.GetRepository<Soft_Userinfo_Sub>().Query()
|
||||
.Where(x => x.unionid == unionid || x.appuserid == unionid).ToListAsync();
|
||||
if (unionlist.Any())
|
||||
{
|
||||
mobiles = await _repository.GetRepository<Soft_Userinfo_Sub>().Query()
|
||||
.Where(x => x.cid == unionlist.First().cid && !string.IsNullOrEmpty(x.mobile)).Select(m => m.mobile).Distinct().ToListAsync();
|
||||
}
|
||||
return mobiles;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExtUserItem
|
||||
{
|
||||
public string userid { get; set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue