初始化
This commit is contained in:
commit
80e2934b51
|
|
@ -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,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public enum LifeCycle
|
||||
{
|
||||
Scoped = 0x1,
|
||||
Singleton = 0x2,
|
||||
Transient = 0x3,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Version>1.1.9</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface IScopedDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface ISingletonDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface ITransientDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiException : DGException
|
||||
{
|
||||
public ApiException(string? message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ApiException(string? message, int code)
|
||||
: base(message)
|
||||
{
|
||||
Data.Add("code", code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class DGException : Exception
|
||||
{
|
||||
public DGException(string? message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DGException(string? message, int code)
|
||||
: base(message)
|
||||
{
|
||||
Data.Add("code", code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class HttpExtensions
|
||||
{
|
||||
public static string GetCorrelationId(this HttpContext httpContext)
|
||||
{
|
||||
httpContext.Request.Headers.TryGetValue("Cko-Correlation-Id", out StringValues correlationId);
|
||||
return correlationId.FirstOrDefault() ?? httpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class JsonOptionsExtensions : JsonConverter<DateTime>
|
||||
{
|
||||
private readonly string Format;
|
||||
public JsonOptionsExtensions(string format = "yyyy-MM-dd HH:mm:ss")
|
||||
{
|
||||
Format = format;
|
||||
}
|
||||
public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(date.ToString(Format));
|
||||
}
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
// 获取时间类型的字符串
|
||||
var dt = reader.GetString();
|
||||
if (!string.IsNullOrEmpty(dt))
|
||||
{
|
||||
//将日期与时间之间的"T"替换为一个空格,将结尾的"Z"去掉,否则会报错
|
||||
dt = dt.Replace("T", " ").Replace("Z", "");
|
||||
//取到秒,毫秒内容也要去掉,经过测试,不去掉会报错
|
||||
if (dt.Length > 19)
|
||||
{
|
||||
dt = dt.Substring(0, 19);
|
||||
}
|
||||
return DateTime.ParseExact(dt, Format, null);
|
||||
}
|
||||
return DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class LinqMethodExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用自定linq扩展执行排序,查询,分页功能 item1: 未分页结果,item2:分页后的结果
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="coditionEntity"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> UseCoditionFind<T>(this IQueryable<T> source, bool condition, Action<IQueryable<T>> action)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
action(source);
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class PredicateExtensionses
|
||||
{
|
||||
public static Expression<Func<T, bool>> True<T>() { return f => true; }
|
||||
|
||||
public static Expression<Func<T, bool>> False<T>() { return f => false; }
|
||||
|
||||
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>> expRight)
|
||||
{
|
||||
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
|
||||
var parameterReplacer = new ParameterReplacer(candidateExpr);
|
||||
|
||||
var left = parameterReplacer.Replace(expLeft.Body);
|
||||
var right = parameterReplacer.Replace(expRight.Body);
|
||||
var body = Expression.And(left, right);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>> expRight)
|
||||
{
|
||||
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
|
||||
var parameterReplacer = new ParameterReplacer(candidateExpr);
|
||||
|
||||
var left = parameterReplacer.Replace(expLeft.Body);
|
||||
var right = parameterReplacer.Replace(expRight.Body);
|
||||
var body = Expression.OrElse(left, right);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
|
||||
}
|
||||
/// <summary>
|
||||
/// And ((a or b )and (x or d))关系,但是and后面里面的关系是Or的关系,如 a.resid='' and ((a.channel>=1 and a.channel<10) or (a.channel>=50 and a.channel<60))
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="expLeft"></param>
|
||||
/// <param name="expRight"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> AndListOr<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>>[] predicates)
|
||||
{
|
||||
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
|
||||
var parameterReplacer = new ParameterReplacer(candidateExpr);
|
||||
var left = parameterReplacer.Replace(expLeft.Body);
|
||||
Expression<Func<T, bool>> lambda = predicates[0];
|
||||
for (int i = 1; i < predicates.Length; i++)
|
||||
{
|
||||
lambda = lambda.Or(predicates[i]);
|
||||
}
|
||||
var right = parameterReplacer.Replace(lambda.Body);
|
||||
var body = Expression.And(left, right);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传入条件之间为OR查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="predicates"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> WhereOR<T>(this IQueryable<T> source, params Expression<Func<T, bool>>[] predicates)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (predicates == null) throw new ArgumentNullException("predicates");
|
||||
if (predicates.Length == 0) return source.Where(x => true);
|
||||
if (predicates.Length == 1) return source.Where(predicates[0]);
|
||||
|
||||
var param = Expression.Parameter(typeof(T), "x");
|
||||
Expression body = Expression.Invoke(predicates[0], param);
|
||||
for (int i = 1; i < predicates.Length; i++)
|
||||
{
|
||||
body = Expression.OrElse(body, Expression.Invoke(predicates[i], param));
|
||||
}
|
||||
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
|
||||
return source.Where(lambda);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ParameterReplacer : ExpressionVisitor
|
||||
{
|
||||
public ParameterReplacer(ParameterExpression paramExpr)
|
||||
{
|
||||
this.ParameterExpression = paramExpr;
|
||||
}
|
||||
|
||||
public ParameterExpression ParameterExpression { get; private set; }
|
||||
|
||||
public Expression Replace(Expression expr)
|
||||
{
|
||||
return this.Visit(expr);
|
||||
}
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return this.ParameterExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class SystemKeyExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// If extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="condition"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public static T If<T>(this T t, bool condition, Action<T> action) where T : class
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
action(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public static T If<T>(this T t, Predicate<T> predicate, Action<T> action) where T : class
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if (predicate(t))
|
||||
{
|
||||
action(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="condition"></param>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
public static T If<T>(this T t, bool condition, Func<T, T> func) where T : class => condition ? func(t) : t;
|
||||
|
||||
/// <summary>
|
||||
/// If extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="func"></param>
|
||||
/// <returns></returns>
|
||||
public static T If<T>(this T t, Predicate<T> predicate, Func<T, T> func) where T : class => predicate(t) ? func(t) : t;
|
||||
|
||||
/// <summary>
|
||||
/// If and else extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="condition"></param>
|
||||
/// <param name="ifAction"></param>
|
||||
/// <param name="elseAction"></param>
|
||||
/// <returns></returns>
|
||||
public static T IfAndElse<T>(this T t, bool condition, Action<T> ifAction, Action<T> elseAction) where T : class
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
ifAction(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
elseAction(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If and else extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="ifAction"></param>
|
||||
/// <param name="elseAction"></param>
|
||||
/// <returns></returns>
|
||||
public static T IfAndElse<T>(this T t, Predicate<T> predicate, Action<T> ifAction, Action<T> elseAction) where T : class
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if (predicate(t))
|
||||
{
|
||||
ifAction(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
elseAction(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If and else extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="condition"></param>
|
||||
/// <param name="ifFunc"></param>
|
||||
/// <param name="elseFunc"></param>
|
||||
/// <returns></returns>
|
||||
public static T IfAndElse<T>(this T t, bool condition, Func<T, T> ifFunc, Func<T, T> elseFunc) where T : class => condition ? ifFunc(t) : elseFunc(t);
|
||||
|
||||
/// <summary>
|
||||
/// If and else extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="ifFunc"></param>
|
||||
/// <param name="elseFunc"></param>
|
||||
/// <returns></returns>
|
||||
public static T IfAndElse<T>(this T t, Predicate<T> predicate, Func<T, T> ifFunc, Func<T, T> elseFunc) where T : class => predicate(t) ? ifFunc(t) : elseFunc(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,759 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class HttpClient : IHttpClient
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly ILogger<HttpClient> _logger;
|
||||
private static LogLevel _logLevel = LogLevel.Debug;
|
||||
|
||||
public HttpClient(IHttpClientFactory httpClientFactory,
|
||||
ILogger<HttpClient> logger)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private static JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
public void ChangeLogLevel(LogLevel logLevel)
|
||||
{
|
||||
_logLevel = logLevel;
|
||||
}
|
||||
|
||||
private void Log(string message)
|
||||
{
|
||||
_logger.Log(_logLevel, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post Security
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="clientid"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> PostSecurityAsync<T>(string url, object data, string clientid, string accessKey, string iv)
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
var param = JsonSerializer.Serialize(data, options);
|
||||
var bodyJson = EncryptByAES(param, accessKey, iv);
|
||||
var sign = SignData(bodyJson, accessKey);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("clientid", clientid);
|
||||
client.DefaultRequestHeaders.Add("sign", sign);
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync($"{url}", httpData);
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static string SignData(string ciphertext, string accessKey)
|
||||
{
|
||||
Encoding utf = new UTF8Encoding();
|
||||
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
|
||||
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
|
||||
return Convert.ToBase64String(hashValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="clientid"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> PostSecurityAsync<T>(string url, object param, object data, string clientid, string accessKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var bodyJson = JsonSerializer.Serialize(data, options);
|
||||
var content = EncyptData(paramStr, accessKey);
|
||||
var sign = SignData(content, accessKey);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
|
||||
url = $"{url}?content={HttpUtility.UrlEncode(content)}&sign={HttpUtility.UrlEncode(sign, Encoding.UTF8)}&clientid={clientid}";
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync(url, httpData);
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post Security
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="clientid"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <param name="iv"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> PostSecurityAsync(string url, object data, string clientid, string accessKey, string iv)
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
var param = JsonSerializer.Serialize(data, options);
|
||||
var bodyJson = EncryptByAES(param, accessKey, iv);
|
||||
var sign = SignData(bodyJson, accessKey);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("clientid", clientid);
|
||||
client.DefaultRequestHeaders.Add("sign", sign);
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync($"{url}", httpData);
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="clientid"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> PostSecurityAsync(string url, object param, object data, string clientid, string accessKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var bodyJson = JsonSerializer.Serialize(data, options);
|
||||
var content = EncyptData(paramStr, accessKey);
|
||||
var sign = SignData(content, accessKey);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
|
||||
url = $"{url}?content={HttpUtility.UrlEncode(content)}&sign={HttpUtility.UrlEncode(sign, Encoding.UTF8)}&clientid={clientid}";
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync(url, httpData);
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T> UploadFileAsync<T>(string url, string fileName, string fullName, Dictionary<string, string>? headers = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = await File.ReadAllBytesAsync(fullName);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
ByteArrayContent fileContent = new ByteArrayContent(buffer);
|
||||
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
|
||||
MultipartFormDataContent content = new MultipartFormDataContent
|
||||
{
|
||||
fileContent
|
||||
};
|
||||
Log($"UploadFile 文件上传,请求Url:{url}");
|
||||
var httpResponse = await client.PostAsync(url, content);
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "UploadFile 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> UploadFileAsync(string url, string fileName, string fullName, Dictionary<string, string>? headers = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = await File.ReadAllBytesAsync(fullName);
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
ByteArrayContent fileContent = new ByteArrayContent(buffer);
|
||||
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
|
||||
MultipartFormDataContent content = new MultipartFormDataContent
|
||||
{
|
||||
fileContent
|
||||
};
|
||||
Log($"UploadFile 文件上传,请求Url:{url}");
|
||||
var httpResponse = await client.PostAsync(url, content);
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "UploadFile 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region 正常请求
|
||||
|
||||
/// <summary>
|
||||
/// Post
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <param name="mediaType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> PostAsync2<T>(string url, string data, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
|
||||
{
|
||||
// _logger.LogInformation("卧槽,进来了。1111");
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
//var options = new JsonSerializerOptions
|
||||
//{
|
||||
// DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
// PropertyNameCaseInsensitive = true
|
||||
//};
|
||||
// _logger.LogInformation("卧槽,进来了。");
|
||||
var bodyJson = data;
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
|
||||
_logger.LogInformation($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync($"{url}", httpData);
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
_logger.LogInformation($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <param name="mediaType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> PostAsync<T>(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
//var options = new JsonSerializerOptions
|
||||
//{
|
||||
// DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
// PropertyNameCaseInsensitive = true
|
||||
//};
|
||||
Log("卧槽,进来了。");
|
||||
var bodyJson = data != null ? Newtonsoft.Json.JsonConvert.SerializeObject(data) : "";
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync($"{url}", httpData);
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> PostAsync(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
var bodyJson = data != null ? JsonSerializer.Serialize(data, options) : "";
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
|
||||
Log($"POST 请求Url:{url}, Body:{bodyJson}");
|
||||
var httpResponse = await client.PostAsync($"{url}", httpData);
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "POST 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> GetAsync<T>(string url, string appId = "", string appSecret = "", int timeout = 10000)
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var query = uri.Query;
|
||||
var param = new Dictionary<string, object>();
|
||||
if (query != null)
|
||||
{
|
||||
foreach (var item in query.Split('&'))
|
||||
{
|
||||
var sp = item.Split("=");
|
||||
if (sp.Count() > 1)
|
||||
{
|
||||
param.Add(sp[0].Replace("?", ""), sp[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
var timeStamp = GetTimeStamp();
|
||||
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
|
||||
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
Log($"GET 请求Url:{url}");
|
||||
var httpResponse = await client.GetAsync($"{url}");
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "GET 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<T> GetAsync<T>(string url, Dictionary<string, object> param, string appId = "", string appSecret = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
var urlParam = string.Join("&", param.Select(m => m.Key + "=" + m.Value));
|
||||
if (url.IndexOf('?') > -1)
|
||||
{
|
||||
url += urlParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
url = url + "?" + urlParam;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
Log($"GET 请求Url:{url}");
|
||||
var httpResponse = await client.GetAsync($"{url}");
|
||||
var stream = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{stream}");
|
||||
var response = JsonSerializer.Deserialize<T>(stream, options);
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "GET 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetAsync(string url, string appId = "", string appSecret = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
var query = uri.Query;
|
||||
var param = new Dictionary<string, object>();
|
||||
if (query != null)
|
||||
{
|
||||
foreach (var item in query.Split('&'))
|
||||
{
|
||||
var sp = item.Split("=");
|
||||
if (sp.Count() > 1)
|
||||
{
|
||||
param.Add(sp[0].Replace("?", ""), sp[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
var timeStamp = GetTimeStamp();
|
||||
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
|
||||
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
Log($"GET 请求Url:{url}");
|
||||
var httpResponse = await client.GetAsync($"{url}");
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "GET 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="appSecret"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetAsync(string url, Dictionary<string, object> param, string appId = "", string appSecret = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
var urlParam = string.Join("&", param.Select(m => m.Key + "=" + m.Value));
|
||||
if (url.IndexOf('?') > -1)
|
||||
{
|
||||
url += urlParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
url = url + "?" + urlParam;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId))
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("appid", appId);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
var timeStamp = GetTimeStamp();
|
||||
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
|
||||
var paramStr = JsonSerializer.Serialize(param, options);
|
||||
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
|
||||
var authorization = $"{appId}:{sign}";
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
|
||||
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
|
||||
}
|
||||
Log($"GET 请求Url:{url}");
|
||||
var httpResponse = await client.GetAsync($"{url}");
|
||||
var response = await httpResponse.Content.ReadAsStringAsync();
|
||||
Log($"请求结果:{response}");
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "GET 方法请求错误!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成签名
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="bodyJson"></param>
|
||||
/// <param name="secret"></param>
|
||||
/// <param name="timestamps"></param>
|
||||
/// <returns></returns>
|
||||
private static string CreateSign(string appId, string bodyJson, string secret, string timestamps)
|
||||
{
|
||||
var enStrList = new string[] { appId, bodyJson, secret, timestamps };
|
||||
Array.Sort(enStrList, string.CompareOrdinal);
|
||||
var enStr = string.Join("", enStrList);
|
||||
var md = GetMd5Hash(enStr);
|
||||
return md;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算 md5
|
||||
/// </summary>
|
||||
/// <param name="enCode"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetMd5Hash(string enCode)
|
||||
{
|
||||
string res = "";
|
||||
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(enCode);
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] bytes = md5.ComputeHash(data);
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
res += bytes[i].ToString("x2");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetTimeStamp()
|
||||
{
|
||||
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return Convert.ToInt64(ts.TotalSeconds).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密
|
||||
/// </summary>
|
||||
/// <param name="ciphertext"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <returns></returns>
|
||||
private static string EncyptData(string ciphertext, string accessKey)
|
||||
{
|
||||
SymmetricAlgorithm des = DES.Create();
|
||||
|
||||
Encoding utf = new UTF8Encoding();
|
||||
byte[] key = utf.GetBytes(accessKey);
|
||||
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
|
||||
ICryptoTransform encryptor = des.CreateEncryptor(key, iv);
|
||||
byte[] data = utf.GetBytes(ciphertext);
|
||||
byte[] encData = encryptor.TransformFinalBlock(data, 0, data.Length);
|
||||
return Convert.ToBase64String(encData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密
|
||||
/// </summary>
|
||||
/// <param name="cryptograph"></param>
|
||||
/// <param name="accessKey"></param>
|
||||
/// <returns></returns>
|
||||
private static string DecyptData(string cryptograph, string accessKey)
|
||||
{
|
||||
SymmetricAlgorithm des = DES.Create();
|
||||
|
||||
Encoding utf = new UTF8Encoding();
|
||||
byte[] key = utf.GetBytes(accessKey);
|
||||
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
|
||||
ICryptoTransform decryptor = des.CreateDecryptor(key, iv);
|
||||
byte[] encData = Convert.FromBase64String(cryptograph);
|
||||
byte[] data = decryptor.TransformFinalBlock(encData, 0, encData.Length);
|
||||
return utf.GetString(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AES加密算法
|
||||
/// </summary>
|
||||
/// <param name="input">明文字符串</param>
|
||||
/// <returns>字符串</returns>
|
||||
private static string EncryptByAES(string input, string key, string iv)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
Aes aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.FeedbackSize = 128;
|
||||
aes.Key = Encoding.UTF8.GetBytes(key);
|
||||
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||
using MemoryStream msEncrypt = new();
|
||||
using CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write);
|
||||
using (StreamWriter swEncrypt = new(csEncrypt))
|
||||
{
|
||||
swEncrypt.Write(input);
|
||||
}
|
||||
byte[] bytes = msEncrypt.ToArray();
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
#endregion 正常请求
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface IHttpClient
|
||||
{
|
||||
void ChangeLogLevel(LogLevel logLevel);
|
||||
|
||||
Task<T> PostSecurityAsync<T>(string url, object data, string clientid, string accessKey, string iv);
|
||||
|
||||
Task<T> PostSecurityAsync<T>(string url, object param, object data, string clientid, string accessKey);
|
||||
|
||||
Task<string> PostSecurityAsync(string url, object data, string clientid, string accessKey, string iv);
|
||||
|
||||
Task<string> PostSecurityAsync(string url, object param, object data, string clientid, string accessKey);
|
||||
|
||||
Task<T> PostAsync<T>(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
|
||||
Task<T> PostAsync2<T>(string url, string data, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
|
||||
|
||||
Task<string> PostAsync(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
|
||||
|
||||
Task<T> GetAsync<T>(string url, string appId = "", string appSecret = "", int timeout = 10000);
|
||||
|
||||
Task<T> GetAsync<T>(string url, Dictionary<string, object> param, string appId = "", string appSecret = "");
|
||||
|
||||
Task<string> GetAsync(string url, string appId = "", string appSecret = "");
|
||||
|
||||
Task<string> GetAsync(string url, Dictionary<string, object> param, string appId = "", string appSecret = "");
|
||||
|
||||
Task<T> UploadFileAsync<T>(string url, string fileName, string fullName, Dictionary<string, string>? headers = null);
|
||||
|
||||
Task<string> UploadFileAsync(string url, string fileName, string fullName, Dictionary<string, string>? headers = null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class IMvcBuilderApiResultExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 启用API标准返回值模式
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public static IMvcBuilder AddApiResult(this IMvcBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
return builder.AddMvcOptions(options => {
|
||||
options.Filters.Add(typeof(ApiExceptionFilterAttribute));
|
||||
options.Filters.Add(typeof(ApiResultFilterAttribute));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用API签名模式
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public static IMvcBuilder AddApiSignature(this IMvcBuilder builder)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
return builder.AddMvcOptions(options => {
|
||||
options.Filters.Add(typeof(ApiSecurityAsyncFilter));
|
||||
options.Filters.Add(typeof(ApiSignatureAsyncFilterAttribute));
|
||||
options.Filters.Add(typeof(ApiTimeSecurityAsyncFilter));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface IMapper
|
||||
{
|
||||
TTarget Map<TSource, TTarget>(TSource source);
|
||||
|
||||
List<TTarget> Map<TSource, TTarget>(List<TSource> source);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
internal class Mapper
|
||||
{
|
||||
public static readonly Mapper Instance = new Mapper();
|
||||
|
||||
private Mapper()
|
||||
{
|
||||
}
|
||||
|
||||
public TTarget Map<TSource, TTarget>(TSource source) => CacheModel<TSource, TTarget>.Invoke(source);
|
||||
|
||||
public List<TTarget> Map<TSource, TTarget>(List<TSource> sources) => sources.AsParallel().Select(CacheModel<TSource, TTarget>.Invoke).ToList();
|
||||
|
||||
internal class CacheModel<TSource, TTarget>
|
||||
{
|
||||
private static readonly Func<TSource, TTarget> Func;
|
||||
|
||||
static CacheModel()
|
||||
{
|
||||
var parameterExpression = Expression.Parameter(typeof(TSource), "x");
|
||||
var sourcePropNames = typeof(TSource).GetProperties()
|
||||
.Where(x => !x.IsDefined(typeof(NotMapAttribute), true))
|
||||
.Select(x => x.Name)
|
||||
.ToArray();
|
||||
|
||||
var memberBindings = typeof(TTarget).GetProperties()
|
||||
.Where(x => x.CanWrite && sourcePropNames.Any(y => y.ToUpper() == x.Name.ToUpper()))
|
||||
.Select(x => Expression.Bind(typeof(TTarget).GetProperty(x.Name),
|
||||
Expression.Property(parameterExpression,
|
||||
typeof(TSource).GetProperty(sourcePropNames.FirstOrDefault(y => y.ToUpper() == x.Name.ToUpper())))));
|
||||
|
||||
Func = Expression.Lambda<Func<TSource, TTarget>>(Expression.MemberInit(Expression.New(typeof(TTarget)), memberBindings), parameterExpression).Compile();
|
||||
}
|
||||
|
||||
public static TTarget Invoke(TSource source) => Func(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class MapperExtendsions
|
||||
{
|
||||
/// <summary>
|
||||
/// 映射到
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TTarget"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static TTarget Map<TSource, TTarget>(this TSource source) => Mapper.Instance.Map<TSource, TTarget>(source);
|
||||
|
||||
/// <summary>
|
||||
/// 映射到
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TTarget"></typeparam>
|
||||
/// <param name="sources"></param>
|
||||
/// <returns></returns>
|
||||
public static List<TTarget> Map<TSource, TTarget>(this List<TSource> sources) => Mapper.Instance.Map<TSource, TTarget>(sources);
|
||||
|
||||
/// <summary>
|
||||
/// 复制到
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TTarget"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>因为重名了,所以对方法取别名,同 MapTo</remarks>
|
||||
public static TTarget Replicate<TSource, TTarget>(this TSource source) => source.Map<TSource, TTarget>();
|
||||
|
||||
/// <summary>
|
||||
/// 复制到
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TTarget"></typeparam>
|
||||
/// <param name="sources"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>因为重名了,所以对方法取别名,同 MapTo</remarks>
|
||||
public static List<TTarget> Replicate<TSource, TTarget>(this List<TSource> sources) => sources.Map<TSource, TTarget>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class MapperManager : IMapper
|
||||
{
|
||||
public TTarget Map<TSource, TTarget>(TSource source) => source.Map<TSource, TTarget>();
|
||||
|
||||
public List<TTarget> Map<TSource, TTarget>(List<TSource> source) => source.Map<TSource, TTarget>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class NotMapAttribute : Attribute
|
||||
{
|
||||
public NotMapAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示处理API异常的筛选器。
|
||||
/// </summary>
|
||||
public class ApiExceptionFilterAttribute : Attribute, IExceptionFilter
|
||||
{
|
||||
private readonly ILogger<ApiExceptionFilterAttribute> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiExceptionFilterAttribute" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger</param>
|
||||
public ApiExceptionFilterAttribute(ILogger<ApiExceptionFilterAttribute> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [exception].
|
||||
/// </summary>
|
||||
/// <param name="context">The context.</param>
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
|
||||
_logger.LogError(0, context.Exception, $"ip={context.HttpContext.Connection.RemoteIpAddress}, path={context.HttpContext.Request.Path}, error={JsonSerializer.Serialize(context.Exception.Message)}");
|
||||
|
||||
if (context.Exception.Data != null && context.Exception.Data["code"] != null)
|
||||
{
|
||||
var code = (int)context.Exception.Data["code"];
|
||||
context.Result = new ObjectResult(ApiResult.Failed(context.Exception.Message, code));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed(context.Exception.Message));
|
||||
}
|
||||
|
||||
|
||||
context.ExceptionHandled = true;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiResourceFilter : Attribute, IResourceFilter
|
||||
{
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
if (!context.ModelState.IsValid)
|
||||
{
|
||||
var errors = string.Empty;
|
||||
foreach (var key in context.ModelState.Keys)
|
||||
{
|
||||
var modelState = context.ModelState[key];
|
||||
foreach (var error in modelState.Errors)
|
||||
{
|
||||
errors += string.IsNullOrEmpty(errors) ? error.ErrorMessage
|
||||
: $",{error.ErrorMessage}";
|
||||
}
|
||||
}
|
||||
context.Result = new ObjectResult(ApiResult.Failed(errors));
|
||||
}
|
||||
// 执行完后的操作
|
||||
}
|
||||
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
// 执行中的过滤器管道
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiResult : IApiResult
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an empty <see cref="IApiResult"/>.
|
||||
/// </summary>
|
||||
public static readonly IApiResult Empty = new ApiResult
|
||||
{
|
||||
Code = 0
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status code.
|
||||
/// </summary>
|
||||
/// <value>The status code.</value>
|
||||
[JsonPropertyName("code")]
|
||||
public int Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
[JsonPropertyName("message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="IApiResult{TData}"/> by the specified result.
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">The type of the result.</typeparam>
|
||||
/// <param name="data">The result.</param>
|
||||
/// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
|
||||
public static IApiResult<TData> Succeed<TData>(TData data) => new ApiResult<TData>
|
||||
{
|
||||
Code = 0,
|
||||
Data = data
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="IApiResult"/> by the specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <param name="code">The status code</param>
|
||||
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
|
||||
public static IApiResult Failed(string message, int? code = null) => new ApiResult
|
||||
{
|
||||
Code = code ?? -1,
|
||||
Message = message
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified error message.
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">The type of the result.</typeparam>
|
||||
/// <param name="data">The error result.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <param name="code">The status code.</param>
|
||||
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
|
||||
public static IApiResult<TData> Failed<TData>(TData data, string message, int? code = null) => new ApiResult<TData>
|
||||
{
|
||||
Code = code ?? -1,
|
||||
Message = message,
|
||||
Data = data
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="IApiResult"/> by the specified status code and message.
|
||||
/// </summary>
|
||||
/// <param name="code">The status code.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
|
||||
public static IApiResult From(int code, string message = null) => new ApiResult
|
||||
{
|
||||
Code = code,
|
||||
Message = message
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified result.
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">The type of the result.</typeparam>
|
||||
/// <param name="data">The result.</param>
|
||||
/// <param name="code">The status code.</param>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
|
||||
public static IApiResult<TData> From<TData>(TData data, int code, string message) => new ApiResult<TData>
|
||||
{
|
||||
Code = code,
|
||||
Message = message,
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiResultFilterAttribute : ResultFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
if (context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiResultFilterForbidAttribute)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (context.Result)
|
||||
{
|
||||
case ObjectResult result:
|
||||
{
|
||||
// this include OkObjectResult, NotFoundObjectResult, BadRequestObjectResult, CreatedResult (lose Location)
|
||||
var objectResult = result;
|
||||
if (objectResult.Value == null)
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Empty);
|
||||
}
|
||||
else if (objectResult.Value is ValidationProblemDetails validationProblemDetails)
|
||||
{
|
||||
var errors = string.Empty;
|
||||
foreach(var error in validationProblemDetails.Errors)
|
||||
{
|
||||
errors += string.IsNullOrEmpty(errors) ? error.Value.First()
|
||||
: $",{error.Value.First()}";
|
||||
}
|
||||
context.Result = new ObjectResult(ApiResult.Failed(errors));
|
||||
}
|
||||
else if (!(objectResult.Value is IApiResult))
|
||||
{
|
||||
if (objectResult.DeclaredType != null)
|
||||
{
|
||||
var apiResult = Activator.CreateInstance(
|
||||
typeof(ApiResult<>).MakeGenericType(objectResult.DeclaredType), objectResult.Value, objectResult.StatusCode);
|
||||
context.Result = new ObjectResult(apiResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Result = objectResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EmptyResult _:
|
||||
// return void or Task
|
||||
context.Result = new ObjectResult(ApiResult.Empty);
|
||||
break;
|
||||
|
||||
case ContentResult result:
|
||||
context.Result = new ObjectResult(ApiResult.Succeed(result.Content));
|
||||
break;
|
||||
|
||||
case StatusCodeResult result:
|
||||
// this include OKResult, NoContentResult, UnauthorizedResult, NotFoundResult, BadRequestResult
|
||||
context.Result = new ObjectResult(ApiResult.From(result.StatusCode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiResultFilterForbidAttribute : ResultFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiResult<TData> : ApiResult, IApiResult<TData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiResult{TResult}"/> class.
|
||||
/// </summary>
|
||||
public ApiResult() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiResult{TResult}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The result.</param>
|
||||
/// <param name="code">The status code.</param>
|
||||
public ApiResult(TData data, int? code)
|
||||
{
|
||||
Code = code ?? 0;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the result.
|
||||
/// </summary>
|
||||
/// <value>The result.</value>
|
||||
[JsonPropertyName("data")]
|
||||
public TData Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface IApiResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the status code.
|
||||
/// </summary>
|
||||
/// <value>The status code.</value>
|
||||
int Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message.
|
||||
/// </summary>
|
||||
/// <value>The message.</value>
|
||||
string Message { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public interface IApiResult<TData> : IApiResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the result.
|
||||
/// </summary>
|
||||
/// <value>The result.</value>
|
||||
TData Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class PageResult<TData> where TData : class
|
||||
{
|
||||
public PageResult(int pageIndex, int pageSize, int total, IList<TData>? data)
|
||||
{
|
||||
PageIndex = pageIndex;
|
||||
PageSize = pageSize;
|
||||
Total = total;
|
||||
Data = data;
|
||||
TotalCount = total == 0 ? 0 : (Total / PageSize) + (Total % PageSize) > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 页数
|
||||
/// </summary>
|
||||
public int PageIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分页大小
|
||||
/// </summary>
|
||||
public int PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总数量
|
||||
/// </summary>
|
||||
public int Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分页总数量
|
||||
/// </summary>
|
||||
public int TotalCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据
|
||||
/// </summary>
|
||||
public IList<TData>? Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 页数
|
||||
/// </summary>
|
||||
public int PageIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分页大小
|
||||
/// </summary>
|
||||
public int PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序字段,支持逗号隔开
|
||||
/// </summary>
|
||||
public string? Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 升降序,Asc/Desc
|
||||
/// </summary>
|
||||
public string? Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否导出
|
||||
/// </summary>
|
||||
public bool? Export { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class SelectItem
|
||||
{
|
||||
public SelectItem(object key, object value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public object Key { get; set; }
|
||||
|
||||
public object? Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiSecurityAsyncFilter : IAsyncAuthorizationFilter
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<ApiSecurityAsyncFilter> _logger;
|
||||
|
||||
public ApiSecurityAsyncFilter(IConfiguration configuration,
|
||||
ILogger<ApiSecurityAsyncFilter> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiSecurityAttribute)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var request = context.HttpContext.Request;
|
||||
if (!request.Method.ToLower().Equals("post"))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("ApiSecurityAsyncFilter只支持POST方法!", 10004));
|
||||
return;
|
||||
}
|
||||
var clientKeys = _configuration.GetSection("ClientKey").Get<List<ClientKey>>();
|
||||
if (clientKeys == null || !clientKeys.Any())
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("ClientKey没有配置!", 10003));
|
||||
return;
|
||||
}
|
||||
var clientid = request.Headers["clientid"].ToString();
|
||||
var sign = request.Headers["sign"].ToString();
|
||||
if (string.IsNullOrEmpty(clientid) || string.IsNullOrEmpty(sign))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("请求头clientid或sign不能为空!", 10003));
|
||||
return;
|
||||
}
|
||||
var client = clientKeys.First(x => x.Id == clientid);
|
||||
request.EnableBuffering();
|
||||
var stream = request.Body;
|
||||
var buffer = new byte[request.ContentLength.Value];
|
||||
await stream.ReadAsync(buffer);
|
||||
var bodyJson = Encoding.UTF8.GetString(buffer);
|
||||
stream.Position = 0;
|
||||
var signData = SignData(bodyJson, client.NewAccessKey);
|
||||
if (!signData.Equals(sign))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var contextAes = DecryptByAES(client, bodyJson);
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
var dataContext = Encoding.UTF8.GetBytes(contextAes);
|
||||
var requestBodyStream = new MemoryStream();//创建一个流
|
||||
requestBodyStream.Seek(0, SeekOrigin.Begin);//设置从0开始读取
|
||||
requestBodyStream.Write(dataContext, 0, dataContext.Length);//把修改写入流中
|
||||
request.Body = requestBodyStream;//把修改后的内容赋值给请求body
|
||||
request.Body.Seek(0, SeekOrigin.Begin);
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogInformation(ex, "报错解密");
|
||||
}
|
||||
}
|
||||
|
||||
private static string SignData(string ciphertext, string accessKey)
|
||||
{
|
||||
Encoding utf = new UTF8Encoding();
|
||||
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
|
||||
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
|
||||
return Convert.ToBase64String(hashValue);
|
||||
}
|
||||
|
||||
private static string DecryptByAES(ClientKey client, string bodyJson)
|
||||
{
|
||||
return DecryptByAES(bodyJson, client.NewAccessKey, client.Vi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AES解密
|
||||
/// </summary>
|
||||
/// <param name="input">密文字节数组</param>
|
||||
/// <returns>返回解密后的字符串</returns>
|
||||
private static string DecryptByAES(string input, string key, string iv)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
var buffer = Convert.FromBase64String(input);
|
||||
using Aes aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.FeedbackSize = 128;
|
||||
aes.Key = Encoding.UTF8.GetBytes(key);
|
||||
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||
using MemoryStream msEncrypt = new(buffer);
|
||||
using CryptoStream csEncrypt = new(msEncrypt, decryptor, CryptoStreamMode.Read);
|
||||
using StreamReader srEncrypt = new(csEncrypt);
|
||||
return srEncrypt.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 安全API
|
||||
/// </summary>
|
||||
public class ApiSecurityAttribute : Attribute, IFilterMetadata
|
||||
{
|
||||
public ApiSecurityAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
internal class ClientKey
|
||||
{
|
||||
public ClientKey(string id, string name, string accessKey, string vi, string newAccessKey)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
AccessKey = accessKey;
|
||||
Vi = vi;
|
||||
NewAccessKey = newAccessKey;
|
||||
}
|
||||
|
||||
public 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,65 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddMapper(this IServiceCollection services)
|
||||
=> services.AddSingleton<IMapper, MapperManager>();
|
||||
|
||||
/// <summary>
|
||||
/// Add auto ioc services
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="baseType"></param>
|
||||
/// <param name="lifeCycle"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddAutoIoc(this IServiceCollection services, Type baseType, LifeCycle lifeCycle)
|
||||
{
|
||||
if (!baseType.IsInterface)
|
||||
{
|
||||
throw new TypeLoadException("The status code must be an enumerated type");
|
||||
}
|
||||
|
||||
var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
|
||||
var referencedAssemblies = System.IO.Directory.GetFiles(path, "*.dll").Select(Assembly.LoadFrom).ToArray();
|
||||
var types = referencedAssemblies
|
||||
.SelectMany(a => a.DefinedTypes)
|
||||
.Select(type => type.AsType())
|
||||
.Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToArray();
|
||||
var implementTypes = types.Where(x => x.IsClass).ToArray();
|
||||
var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
|
||||
foreach (var implementType in implementTypes)
|
||||
{
|
||||
var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
|
||||
if (interfaceType != null)
|
||||
switch (lifeCycle)
|
||||
{
|
||||
case LifeCycle.Singleton:
|
||||
services.AddSingleton(interfaceType, implementType);
|
||||
break;
|
||||
|
||||
case LifeCycle.Transient:
|
||||
services.AddTransient(interfaceType, implementType);
|
||||
break;
|
||||
|
||||
case LifeCycle.Scoped:
|
||||
services.AddScoped(interfaceType, implementType);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(lifeCycle), lifeCycle, null);
|
||||
}
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
public static IServiceCollection AddDGHttpClient(this IServiceCollection services)
|
||||
{
|
||||
return services.AddHttpClient()
|
||||
.AddTransient<IHttpClient, HttpClient>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiSignatureAsyncFilterAttribute : IAsyncAuthorizationFilter
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public ApiSignatureAsyncFilterAttribute(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.Filters.Any(filterMetadata =>
|
||||
filterMetadata.GetType() == typeof(ApiSignatureFilterForbidAttribute) ||
|
||||
filterMetadata.GetType() == typeof(ApiSecurityAttribute) ||
|
||||
filterMetadata.GetType() == typeof(ApiTimeSecurityAttribute)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var request = context.HttpContext.Request;
|
||||
var appId = _configuration.GetSection("SignConfig:AppId").Value;
|
||||
var secret = _configuration.GetSection("SignConfig:Secret").Value;
|
||||
if (string.IsNullOrWhiteSpace(appId) || string.IsNullOrWhiteSpace(secret))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("appId或secret没有配置!", 10003));
|
||||
return;
|
||||
}
|
||||
|
||||
var authorization = request.Headers["Authorization"].ToString();
|
||||
var timestamps = request.Headers["timestamps"].ToString();
|
||||
if (string.IsNullOrEmpty(authorization) || string.IsNullOrEmpty(timestamps))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("请求头authorization或timestamps不能为空!", 10003));
|
||||
return;
|
||||
}
|
||||
string? bodyJson;
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))
|
||||
{
|
||||
var query = request.Query;
|
||||
var parames = new Dictionary<string, object>();
|
||||
foreach (var item in query)
|
||||
{
|
||||
parames.Add(item.Key, item.Value.ToString());
|
||||
}
|
||||
parames = parames.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
|
||||
bodyJson = JsonSerializer.Serialize(parames, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.EnableBuffering();
|
||||
var stream = request.Body;
|
||||
var buffer = new byte[request.ContentLength.Value];
|
||||
await stream.ReadAsync(buffer);
|
||||
bodyJson = Encoding.UTF8.GetString(buffer);
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
var md = CreateSign(appId, bodyJson, secret, timestamps);
|
||||
if (authorization != $"{appId}:{md}")
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
|
||||
}
|
||||
else
|
||||
{
|
||||
var nowTime = GetTimeStamp();
|
||||
var diff = Convert.ToInt32(nowTime) - Convert.ToInt32(timestamps);
|
||||
if (diff > 1800)
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("签名已过期!", 10002));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成签名
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="bodyJson"></param>
|
||||
/// <param name="secret"></param>
|
||||
/// <param name="timestamps"></param>
|
||||
/// <returns></returns>
|
||||
private static string CreateSign(string appId, string bodyJson, string secret, string timestamps)
|
||||
{
|
||||
var enStrList = new string[] { appId, bodyJson, secret, timestamps };
|
||||
Array.Sort(enStrList, string.CompareOrdinal);
|
||||
var enStr = string.Join("", enStrList);
|
||||
var md = GetMd5Hash(enStr);
|
||||
return md;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算 md5
|
||||
/// </summary>
|
||||
/// <param name="enCode"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetMd5Hash(string enCode)
|
||||
{
|
||||
string res = "";
|
||||
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(enCode);
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] bytes = md5.ComputeHash(data);
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
res += bytes[i].ToString("x2");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetTimeStamp()
|
||||
{
|
||||
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return Convert.ToInt64(ts.TotalSeconds).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// API屏蔽签名
|
||||
/// </summary>
|
||||
public class ApiSignatureFilterForbidAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class ApiTimeSecurityAsyncFilter : IAsyncAuthorizationFilter
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<ApiTimeSecurityAsyncFilter> _logger;
|
||||
|
||||
public ApiTimeSecurityAsyncFilter(IConfiguration configuration,
|
||||
ILogger<ApiTimeSecurityAsyncFilter> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiTimeSecurityAttribute)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var request = context.HttpContext.Request;
|
||||
var clientKeys = _configuration.GetSection("ClientKey").Get<List<ClientKey>>();
|
||||
if (clientKeys == null || !clientKeys.Any())
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("ClientKey没有配置!", 10003));
|
||||
return;
|
||||
}
|
||||
var clientid = request.Headers["clientid"].ToString();
|
||||
var sign = request.Headers["sign"].ToString();
|
||||
var timestamps = request.Headers["timestamps"].ToString();
|
||||
if (string.IsNullOrEmpty(clientid) || string.IsNullOrEmpty(sign) || string.IsNullOrEmpty(timestamps))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("请求头clientid或sign或timestamps不能为空!", 10003));
|
||||
return;
|
||||
}
|
||||
var client = clientKeys.First(x => x.Id == clientid);
|
||||
|
||||
string? bodyJson;
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))
|
||||
{
|
||||
var query = request.Query;
|
||||
var parames = new Dictionary<string, object>();
|
||||
foreach (var item in query)
|
||||
{
|
||||
parames.Add(item.Key, item.Value.ToString());
|
||||
}
|
||||
bodyJson = JsonSerializer.Serialize(parames, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.EnableBuffering();
|
||||
var stream = request.Body;
|
||||
var buffer = new byte[request.ContentLength.Value];
|
||||
await stream.ReadAsync(buffer);
|
||||
bodyJson = Encoding.UTF8.GetString(buffer);
|
||||
stream.Position = 0;
|
||||
|
||||
var content = JsonSerializer.Deserialize<ContentDto>(bodyJson);
|
||||
bodyJson = content.Content;
|
||||
}
|
||||
var signData = SignData(bodyJson, client.NewAccessKey);
|
||||
if (!signData.Equals(sign))
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var nowTime = GetTimeStamp();
|
||||
var diff = Convert.ToInt32(nowTime) - Convert.ToInt32(timestamps);
|
||||
if (diff > 1800)
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Failed("签名已过期!", 10002));
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var contextAes = DecryptByAES(client, bodyJson);
|
||||
|
||||
var dataContext = Encoding.UTF8.GetBytes(contextAes);
|
||||
var requestBodyStream = new MemoryStream();//创建一个流
|
||||
requestBodyStream.Seek(0, SeekOrigin.Begin);//设置从0开始读取
|
||||
requestBodyStream.Write(dataContext, 0, dataContext.Length);//把修改写入流中
|
||||
request.Body = requestBodyStream;//把修改后的内容赋值给请求body
|
||||
request.Body.Seek(0, SeekOrigin.Begin);
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogInformation(ex, "报错解密");
|
||||
}
|
||||
}
|
||||
|
||||
private static string SignData(string ciphertext, string accessKey)
|
||||
{
|
||||
Encoding utf = new UTF8Encoding();
|
||||
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
|
||||
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
|
||||
return Convert.ToBase64String(hashValue);
|
||||
}
|
||||
|
||||
private static string DecryptByAES(ClientKey client, string bodyJson)
|
||||
{
|
||||
return DecryptByAES(bodyJson, client.NewAccessKey, client.Vi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AES解密
|
||||
/// </summary>
|
||||
/// <param name="input">密文字节数组</param>
|
||||
/// <returns>返回解密后的字符串</returns>
|
||||
private static string DecryptByAES(string input, string key, string iv)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
var buffer = Convert.FromBase64String(input);
|
||||
using Aes aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.FeedbackSize = 128;
|
||||
aes.Key = Encoding.UTF8.GetBytes(key);
|
||||
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
|
||||
using MemoryStream msEncrypt = new(buffer);
|
||||
using CryptoStream csEncrypt = new(msEncrypt, decryptor, CryptoStreamMode.Read);
|
||||
using StreamReader srEncrypt = new(csEncrypt);
|
||||
return srEncrypt.ReadToEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetTimeStamp()
|
||||
{
|
||||
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||
return Convert.ToInt64(ts.TotalSeconds).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class ContentDto
|
||||
{
|
||||
public string Content { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 安全API
|
||||
/// </summary>
|
||||
public class ApiTimeSecurityAttribute : Attribute, IFilterMetadata
|
||||
{
|
||||
public ApiTimeSecurityAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class DecimalValidationAttribute : ValidationAttribute
|
||||
{
|
||||
public int? Length { get; }
|
||||
private bool LengthError { get; set; }
|
||||
|
||||
public DecimalValidationAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public DecimalValidationAttribute(int? length)
|
||||
{
|
||||
Length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsValid 为 false 时,提示得 error 信息
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public override string FormatErrorMessage(string name)
|
||||
{
|
||||
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
|
||||
return $"{name}必须输入数字{lengthMessage},请重新输入!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前字段得结果
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool IsValid(object? value)
|
||||
{
|
||||
if (value == null) return true;
|
||||
if (decimal.TryParse(Convert.ToString(value), out decimal num))
|
||||
{
|
||||
if (Length != null && num.ToString().Length > Length)
|
||||
{
|
||||
LengthError = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class IntValidationAttribute : ValidationAttribute
|
||||
{
|
||||
public int? Length { get; }
|
||||
private bool LengthError { get; set; }
|
||||
|
||||
public IntValidationAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public IntValidationAttribute(int? length)
|
||||
{
|
||||
Length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsValid 为 false 时,提示得 error 信息
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public override string FormatErrorMessage(string name)
|
||||
{
|
||||
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
|
||||
return $"{name}必须输入数字{lengthMessage},请重新输入!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前字段得结果
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool IsValid(object? value)
|
||||
{
|
||||
if (value == null) return true;
|
||||
if (int.TryParse(Convert.ToString(value), out int num))
|
||||
{
|
||||
if (Length != null && num.ToString().Length > Length)
|
||||
{
|
||||
LengthError = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DG.Core
|
||||
{
|
||||
public class LongValidationAttribute : ValidationAttribute
|
||||
{
|
||||
public int? Length { get; }
|
||||
private bool LengthError { get; set; }
|
||||
|
||||
public LongValidationAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public LongValidationAttribute(int? length)
|
||||
{
|
||||
Length = length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IsValid 为 false 时,提示得 error 信息
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public override string FormatErrorMessage(string name)
|
||||
{
|
||||
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
|
||||
return $"{name}必须输入数字{lengthMessage},请重新输入!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前字段得结果
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public override bool IsValid(object? value)
|
||||
{
|
||||
if (value == null) return true;
|
||||
if (long.TryParse(Convert.ToString(value), out long num))
|
||||
{
|
||||
if (Length != null && num.ToString().Length > Length)
|
||||
{
|
||||
LengthError = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
using DG.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
|
||||
namespace Hg.Complaint.Domain
|
||||
{
|
||||
internal class CacheDomain : ICacheDomain
|
||||
{
|
||||
private readonly IRedisManager _redisManager;
|
||||
private readonly IBaseRepository<DncmsbaseDbContext> _dncmsbaseRepository;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly SystemConfig _systemConfig;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public CacheDomain(IRedisManager redisManager,
|
||||
IBaseRepository<DncmsbaseDbContext> dncmsbaseRepository,
|
||||
IHttpClient httpClient,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_redisManager = redisManager;
|
||||
_dncmsbaseRepository = dncmsbaseRepository;
|
||||
_httpClient = httpClient;
|
||||
_systemConfig = configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
}
|
||||
|
||||
public async Task<List<DeptmentDto>> GetDeptments()
|
||||
{
|
||||
var key = $"{CacheKeys.ZxdParameterList}";
|
||||
if (!await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
var response = await _httpClient.GetAsync<ApiResult<List<DeptmentDto>>>($"{_systemConfig.ZxdCoreUrl}/Api/Deptment/Depts");
|
||||
if (response.Code == 0)
|
||||
{
|
||||
await _redisManager.SetAsync(key, response.Data, TimeSpan.FromDays(1));
|
||||
return response.Data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _redisManager.GetListAsync<DeptmentDto>(key);
|
||||
}
|
||||
return new List<DeptmentDto>();
|
||||
}
|
||||
|
||||
public async Task<List<DeptmentGroupDto>> GetDeptmentGroups()
|
||||
{
|
||||
var key = CacheKeys.DeptmentGroup;
|
||||
if (!await _redisManager.ExistsAsync(key))
|
||||
{
|
||||
var query = _dncmsbaseRepository.GetRepository<DeptmentGroup>().Query()
|
||||
.Include(x => x.Deptments)
|
||||
.Select(x => new DeptmentGroupDto
|
||||
{
|
||||
Id = x.Id,
|
||||
CrmAppid = x.CrmAppid,
|
||||
GroupName = x.GroupName,
|
||||
Deptments = x.Deptments,
|
||||
});
|
||||
var data = await query.ToListAsync();
|
||||
data.Add(new DeptmentGroupDto
|
||||
{
|
||||
Id = 0,
|
||||
CrmAppid = "",
|
||||
GroupName = "总部",
|
||||
Deptments = new List<Deptment> {
|
||||
new Deptment {
|
||||
Id = 0,
|
||||
Title = "总部"
|
||||
}
|
||||
}
|
||||
});
|
||||
await _redisManager.SetAsync(key, data, TimeSpan.FromDays(1));
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = await _redisManager.GetListAsync<DeptmentGroupDto>(key);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<DeptmentGroupDto?> GetDeptmentGroupByDeptid(int? deptid)
|
||||
{
|
||||
if (deptid == null) return null;
|
||||
|
||||
var list = await GetDeptmentGroups();
|
||||
return list.FirstOrDefault(x => x.Deptments.Any(y => y.Id == deptid)) ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain
|
||||
{
|
||||
/// <summary>
|
||||
/// 投诉处理类
|
||||
/// </summary>
|
||||
public class ComplaintEventSingleton
|
||||
{
|
||||
private List<ComplaintEventDto> _complaintEvents = new();
|
||||
|
||||
/// <summary>
|
||||
/// 投诉处理类
|
||||
/// </summary>
|
||||
public ComplaintEventSingleton()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务队列
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ComplaintEventDto> GetComplaintEvents() => _complaintEvents;
|
||||
|
||||
/// <summary>
|
||||
/// 移除任务队列
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public List<ComplaintEventDto> RemoveComplaint(int id)
|
||||
{
|
||||
if (_complaintEvents.Any(x => x.Id.Equals(id)))
|
||||
{
|
||||
_complaintEvents.Remove(_complaintEvents.First(x => x.Id == id));
|
||||
}
|
||||
return _complaintEvents;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量移除任务队列
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
public List<ComplaintEventDto> RemoveComplaints(List<int> ids)
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
RemoveComplaint(id);
|
||||
}
|
||||
return _complaintEvents;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取到期的未处理投诉
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ComplaintEventDto> GetDueComplaint()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var dueHours = DefaultHelper.DueHours;
|
||||
var data = new List<ComplaintEventDto>();
|
||||
foreach (var complaintEvent in _complaintEvents)
|
||||
{
|
||||
if (complaintEvent.Ctime.HasValue && (now - complaintEvent.Ctime.Value).TotalHours >= dueHours)
|
||||
{
|
||||
data.Add(complaintEvent);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加需要计时的投诉处理
|
||||
/// </summary>
|
||||
/// <param name="complaintEvent"></param>
|
||||
public void AddComplaintEvent(ComplaintEventDto complaintEvent)
|
||||
{
|
||||
RemoveComplaint(complaintEvent.Id);
|
||||
_complaintEvents.Add(complaintEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化需要计时的投诉处理
|
||||
/// </summary>
|
||||
/// <param name="complaintEvents"></param>
|
||||
/// <returns></returns>
|
||||
public List<ComplaintEventDto> InitComplaintEvents(List<ComplaintEventDto> complaintEvents)
|
||||
{
|
||||
_complaintEvents = complaintEvents;
|
||||
return _complaintEvents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
namespace Hg.Complaint.Domain.Config
|
||||
{
|
||||
internal class CacheKeys
|
||||
{
|
||||
public const string SsoOrganization = "cache:sso_organization";
|
||||
|
||||
public const string CompanyVirtual = "cache:company_virtual";
|
||||
|
||||
public const string ParameterList = "cache:parameter_list";
|
||||
|
||||
public const string CsvrCallrecordCount = "csvr_callrecord_count";
|
||||
|
||||
public const string ProductList = "cache:szzyproduct_list";
|
||||
|
||||
public const string SubProductList = "cache:szzysubproduct_list";
|
||||
|
||||
public const string ComplaintMessageEnqueue = "enqueue:complaint_message";
|
||||
|
||||
public const string DeptmentGroup = "cache:deptment_group";
|
||||
|
||||
public const string ZxdParameterList = "cache:zxd_parameter_list";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Config
|
||||
{
|
||||
public class Consumer
|
||||
{
|
||||
public string? Host { get; set; }
|
||||
|
||||
public string? GroupId { get; set; }
|
||||
|
||||
public string? Topic { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Config
|
||||
{
|
||||
public class SystemConfig
|
||||
{
|
||||
public SystemConfig(string appid, string appSecret, string ssoUrl, string ssoOrganizationUrl, string[] clearCacheUrls, string userCenterRiaServiceUrl, string previewUrl, List<ClientKey>? clientKey)
|
||||
{
|
||||
Appid = appid;
|
||||
AppSecret = appSecret;
|
||||
SsoUrl = ssoUrl;
|
||||
SsoOrganizationUrl = ssoOrganizationUrl;
|
||||
ClearCacheUrls = clearCacheUrls;
|
||||
UserCenterRiaServiceUrl = userCenterRiaServiceUrl;
|
||||
PreviewUrl = previewUrl;
|
||||
ClientKey = clientKey;
|
||||
}
|
||||
|
||||
public SystemConfig()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string Appid { get; set; }
|
||||
|
||||
public string AppSecret { get; set; }
|
||||
|
||||
public string SsoUrl { get; set; }
|
||||
|
||||
public string SsoOrganizationUrl { get; set; }
|
||||
|
||||
public string UserCenterRiaServiceUrl { get; set; }
|
||||
|
||||
public string PreviewUrl { get; set; }
|
||||
|
||||
public string AuditUrl { get; set; }
|
||||
|
||||
public string? Riskinfo { get; set; }
|
||||
|
||||
public string? ContractStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端密钥
|
||||
/// </summary>
|
||||
public List<ClientKey>? ClientKey { get; set; }
|
||||
|
||||
public List<Company> CompanyList { get; set; }
|
||||
|
||||
public string ZxdUrl { get; set; }
|
||||
public string ZxdCoreUrl { get; set; }
|
||||
|
||||
|
||||
public string CrmUrl { get; set; }
|
||||
|
||||
public string[] ClearCacheUrls { get; set; }
|
||||
|
||||
public string GetAccessKey(string id)
|
||||
{
|
||||
return ClientKey?.First(x => x.Id == id).AccessKey ?? "";
|
||||
}
|
||||
|
||||
public string GetRiskinfo()
|
||||
{
|
||||
return UserCenterRiaServiceUrl + Riskinfo;
|
||||
}
|
||||
|
||||
public string PostContractStatus(string content, string sign, string clientId)
|
||||
{
|
||||
return $"{UserCenterRiaServiceUrl}{ContractStatus}?content={content}&sign={sign}&clientId={clientId}";
|
||||
}
|
||||
|
||||
public string? GetCompanyVideoUrl(CompanyList company)
|
||||
{
|
||||
return CompanyList.Where(x => x.Code == company.GetDescription()).Select(x => x.VideoUrl).FirstOrDefault();
|
||||
}
|
||||
|
||||
public string? GetCompanyWxMessageUrl(CompanyList company)
|
||||
{
|
||||
return CompanyList.Where(x => x.Code == company.GetDescription()).Select(x => x.WxMessageUrl).FirstOrDefault();
|
||||
}
|
||||
|
||||
public string? GetCompanyName(CompanyList company)
|
||||
{
|
||||
return CompanyList.Where(x => x.Code == company.GetDescription()).Select(x => x.Name).FirstOrDefault();
|
||||
}
|
||||
|
||||
public string? GetCompanyCode(CompanyList company)
|
||||
{
|
||||
return CompanyList.Where(x => x.Code == company.GetDescription()).Select(x => x.Code).FirstOrDefault();
|
||||
}
|
||||
|
||||
public string GetBusinessLineByDeptMentIds(string? groupIds, string? deptId)
|
||||
{
|
||||
return $"{CrmUrl}/Api/Customer/BusinessLineByDeptMentIds?GroupIds={groupIds}&DeptId={deptId}";
|
||||
}
|
||||
|
||||
public string GetEidsByDeptMentIds(string? groupIds, string? deptId)
|
||||
{
|
||||
return $"{CrmUrl}/Api/Customer/EidsByDeptMentIds?GroupIds={groupIds}&DeptId={deptId}";
|
||||
}
|
||||
|
||||
public string GetUserInfoByEIds(string? eids)
|
||||
{
|
||||
return $"{CrmUrl}/Api/Customer/GetUserInfoByEIds?eids={eids}";
|
||||
}
|
||||
}
|
||||
|
||||
public class ClientKey
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string AccessKey { get; set; }
|
||||
}
|
||||
|
||||
public class Company
|
||||
{
|
||||
public string? Code { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? VideoUrl { get; set; }
|
||||
|
||||
public string? WxMessageUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认
|
||||
/// </summary>
|
||||
public static class DefaultHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 到期时间(小时)
|
||||
/// </summary>
|
||||
public static int DueHours = 24;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
/// <summary>
|
||||
/// 投诉申请
|
||||
/// </summary>
|
||||
public class ApplyComplaintDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 平台id
|
||||
/// </summary>
|
||||
public string? Appid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户账号,比如,软件平台(username),服务号(openid)
|
||||
/// </summary>
|
||||
public string? Appuserid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 联合ID
|
||||
/// </summary>
|
||||
public string? Unionid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事业线ID
|
||||
/// </summary>
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 坐席的appid
|
||||
/// </summary>
|
||||
public string? CrmAppid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉来源
|
||||
/// 1、官网
|
||||
/// 2、公众号投诉
|
||||
/// 3、企微客服名片投诉
|
||||
/// 4、PC软件
|
||||
/// </summary>
|
||||
public ComplaintSource? Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户号码ID
|
||||
/// </summary>
|
||||
public string? Resid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉内容(json形式)
|
||||
/// </summary>
|
||||
public string? Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
public string? Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉类型
|
||||
/// </summary>
|
||||
public ComplaintSignType? SignType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉方式
|
||||
/// </summary>
|
||||
public ComplaintSignWay? SignWay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 渠道号
|
||||
/// </summary>
|
||||
public int? Channel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 工号
|
||||
/// </summary>
|
||||
public int? Eid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 员工姓名
|
||||
/// </summary>
|
||||
public string? Ename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水军类型
|
||||
/// </summary>
|
||||
public ComplaintSignReason? Reason { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class BatchAssignComplaintDto
|
||||
{
|
||||
public List<int> Ids { get; set; }
|
||||
|
||||
public int Eid { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class BusinessLineDto
|
||||
{
|
||||
public bool IsLine { get; set; }
|
||||
|
||||
public int DeptId { get; set; }
|
||||
|
||||
public List<int> EidInfo { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class ComplaintDetailDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int Fid { get; set; }
|
||||
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
public string? Resid { get; set; }
|
||||
|
||||
public string Uname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public ComplaintStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public string StatusStr { get
|
||||
{
|
||||
return Status.GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 风险标记
|
||||
/// </summary>
|
||||
public List<ComplaintLogDetailDto>? ComplaintLogDetails { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 跟进情况
|
||||
/// </summary>
|
||||
public List<ComplaintFollowDetailDto>? ComplaintFollowDetails { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
using Hg.Complaint.Domain.Dto.ContentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class ComplaintDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事业部id
|
||||
/// </summary>
|
||||
public int? DeptId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事业部
|
||||
/// </summary>
|
||||
public string? DeptName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事业部组
|
||||
/// </summary>
|
||||
public string? DeptGroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户id
|
||||
/// </summary>
|
||||
public string? ResId { get; set; }
|
||||
/// <summary>
|
||||
/// 客户id
|
||||
/// </summary>
|
||||
public string? UMID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户姓名
|
||||
/// </summary>
|
||||
public string? Uname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 归属员工
|
||||
/// </summary>
|
||||
public string? BelongEname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记类型
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplaintSignType? SignType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// summary
|
||||
/// </summary>
|
||||
public string? SignTypeStr
|
||||
{ get { return SignType?.GetDescription(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 标记方式
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplaintSignWay? SignWay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记方式
|
||||
/// </summary>
|
||||
public string? SignWayStr
|
||||
{ get { return SignWay?.GetDescription(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 标记时间
|
||||
/// </summary>
|
||||
public DateTime? Ctime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉来源
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplaintSource? Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉来源
|
||||
/// </summary>
|
||||
public string? SourceStr
|
||||
{ get { return Source?.GetDescription(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ComplaintStatus? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public string? StatusStr
|
||||
{ get { return Status?.GetDescription(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 倒计时
|
||||
/// </summary>
|
||||
public string? CountDown
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Status.HasValue && (Status == ComplaintStatus.跟进中 || Status == ComplaintStatus.已完结))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
var timespan = Ctime?.AddDays(1) - DateTime.Now;
|
||||
if (timespan.HasValue)
|
||||
{
|
||||
var hour = timespan.Value.Hours;
|
||||
var minute = timespan.Value.Minutes;
|
||||
var second = timespan.Value.Seconds;
|
||||
if (hour >= 0 && minute >= 0 && second >= 0)
|
||||
{
|
||||
return $"{hour}小时{minute}分{second}秒";
|
||||
}
|
||||
}
|
||||
return "已超时";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工单内容
|
||||
/// </summary>
|
||||
public string? FollowContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跟进时间
|
||||
/// </summary>
|
||||
public DateTime? FollowTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跟进人工号
|
||||
/// </summary>
|
||||
public int? Eid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跟进人
|
||||
/// </summary>
|
||||
public string? EName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 潜在投诉内容
|
||||
/// </summary>
|
||||
public string? Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 投诉内容
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? ContentJson { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 违规关键字
|
||||
/// </summary>
|
||||
public string? Keywords { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否存在订单
|
||||
/// </summary>
|
||||
public bool HasOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否存在分配
|
||||
/// </summary>
|
||||
public bool? HasAssign { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// appid
|
||||
/// </summary>
|
||||
public string? Appid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// appuserid
|
||||
/// </summary>
|
||||
public string? Appuserid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水军类型
|
||||
/// </summary>
|
||||
public ComplaintSignReason? Reason { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class ComplaintEventDto
|
||||
{
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public int? Fid { get; set; }
|
||||
|
||||
public DateTime? Ctime { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class ComplaintFollowDetailDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int? Eid { get; set; }
|
||||
|
||||
public string? Ename { get; set; }
|
||||
|
||||
public string? Crmappid { get; set; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Deptname { get; set; }
|
||||
|
||||
public string? Content { get; set; }
|
||||
|
||||
public DateTime? Ctime { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using Hg.Complaint.Domain.Dto.ContentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class ComplaintLogDetailDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public ComplaintSignType? SignType { get; set; }
|
||||
|
||||
public string? SignTypeStr { get { return SignType?.GetDescription(); } }
|
||||
|
||||
[JsonIgnore]
|
||||
public ComplaintSignWay? SignWay { get; set; }
|
||||
|
||||
public string? SignWayStr { get { return SignWay?.GetDescription(); } }
|
||||
|
||||
[JsonIgnore]
|
||||
public ComplaintSource? Source { get; set; }
|
||||
|
||||
public string? SourceStr { get { return Source?.GetDescription(); } }
|
||||
|
||||
public string? Type { get; set; }
|
||||
|
||||
public DateTime? Ctime { get; set; }
|
||||
|
||||
public string? Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 企微聊天id
|
||||
/// </summary>
|
||||
public string? Msgid { get; set; }
|
||||
|
||||
public string? Appid { get; set; }
|
||||
|
||||
public string? Appuserid { get; set; }
|
||||
|
||||
public string? InternalAppuserid { get; set; }
|
||||
|
||||
public string? Nickname { get; set; }
|
||||
|
||||
public string? InternalNickname { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string? ContentJson { get; set; }
|
||||
|
||||
public string? Keywords { get; set; }
|
||||
|
||||
public string? Deptname { get; set; }
|
||||
|
||||
public string? Signer { get; set; }
|
||||
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
public int? Eid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水军类型
|
||||
/// </summary>
|
||||
public ComplaintSignReason? Reason { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
/// <summary>
|
||||
/// 投诉日志队列
|
||||
/// </summary>
|
||||
public class ComplaintLogMessageDto : ComplaintLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 重试次数
|
||||
/// </summary>
|
||||
public int RetryCount { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto.ContentModel
|
||||
{
|
||||
internal class FormContentModelDto
|
||||
{
|
||||
[JsonPropertyName("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[JsonPropertyName("content")]
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto.ContentModel
|
||||
{
|
||||
public class NegativeContentModelDto : NegativeMessageDto
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class CreateLiveAuditDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 审核id
|
||||
/// </summary>
|
||||
public int AuditId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核备注
|
||||
/// </summary>
|
||||
public string? AuditRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 驳回理由
|
||||
/// </summary>
|
||||
public LiveAuditRejectReason? RejectReason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核附件
|
||||
/// </summary>
|
||||
public string? AuditAccessory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public LiveAuditStatus AuditStatus { get; set; }
|
||||
}
|
||||
public class AddLiveAuditDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 回放ids
|
||||
/// </summary>
|
||||
public string playBackIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播间id
|
||||
/// </summary>
|
||||
public int? SchedulesId { get; set; }
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核备注
|
||||
/// </summary>
|
||||
public string? AuditRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 驳回理由
|
||||
/// </summary>
|
||||
public LiveAuditRejectReason? RejectReason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核附件
|
||||
/// </summary>
|
||||
public string? AuditAccessory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public LiveAuditStatus AuditStatus { get; set; }
|
||||
}
|
||||
public class SolveLiveAuditDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 回放ids
|
||||
/// </summary>
|
||||
public int logId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 解决备注
|
||||
/// </summary>
|
||||
public string? SolveRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 解决附件
|
||||
/// </summary>
|
||||
public string? SolveAccessory { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class CreateLiveAuditRectificationDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 审核id
|
||||
/// </summary>
|
||||
public int AuditId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作人
|
||||
/// </summary>
|
||||
public string? Operator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 整改附件
|
||||
/// </summary>
|
||||
public string? RectificationAccessory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 整改备注
|
||||
/// </summary>
|
||||
public string? RectificationRemark { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
internal class CrmUserInfoDto
|
||||
{
|
||||
public int? Pkid { get; set; }
|
||||
|
||||
public int? Eid { get; set; }
|
||||
|
||||
public string? Uname { get; set; }
|
||||
|
||||
public int? DeptId { get; set; }
|
||||
|
||||
public string? DeptName { get; set; }
|
||||
|
||||
public int? GroupId { get; set; }
|
||||
|
||||
public string? GroupName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class DeptmentGroupDto : DeptmentGroup
|
||||
{
|
||||
public virtual List<Deptment>? Deptments { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class LiveAuditDetailDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播链接
|
||||
/// </summary>
|
||||
public string? LiveUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播信息
|
||||
/// </summary>
|
||||
public string? LiveRoomInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public LiveAuditStatus AuditStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 整改附件
|
||||
/// </summary>
|
||||
public string? RectificationAccessory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 整改备注
|
||||
/// </summary>
|
||||
public string? RectificationRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播课程id
|
||||
/// </summary>
|
||||
public int? ScheduleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播日期
|
||||
/// </summary>
|
||||
public string? LiveDate { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using Hg.Core.Entity.Hgaction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class LiveAuditDto : LiveAudit
|
||||
{
|
||||
public string? Deptname { get; set; }
|
||||
|
||||
public string? Event { get { return AuditStatus.GetDescription(); } }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using Hg.Core.Entity.Hgaction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class LiveAuditLogDto : LiveAuditLog
|
||||
{
|
||||
public string? Event { get { return AuditStatus.GetDescription(); } }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
using Hg.Core.Entity.Hgaction;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class LiveInfoDto : LiveInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 违规次数
|
||||
/// </summary>
|
||||
public int RejectCount { get; set; }
|
||||
|
||||
public string? Deptname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public LiveAuditStatus AuditStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public string? AuditStatusStr { get { return AuditStatus.GetDescription(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 待审核次数
|
||||
/// </summary>
|
||||
public int ToBeReviewedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已整改次数
|
||||
/// </summary>
|
||||
public int RectifyCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核通过次数
|
||||
/// </summary>
|
||||
public int PassCount { get; set; }
|
||||
}
|
||||
public class LiveAuditSchedules {
|
||||
/// <summary>
|
||||
/// 课程id
|
||||
/// </summary>
|
||||
public int? schedulesId { get; set; }
|
||||
/// <summary>
|
||||
/// 课程标题
|
||||
/// </summary>
|
||||
public string? title { get; set; }
|
||||
/// <summary>
|
||||
/// 第一列备注
|
||||
/// </summary>
|
||||
public string? cmsmome { get; set; }
|
||||
/// <summary>
|
||||
/// 简介
|
||||
/// </summary>
|
||||
public string? mome { get; set; }
|
||||
/// <summary>
|
||||
/// 管理事业部
|
||||
/// </summary>
|
||||
public string? deptid { get; set; }
|
||||
/// <summary>
|
||||
/// 事业部名称
|
||||
/// </summary>
|
||||
public string? deptname { get; set; }
|
||||
/// <summary>
|
||||
/// 直播开始时间
|
||||
/// </summary>
|
||||
public string? starttime { get; set; }
|
||||
/// <summary>
|
||||
/// 直播结束时间
|
||||
/// </summary>
|
||||
public string? endtime { get; set; }
|
||||
/// <summary>
|
||||
/// 直播老师
|
||||
/// </summary>
|
||||
public string? Liver { get; set; }
|
||||
/// <summary>
|
||||
/// 预热时间
|
||||
/// </summary>
|
||||
public int? pretime { get; set; }
|
||||
/// <summary>
|
||||
/// 直播周
|
||||
/// </summary>
|
||||
public string? weeks { get; set; }
|
||||
/// <summary>
|
||||
/// 营销类型:
|
||||
/// 1、免费营销
|
||||
/// 10、升级营销
|
||||
/// 100、付费服务
|
||||
/// </summary>
|
||||
public MarketingType? marketingtype { get; set; }
|
||||
/// <summary>
|
||||
/// 直播流id
|
||||
/// </summary>
|
||||
public int? livestreamid { get; set; }
|
||||
/// <summary>
|
||||
/// 投放方式
|
||||
/// 1: 直播间
|
||||
/// 2:工作室
|
||||
/// </summary>
|
||||
public RoomType? roomtype { get; set; }
|
||||
/// <summary>
|
||||
/// 待审核 直播
|
||||
/// </summary>
|
||||
public int waitAudit { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// 违规次数
|
||||
/// </summary>
|
||||
public int violation { get; set; } = 0;
|
||||
|
||||
}
|
||||
|
||||
public class LiveAuditPlayBack {
|
||||
|
||||
public int? pbid { get; set; }
|
||||
public int scheduleid { get; set; }
|
||||
public string? title { get; set; }
|
||||
public string? thumb { get; set; }
|
||||
public string? intro { get; set; }
|
||||
public DateTime? ctime { get; set; }
|
||||
public string? url { get; set; }
|
||||
public int? recordid { get; set; }
|
||||
public int? status { get; set; }
|
||||
public int? istop { get; set; }
|
||||
public DateTime? zbdate { get; set; }
|
||||
public LiveAuditStatus? auditStatus { get; set; }
|
||||
}
|
||||
public class PlayBackAuditLog
|
||||
{
|
||||
public int? playBackId { get; set; }
|
||||
public int? schedulesId { get; set; }
|
||||
public LiveAuditStatus auditStatus { get; set; }
|
||||
public LiveAuditRejectReason? rejectReason { get; set; }
|
||||
public string? auditRemark { get; set; }
|
||||
public string? auditAccessory { get; set; }
|
||||
public string? creater { get; set; }
|
||||
public DateTime? ctime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 处理人
|
||||
/// </summary>
|
||||
public string? solver { get; set; }
|
||||
/// <summary>
|
||||
/// 处理事件
|
||||
/// </summary>
|
||||
public DateTime? solveTime { get; set; }
|
||||
public string? solveRemark { get; set; }
|
||||
public string? solveAccessory { get; set; }
|
||||
}
|
||||
public enum WeeksEnum
|
||||
{
|
||||
周日 = 0,
|
||||
周一 = 1,
|
||||
周二 = 2,
|
||||
周三 = 3,
|
||||
周四 = 4,
|
||||
周五 = 5,
|
||||
周六 = 6
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class MarkCustomerDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 1为合规 2 为业务
|
||||
/// </summary>
|
||||
public int? Type { get; set; }
|
||||
|
||||
public bool IsResid { get; set; }
|
||||
public string? PostId { get; set; }
|
||||
public ComplaintSignType? Signtype { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public string? DeptId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 工号
|
||||
/// </summary>
|
||||
public int? Eid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 员工姓名
|
||||
/// </summary>
|
||||
public string? Ename { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class MarkTrollsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 平台id
|
||||
/// </summary>
|
||||
public string? Appid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户账号,比如,软件平台(username),服务号(openid)
|
||||
/// </summary>
|
||||
public string? Appuserid { get; set; }
|
||||
|
||||
public int? Eid { get; set; }
|
||||
|
||||
public ComplaintSignReason? Reason { get; set; }
|
||||
|
||||
public string? Content { get; set; }
|
||||
|
||||
public string? Deptid { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
/// <summary>
|
||||
/// 消极消息
|
||||
/// </summary>
|
||||
public class NegativeMessageDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息ID
|
||||
/// </summary>
|
||||
public string? Msgid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息类型
|
||||
/// </summary>
|
||||
public string? Msgtype { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收时间
|
||||
/// </summary>
|
||||
public long? Recvtime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送时间
|
||||
/// </summary>
|
||||
public long? Msgtime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 企微ID
|
||||
/// </summary>
|
||||
public string? Corpid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 企微名称
|
||||
/// </summary>
|
||||
public string? Corpname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 群消息接收者列表
|
||||
/// </summary>
|
||||
public string? Tolist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 房间ID
|
||||
/// </summary>
|
||||
public string? Roomid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送序列号
|
||||
/// </summary>
|
||||
public long? Seq { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送或接收,1:发送,2:接收
|
||||
/// </summary>
|
||||
[JsonPropertyName("send_type")]
|
||||
public int? SendType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 聊天内容
|
||||
/// </summary>
|
||||
[JsonPropertyName("text_content")]
|
||||
public string? TextContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 不合规词汇ID位图
|
||||
/// </summary>
|
||||
[JsonPropertyName("illegal_words")]
|
||||
public string[]? IllegalWords { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人客户ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("external_resid")]
|
||||
public string? ExternalResid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人联合ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("external_unionid")]
|
||||
public string? ExternalUnionid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人账号或群ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("external_appuserid")]
|
||||
public string? EnternalAppuserid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部联系人昵称或群名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("external_nickname")]
|
||||
public string? ExternalNickname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人工号
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_eid")]
|
||||
public int? EnternalEid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人小组ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_groupid")]
|
||||
public int? InternalGroupid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人部门ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_deptid")]
|
||||
public int? InternalDeptid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人员工姓名
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_employee_name")]
|
||||
public string? InternalEmployeeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人小组名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_group_name")]
|
||||
public string? InternalGroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人业务部名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_dept_name")]
|
||||
public string? InternalDeptName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人联合ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_unionid")]
|
||||
public string? InternalUnionid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人昵称或群名称
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_nickname")]
|
||||
public string? InternalNickname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部联系人ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("internal_appuserid")]
|
||||
public string? InternalAppuserid { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class RiskInfoDto
|
||||
{
|
||||
public int Ret { get; set; }
|
||||
public string? Answer { get; set; }
|
||||
public long CreateTime { get; set; }
|
||||
public string? IdCard { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Key { get; set; }
|
||||
public string? Style { get; set; }
|
||||
public int Index { get; set; }
|
||||
public string? Businesstype { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class SearchComplaintDto : SearchPageBase
|
||||
{
|
||||
public string? DeptId { get; set; }
|
||||
public string? ResId { get; set; }
|
||||
public string? UMID { get; set; }
|
||||
public string? UName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 来源
|
||||
/// </summary>
|
||||
public ComplaintSource? Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记类型 标记类型1.电话 2. 违规关键词 3.企微投诉连接
|
||||
/// </summary>
|
||||
public ComplaintSignType? SignType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记方法1.人工标记 2. 系统标记 3.客户投诉
|
||||
/// </summary>
|
||||
public ComplaintSignWay? SignWay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public ComplaintStatus? Status { get; set; }
|
||||
|
||||
public DateTime? STime { get; set; }
|
||||
public DateTime? ETime { get; set; }
|
||||
|
||||
[JsonPropertyName("txt_groupIds")]
|
||||
public string? Txt_groupIds { get; set; }
|
||||
|
||||
[JsonPropertyName("txt_deptId")]
|
||||
public string? Txt_deptId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有成交
|
||||
/// </summary>
|
||||
public bool? HasOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有分配
|
||||
/// </summary>
|
||||
public bool? HasAssign { get; set; }
|
||||
|
||||
[JsonPropertyName("txt_deptId")]
|
||||
public int? Txt_userId { get; set; }
|
||||
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class SearchLiveAuditDto : SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 直播间id
|
||||
/// </summary>
|
||||
public int? LiveId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事业部
|
||||
/// </summary>
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播人
|
||||
/// </summary>
|
||||
public string? Liver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime? TimeFrom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 课程
|
||||
/// </summary>
|
||||
public string? Schedule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime? TimeTo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核人
|
||||
/// </summary>
|
||||
public string? Auditer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public LiveAuditStatus? AuditStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核时间
|
||||
/// </summary>
|
||||
public DateTime? AuditTimeFrom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核时间
|
||||
/// </summary>
|
||||
public DateTime? AuditTimeTo { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class SearchLiveDto : SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 事业部
|
||||
/// </summary>
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播间id
|
||||
/// </summary>
|
||||
public int? LiveId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平台
|
||||
/// </summary>
|
||||
public int? PlatformId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 课程
|
||||
/// </summary>
|
||||
public string? Schedule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播人
|
||||
/// </summary>
|
||||
public string? Liver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime? TimeFrom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime? TimeTo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
public LiveAuditStatus? AuditStatus { get; set; }
|
||||
}
|
||||
public class SearchLiveScheduleDto : SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 平台(暂不传)
|
||||
/// </summary>
|
||||
public int? PlatformId { get; set; }
|
||||
/// <summary>
|
||||
/// 事业部
|
||||
/// </summary>
|
||||
public int? Deptid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 课程
|
||||
/// </summary>
|
||||
public string? Schedule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直播人
|
||||
/// </summary>
|
||||
public string? Liver { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 时间
|
||||
///// </summary>
|
||||
//public DateTime? TimeFrom { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 时间
|
||||
///// </summary>
|
||||
//public DateTime? TimeTo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态
|
||||
/// </summary>
|
||||
// public LiveAuditStatus? AuditStatus { get; set; }
|
||||
}
|
||||
|
||||
public class SearchLivePlayBackDto : SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 课程表id
|
||||
/// </summary>
|
||||
public int? schedulesId { get; set; }
|
||||
public DateTime? stime { get; set; }
|
||||
public DateTime? etime { get; set; }
|
||||
public int? LiveAuditStatus { get; set; }
|
||||
|
||||
|
||||
}
|
||||
public class SearchPlayBackAuditLogDto : SearchPageBase
|
||||
{
|
||||
/// <summary>
|
||||
/// playBackId
|
||||
/// </summary>
|
||||
public int? playBackId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class UpdateComplaintStatusDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int? Eid { get; set; }
|
||||
|
||||
public string? Ename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public ComplaintStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容
|
||||
/// </summary>
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
public class ComplainStatusModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public ComplaintStatus Status { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Dto
|
||||
{
|
||||
public class UserInfoDto
|
||||
{
|
||||
[JsonPropertyName("uid")]
|
||||
public string? Uid { get; set; }
|
||||
|
||||
[JsonPropertyName("appid")]
|
||||
public string? Appid { get; set; }
|
||||
|
||||
[JsonPropertyName("appuserid")]
|
||||
public string? Appuserid { get; set; }
|
||||
|
||||
[JsonPropertyName("customerid")]
|
||||
public string? Customerid { get; set; }
|
||||
|
||||
[JsonPropertyName("resid")]
|
||||
public string? Resid { get; set; }
|
||||
|
||||
[JsonPropertyName("unionid")]
|
||||
public string? Unionid { get; set; }
|
||||
|
||||
public string? Ch { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Confluent.Kafka" Version="1.9.2" />
|
||||
<PackageReference Include="DG.Redis" Version="1.0.17" />
|
||||
<PackageReference Include="DG.Tool" Version="1.0.9" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Exceptionless.AspNetCore" Version="6.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Exceptionless" Version="4.0.0" />
|
||||
<PackageReference Include="DG.Core" Version="1.0.25" />
|
||||
<PackageReference Include="Zxd.Core.Shared" Version="1.0.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Hg.Core.EntityFramework\Hg.Core.EntityFramework.csproj" />
|
||||
<ProjectReference Include="..\Hg.Core.Shared\Hg.Core.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="DG.EntityFramework" />
|
||||
<Using Include="Exceptionless" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="DG.Redis" />
|
||||
<Using Include="DG.Tool" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="System.Text" />
|
||||
<Using Include="System.Text.Json.Serialization" />
|
||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||
<Using Include="Microsoft.Extensions.Configuration" />
|
||||
<Using Include="System.Linq.Expressions" />
|
||||
<Using Include="Hg.Core.EntityFramework" />
|
||||
<Using Include="Hg.Core.Entity" />
|
||||
<Using Include="Hg.Complaint.Domain.Impl" />
|
||||
<Using Include="Hg.Complaint.Domain.Config" />
|
||||
<Using Include="Hg.Complaint.Domain.Dto" />
|
||||
<Using Include="Hg.Core.Entity.HgCrm" />
|
||||
<Using Include="Hg.Core.Entity.Complaint" />
|
||||
<Using Include="Hg.Core.Entity.Dncmsbase" />
|
||||
<Using Include="Hg.Core.Entity.UserCenter" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Zxd.Core.Shared.Dto;
|
||||
|
||||
namespace Hg.Complaint.Domain.Impl
|
||||
{
|
||||
internal interface ICacheDomain : ITransientDependency
|
||||
{
|
||||
Task<List<DeptmentDto>> GetDeptments();
|
||||
|
||||
Task<List<DeptmentGroupDto>> GetDeptmentGroups();
|
||||
|
||||
Task<DeptmentGroupDto?> GetDeptmentGroupByDeptid(int? deptid);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Impl
|
||||
{
|
||||
public interface IComplaintDomain : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 分析消极消息
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> AnalyseNegativeMessage(NegativeMessageDto dto);
|
||||
|
||||
/// <summary>
|
||||
/// 申请投诉
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> ApplyComplaint(ApplyComplaintDto dto);
|
||||
|
||||
/// <summary>
|
||||
/// 分析投诉日志
|
||||
/// </summary>
|
||||
/// <param name="messageDto"></param>
|
||||
/// <returns></returns>
|
||||
Task AnalyseComplaintLog(ComplaintLogMessageDto messageDto);
|
||||
|
||||
/// <summary>
|
||||
/// 获取队列数量
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<long> GetQueue();
|
||||
|
||||
/// <summary>
|
||||
/// 消费单个队列对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<ComplaintLogMessageDto> DequeueQueue();
|
||||
|
||||
/// <summary>
|
||||
/// 获取队列信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<ComplaintLogMessageDto>> GetQueues();
|
||||
|
||||
/// <summary>
|
||||
/// 分页
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
Task<PageResult<ComplaintDto>> GetPage(SearchComplaintDto dto, string? appid);
|
||||
|
||||
/// <summary>
|
||||
/// 重新发起队列
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<ComplaintLogMessageDto>> SyncQueue();
|
||||
|
||||
/// <summary>
|
||||
/// 获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
Task<ComplaintDetailDto> GetComplaintDetail(int id);
|
||||
|
||||
/// <summary>
|
||||
/// 根据资源id和业务线获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="resid"></param>
|
||||
/// <param name="deptid"></param>
|
||||
/// <returns></returns>
|
||||
Task<ComplaintDetailDto> GetComplaintDetail(string? resid, int? deptid);
|
||||
|
||||
/// <summary>
|
||||
/// 根据appid和业务线获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="appuserid"></param>
|
||||
/// <param name="deptid"></param>
|
||||
/// <returns></returns>
|
||||
Task<ComplaintDetailDto> GetComplaintDetail(string? appid, string? appuserid, int? deptid);
|
||||
|
||||
/// <summary>
|
||||
/// 更新投诉状态
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> UpdateComplaintStatus(UpdateComplaintStatusDto dto, string? appid);
|
||||
|
||||
/// <summary>
|
||||
/// 获取跟进状态
|
||||
/// </summary>
|
||||
/// <param name="udid"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
Task<ComplainStatusModel> GetComplaintStatus(int udid);
|
||||
|
||||
/// <summary>
|
||||
/// 标记用户
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> MarkCustomer(MarkCustomerDto dto);
|
||||
|
||||
/// <summary>
|
||||
/// 初始化处理过期未处理投诉
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task InitOverdueComplaint();
|
||||
|
||||
/// <summary>
|
||||
/// 处理过期未处理投诉
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task OverdueComplaint();
|
||||
|
||||
/// <summary>
|
||||
/// 刷新resid
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task SyncResid();
|
||||
|
||||
/// <summary>
|
||||
/// 批量分配客户给客服
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> BatchAssignComplaint(BatchAssignComplaintDto dto, string? appid);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> MarkTrolls(MarkTrollsDto dto);
|
||||
|
||||
Task<int> ComplaintLabel(string resId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hg.Complaint.Domain.Impl
|
||||
{
|
||||
public interface ILiveAuditDomain : IScopedDependency
|
||||
{
|
||||
Task<PageResult<LiveAuditDto>> GetLiveAuditPage(SearchLiveAuditDto dto);
|
||||
|
||||
Task<List<LiveAuditLogDto>> GetLiveAuditLogs(int auditId, string? date);
|
||||
|
||||
Task CreateLiveAudit(CreateLiveAuditDto dto);
|
||||
|
||||
Task CreateLiveAuditRectification(CreateLiveAuditRectificationDto dto);
|
||||
|
||||
List<SelectItem> GetRejectReasonSelect();
|
||||
|
||||
List<SelectItem> GetAuditStatusSelect();
|
||||
|
||||
Task<List<SelectItem>> GetPlatformSelect();
|
||||
|
||||
Task<LiveAuditDetailDto> GetLiveAuditDetail(int auditId);
|
||||
|
||||
Task SyncLiveData();
|
||||
|
||||
Task<PageResult<LiveInfoDto>> GetLivePage(SearchLiveDto dto);
|
||||
|
||||
Task AddLiveAuditLog(AddLiveAuditDto dto);
|
||||
Task SolveLiveAudit(SolveLiveAuditDto dto);
|
||||
Task<PageResult<LiveAuditSchedules>> GetLiveSchedulePage(SearchLiveScheduleDto dto);
|
||||
Task<PageResult<LiveAuditPlayBack>> GetLivePlayBackPage(SearchLivePlayBackDto dto);
|
||||
Task<PageResult<PlayBackAuditLog>> GetPlayBackAuditLogPage(SearchPlayBackAuditLogDto dto);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,879 @@
|
|||
using DG.Core;
|
||||
using Exceptionless.Models;
|
||||
using Hg.Core.Entity.Dncmsbase;
|
||||
using Hg.Core.Entity.Hgaction;
|
||||
using Hg.Core.Entity.Views.DNG8;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
|
||||
|
||||
namespace Hg.Complaint.Domain
|
||||
{
|
||||
internal class LiveAuditDomain : ILiveAuditDomain
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IRedisManager _redisManager;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ICacheDomain _cacheDomain;
|
||||
private readonly int _retryCount = 3;
|
||||
private readonly SystemConfig _systemConfig;
|
||||
|
||||
public LiveAuditDomain(
|
||||
IRedisManager redisManager,
|
||||
IConfiguration configuration,
|
||||
IMapper mapper,
|
||||
IHttpClient httpClient,
|
||||
ICacheDomain cacheDomain,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_systemConfig = configuration.GetSection("SystemConfig").Get<SystemConfig>();
|
||||
_redisManager = redisManager;
|
||||
_mapper = mapper;
|
||||
_httpClient = httpClient;
|
||||
_configuration = configuration;
|
||||
_cacheDomain = cacheDomain;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task<PageResult<LiveInfoDto>> GetLivePage(SearchLiveDto dto)
|
||||
{
|
||||
var deptments = await _cacheDomain.GetDeptments();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var logQuery = hgActionRepository.GetRepository<LiveAuditLog>().Query();
|
||||
var auditQuery = hgActionRepository.GetRepository<LiveAudit>().Query();
|
||||
|
||||
#region 查询拼接
|
||||
|
||||
var query = from a in hgActionRepository.GetRepository<LiveInfo>().Query()
|
||||
select new LiveInfoDto
|
||||
{
|
||||
Id = a.Id,
|
||||
Deptid = a.Deptid,
|
||||
PlatformId = a.PlatformId,
|
||||
Platform = a.Platform,
|
||||
LiveUrl = a.LiveUrl,
|
||||
LiveId = a.LiveId,
|
||||
Liver = a.Liver,
|
||||
Schedule = a.Schedule,
|
||||
ScheduleId = a.ScheduleId,
|
||||
LiveTitle = a.LiveTitle,
|
||||
Ctime = a.Ctime,
|
||||
PassCount = (
|
||||
from c in auditQuery
|
||||
where c.LiveId == a.LiveId && c.AuditStatus == LiveAuditStatus.审核通过
|
||||
select c.Id).Count(),
|
||||
RectifyCount = (
|
||||
from c in auditQuery
|
||||
where c.LiveId == a.LiveId && c.AuditStatus == LiveAuditStatus.已整改
|
||||
select c.Id).Count(),
|
||||
RejectCount = (
|
||||
from c in auditQuery
|
||||
where c.LiveId == a.LiveId && c.AuditStatus == LiveAuditStatus.违规
|
||||
select c.Id).Count(),
|
||||
ToBeReviewedCount = (
|
||||
from c in auditQuery
|
||||
where c.LiveId == a.LiveId && c.AuditStatus == LiveAuditStatus.待审核
|
||||
select c.Id).Count()
|
||||
};
|
||||
|
||||
query = query.GroupBy(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.Deptid,
|
||||
x.PlatformId,
|
||||
x.Platform,
|
||||
x.LiveUrl,
|
||||
x.LiveId,
|
||||
x.Liver,
|
||||
x.Schedule,
|
||||
x.ScheduleId,
|
||||
x.LiveTitle,
|
||||
x.Ctime,
|
||||
}).Select(x => new LiveInfoDto
|
||||
{
|
||||
Id = x.Key.Id,
|
||||
Deptid = x.Key.Deptid,
|
||||
PlatformId = x.Key.PlatformId,
|
||||
Platform = x.Key.Platform,
|
||||
LiveUrl = x.Key.LiveUrl,
|
||||
LiveId = x.Key.LiveId,
|
||||
Liver = x.Key.Liver,
|
||||
Schedule = x.Key.Schedule,
|
||||
ScheduleId = x.Key.ScheduleId,
|
||||
LiveTitle = x.Key.LiveTitle,
|
||||
Ctime = x.Key.Ctime,
|
||||
PassCount = x.Sum(x => x.PassCount),
|
||||
RectifyCount = x.Sum(x => x.RectifyCount),
|
||||
RejectCount = x.Sum(x => x.RejectCount),
|
||||
ToBeReviewedCount = x.Sum(x => x.ToBeReviewedCount),
|
||||
});
|
||||
|
||||
#endregion 查询拼接
|
||||
|
||||
query = query.If(!string.IsNullOrEmpty(dto.Liver), x => x.Where(x => x.Liver.Contains(dto.Liver)))
|
||||
.If(!string.IsNullOrEmpty(dto.Schedule), x => x.Where(x => x.Schedule.Contains(dto.Schedule)))
|
||||
.If(dto.Deptid.HasValue, x => x.Where(x => x.Deptid == dto.Deptid.Value))
|
||||
.If(dto.LiveId.HasValue, x => x.Where(x => x.LiveId == dto.LiveId.Value))
|
||||
.If(dto.PlatformId.HasValue, x => x.Where(x => x.PlatformId == dto.PlatformId.Value))
|
||||
.If(dto.TimeFrom.HasValue, x => x.Where(x => x.Ctime >= dto.TimeFrom.Value))
|
||||
.If(dto.TimeTo.HasValue, x => x.Where(x => x.Ctime < dto.TimeTo.Value));
|
||||
|
||||
var total = await query.CountAsync();
|
||||
var data = await query.OrderByDescending(x => x.Id)
|
||||
.Skip((dto.PageIndex - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.ToListAsync();
|
||||
var lecturerids = string.Join(",", data.Select(x => x.Liver)).Split(',').Select(x => int.Parse(x)).ToList();
|
||||
var lecturers = await dncmsbaseRepository.GetRepository<Lecturer>().Query()
|
||||
.Where(x => lecturerids.Contains(x.Id))
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.Title
|
||||
}).ToListAsync();
|
||||
foreach (var item in data)
|
||||
{
|
||||
item.Deptname = deptments.Where(y => y.Id == item.Deptid).Select(x => x.Title).FirstOrDefault();
|
||||
var liver = item.Liver?.Split(',').Select(x => int.Parse(x)).ToList();
|
||||
var lecturer = lecturers.Where(x => liver.Contains(x.Id)).ToList();
|
||||
item.Liver = string.Join(",", lecturer.Select(x => x.Title).ToList());
|
||||
var audit = await auditQuery.Where(y => y.LiveId == item.LiveId).OrderByDescending(y => y.Id).FirstOrDefaultAsync();
|
||||
if (audit == null)
|
||||
{
|
||||
item.AuditStatus = LiveAuditStatus.待审核;
|
||||
}
|
||||
else
|
||||
{
|
||||
var log = await logQuery.Where(y => y.LiveId == item.LiveId).OrderByDescending(y => y.Id).FirstOrDefaultAsync();
|
||||
item.AuditStatus = log != null && audit.AuditStatus == LiveAuditStatus.待审核 && log.AuditStatus != LiveAuditStatus.审核通过 ? log.AuditStatus
|
||||
: audit.AuditStatus;
|
||||
}
|
||||
}
|
||||
|
||||
return new PageResult<LiveInfoDto>(dto.PageIndex, dto.PageSize, total, data);
|
||||
}
|
||||
|
||||
public async Task<PageResult<LiveAuditDto>> GetLiveAuditPage(SearchLiveAuditDto dto)
|
||||
{
|
||||
var deptments = await _cacheDomain.GetDeptments();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var query = hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.If(dto.LiveId.HasValue, x => x.Where(x => x.LiveId == dto.LiveId))
|
||||
.If(dto.Deptid.HasValue, x => x.Where(x => x.Deptid == dto.Deptid))
|
||||
.If(!string.IsNullOrEmpty(dto.Schedule), x => x.Where(x => x.Schedule.Contains(dto.Schedule)))
|
||||
.If(!string.IsNullOrEmpty(dto.Auditer), x => x.Where(x => x.Auditer.Contains(dto.Auditer)))
|
||||
.If(!string.IsNullOrEmpty(dto.Liver), x => x.Where(x => x.Liver.Contains(dto.Liver)))
|
||||
.If(!string.IsNullOrEmpty(dto.Remark), x => x.Where(x => x.Remark.Contains(dto.Remark)))
|
||||
.If(dto.TimeFrom.HasValue, x => x.Where(x => x.Ctime >= dto.TimeFrom.Value))
|
||||
.If(dto.TimeTo.HasValue, x => x.Where(x => x.Ctime < dto.TimeTo.Value))
|
||||
.If(dto.AuditTimeFrom.HasValue, x => x.Where(x => x.AuditTime >= dto.AuditTimeFrom.Value))
|
||||
.If(dto.AuditTimeTo.HasValue, x => x.Where(x => x.AuditTime < dto.AuditTimeTo.Value))
|
||||
.If(dto.AuditStatus.HasValue, x => x.Where(x => x.AuditStatus == dto.AuditStatus));
|
||||
|
||||
var total = await query.CountAsync();
|
||||
var list = await query.OrderByDescending(x => x.Id)
|
||||
.Skip((dto.PageIndex - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.ToListAsync();
|
||||
|
||||
var data = _mapper.Map<LiveAudit, LiveAuditDto>(list);
|
||||
|
||||
var ids = data.Select(x => x.Id).ToList();
|
||||
|
||||
data.ForEach(x =>
|
||||
{
|
||||
x.Deptname = deptments.Where(y => y.Id == x.Deptid).Select(x => x.Title).FirstOrDefault();
|
||||
});
|
||||
|
||||
return new PageResult<LiveAuditDto>(dto.PageIndex, dto.PageSize, total, data);
|
||||
}
|
||||
|
||||
public async Task<List<LiveAuditLogDto>> GetLiveAuditLogs(int auditId, string? date)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
|
||||
var liveAudit = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.FirstOrDefaultAsync(x => x.Id == auditId) ?? throw new ApiException("审核记录不存在或已删除!");
|
||||
|
||||
var auditIds = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.Where(x => x.LiveId == liveAudit.LiveId && x.LiveDate == date)
|
||||
.Select(x => x.Id)
|
||||
.ToListAsync();
|
||||
|
||||
var list = await hgActionRepository.GetRepository<LiveAuditLog>().Query()
|
||||
.Where(x => auditIds.Contains(x.AuditId)).ToListAsync();
|
||||
|
||||
var data = _mapper.Map<LiveAuditLog, LiveAuditLogDto>(list);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public async Task CreateLiveAudit(CreateLiveAuditDto dto)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var data = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.FirstOrDefaultAsync(x => x.Id == dto.AuditId) ?? throw new ApiException("审核记录不存在或已删除!");
|
||||
|
||||
data.AuditStatus = dto.AuditStatus;
|
||||
data.Auditer = dto.Operator;
|
||||
data.AuditTime = DateTime.Now;
|
||||
|
||||
var log = _mapper.Map<CreateLiveAuditDto, LiveAuditLog>(dto);
|
||||
|
||||
log.Ctime = DateTime.Now;
|
||||
log.Schedule = data.Schedule;
|
||||
log.LiveId = data.LiveId;
|
||||
|
||||
using var transaction = await hgActionRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await hgActionRepository.GetRepository<LiveAudit>().UpdateAsync(data, x => new
|
||||
{
|
||||
x.AuditStatus,
|
||||
x.AuditTime,
|
||||
x.Auditer
|
||||
});
|
||||
await hgActionRepository.GetRepository<LiveAuditLog>().InsertAsync(log);
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region 直播审核2
|
||||
|
||||
private DateTime limitDate = DateTime.Parse("2023-11-07");
|
||||
//private DateTime limitDate = DateTime.Parse("1993-11-07");
|
||||
|
||||
/// <summary>
|
||||
/// 课程表列表
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PageResult<LiveAuditSchedules>> GetLiveSchedulePage(SearchLiveScheduleDto dto)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var deptments = await dncmsbaseRepository.GetRepository<Deptment>().Query().ToListAsync();
|
||||
var zxdRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<ZxdDbContext>>();
|
||||
var setting = await zxdRepository.GetRepository<BasParameter>().Query().FirstOrDefaultAsync(n => n.PARAKEY == "LiveAudtiDeptIgnoreSetting");
|
||||
List<string> notCaontainDeptids = new List<string>();
|
||||
if (setting != null)
|
||||
{
|
||||
var deptids = setting.PARAVALUE.Split(',').ToList();
|
||||
notCaontainDeptids.AddRange(deptids);
|
||||
}
|
||||
|
||||
#region 查询拼接
|
||||
|
||||
var query = from a in dncmsbaseRepository.GetRepository<ZhiboSystemSchedules>().Query().Where(m => m.Status == 1 && !notCaontainDeptids.Contains(m.Dept))
|
||||
select new LiveAuditSchedules
|
||||
{
|
||||
schedulesId = a.Id,
|
||||
title = a.Title,
|
||||
cmsmome = a.Cmsmemo,
|
||||
mome = a.Memo,
|
||||
deptid = a.Dept,
|
||||
starttime = a.Starttime,
|
||||
endtime = a.Endtime,
|
||||
Liver = a.Lecturer,
|
||||
pretime = a.Pretime,
|
||||
weeks = a.Weeks,
|
||||
marketingtype = a.Marketingtype,
|
||||
livestreamid = a.Livestreamid,
|
||||
roomtype = a.Roomtype
|
||||
};
|
||||
query = query.If(!string.IsNullOrEmpty(dto.Liver), x => x.Where(x => x.Liver.Contains(dto.Liver)))
|
||||
.If(!string.IsNullOrEmpty(dto.Schedule), x => x.Where(x => x.title.Contains(dto.Schedule)))
|
||||
.If(dto.Deptid.HasValue, x => x.Where(x => x.deptid.Contains(dto.Deptid.Value.ToString())));
|
||||
// .If(dto.PlatformId.HasValue, x => x.Where(x => x. == dto.PlatformId.Value))
|
||||
// .If(dto.TimeFrom.HasValue, x => x.Where(x => x.Ctime >= dto.TimeFrom.Value))
|
||||
// .If(dto.TimeTo.HasValue, x => x.Where(x => x.Ctime < dto.TimeTo.Value));
|
||||
|
||||
#endregion 查询拼接
|
||||
|
||||
var total = await query.CountAsync();
|
||||
var data = await query.OrderByDescending(x => x.schedulesId)
|
||||
.Skip((dto.PageIndex - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.ToListAsync();
|
||||
var lecturerids = string.Join(",", data.Select(x => x.Liver)).Split(',').Select(x => int.Parse(x)).ToList();
|
||||
var lecturers = await dncmsbaseRepository.GetRepository<Lecturer>().Query()
|
||||
.Where(x => lecturerids.Contains(x.Id))
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.Title
|
||||
}).ToListAsync();
|
||||
|
||||
var schedulesIds = data.Select(m => m.schedulesId).ToList();
|
||||
//var log = dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().Query().Where(m => schedulesIds.Contains(m.schedulesId)).ToList();
|
||||
var pb = dncmsbaseRepository.GetRepository<ZhiboSystemSchedulesPlayback>().Query()
|
||||
.Include(x => x.LiveAuditLogPlayBack)
|
||||
.ThenInclude(x => x.CMS_LiveAuditLog)
|
||||
.Where(m => schedulesIds.Contains(m.scheduleid) && m.zbdate > limitDate && m.status == 1).ToList();
|
||||
foreach (var item in data)
|
||||
{
|
||||
var liver = item.Liver?.Split(',').Select(x => int.Parse(x)).ToList();
|
||||
var lecturer = lecturers.Where(x => liver.Contains(x.Id)).ToList();
|
||||
var mypb = pb.Where(m => m.scheduleid == item.schedulesId).ToList();
|
||||
|
||||
var mylog = mypb.SelectMany(n => n.LiveAuditLogPlayBack).Where(n => n.CMS_LiveAuditLog != null).Select(x => x.CMS_LiveAuditLog).ToList();
|
||||
//var wlog = mylog.Where(i => i.auditStatus == LiveAuditStatus.待审核);
|
||||
|
||||
item.deptname = deptments.Where(y => item.deptid.Split(',').Contains(y.Id.ToString())).Select(x => x.Title).FirstOrDefault();//汉化事业部
|
||||
item.Liver = string.Join(",", lecturer.Select(x => x.Title).ToList());//汉化老师
|
||||
item.weeks = GetWeeksName(item.weeks);//汉化周
|
||||
|
||||
item.violation = mylog.Where(m => m.auditStatus == LiveAuditStatus.已整改 || m.auditStatus == LiveAuditStatus.违规).Count();//提交违规次数
|
||||
//无提交审核记录的 和未审核 都算未审核
|
||||
item.waitAudit = mypb.Count(n => !n.LiveAuditLogPlayBack.Any() || n.LiveAuditLogPlayBack.Exists(x => x.CMS_LiveAuditLog.auditStatus == LiveAuditStatus.待审核));
|
||||
//item.waitAudit = mypb.Count(m => !mylog.Select(n => n.schedulesId).Contains(m.scheduleid) || wlog.Select(n => n.schedulesId).Contains(m.scheduleid));
|
||||
}
|
||||
|
||||
return new PageResult<LiveAuditSchedules>(dto.PageIndex, dto.PageSize, total, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直播回放列表
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PageResult<LiveAuditPlayBack>> GetLivePlayBackPage(SearchLivePlayBackDto dto)
|
||||
{
|
||||
var deptments = await _cacheDomain.GetDeptments();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var query = from a in dncmsbaseRepository.GetRepository<ZhiboSystemSchedulesPlayback>().Query()
|
||||
.Include(x => x.LiveAuditLogPlayBack)
|
||||
.ThenInclude(x => x.CMS_LiveAuditLog)
|
||||
.Where(m => m.scheduleid == dto.schedulesId && m.zbdate > limitDate && m.status == 1)
|
||||
.If(dto.stime.HasValue, x => x.Where(x => x.ctime >= dto.stime))
|
||||
.If(dto.etime.HasValue, x => x.Where(x => x.ctime <= dto.etime))
|
||||
.If(dto.LiveAuditStatus.HasValue && dto.LiveAuditStatus == (int)LiveAuditStatus.违规, x => x.Where(n => n.LiveAuditLogPlayBack.Any(x => x.CMS_LiveAuditLog.auditStatus == LiveAuditStatus.违规)))
|
||||
.If(dto.LiveAuditStatus.HasValue && dto.LiveAuditStatus == (int)LiveAuditStatus.审核通过, x => x.Where(n => !n.LiveAuditLogPlayBack.Any(x => x.CMS_LiveAuditLog.auditStatus == LiveAuditStatus.违规) && n.LiveAuditLogPlayBack.Any(x => x.CMS_LiveAuditLog.auditStatus == LiveAuditStatus.审核通过)))
|
||||
.If(dto.LiveAuditStatus.HasValue && dto.LiveAuditStatus == (int)LiveAuditStatus.已整改, x => x.Where(n => n.LiveAuditLogPlayBack.All(x => x.CMS_LiveAuditLog.auditStatus == LiveAuditStatus.已整改)))
|
||||
.If(dto.LiveAuditStatus.HasValue && dto.LiveAuditStatus == (int)LiveAuditStatus.待审核, x => x.Where(n => !n.LiveAuditLogPlayBack.Any()))
|
||||
|
||||
select new LiveAuditPlayBack
|
||||
{
|
||||
pbid = a.id,
|
||||
scheduleid = a.scheduleid,
|
||||
title = a.title,
|
||||
thumb = a.thumb,
|
||||
intro = a.intro,
|
||||
ctime = a.ctime,
|
||||
url = a.url,
|
||||
recordid = a.recordid,
|
||||
status = a.status,
|
||||
istop = a.istop,
|
||||
zbdate = a.zbdate
|
||||
};
|
||||
var total = await query.CountAsync();
|
||||
var data = await query.OrderByDescending(x => x.ctime)
|
||||
.Skip((dto.PageIndex - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.ToListAsync();
|
||||
//判断回放记录当前状态
|
||||
var lpbids = data.Select(m => m.pbid).ToList();
|
||||
var mylpb = dncmsbaseRepository.GetRepository<LiveAuditLogPlayBack>().Query().Where(m => lpbids.Contains(m.playBackId)).ToList();//关系数据
|
||||
var lpbGupLogid = mylpb.GroupBy(m => m.logId).ToDictionary(m => m.Key, n => n);
|
||||
var myLog = dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().Query().Where(m => lpbGupLogid.Select(i => i.Key).Contains(m.id)).ToList();
|
||||
//处理 回放记录状态
|
||||
foreach (var item in data)
|
||||
{
|
||||
var lpb = mylpb.Where(m => m.playBackId == item.pbid);//
|
||||
//没有审核记录
|
||||
if (!lpb.Any()) item.auditStatus = LiveAuditStatus.待审核;
|
||||
else
|
||||
{
|
||||
var log = myLog.Where(m => lpb.Select(n => n.logId).Contains(m.id));//我的审核日志
|
||||
if (log.Any(m => m.auditStatus == LiveAuditStatus.违规))
|
||||
{
|
||||
item.auditStatus = LiveAuditStatus.违规;
|
||||
}
|
||||
else if (log.Any(m => m.auditStatus == LiveAuditStatus.审核通过))
|
||||
{
|
||||
item.auditStatus = LiveAuditStatus.审核通过;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.auditStatus = LiveAuditStatus.已整改;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PageResult<LiveAuditPlayBack>(dto.PageIndex, dto.PageSize, total, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回放审核记录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PageResult<PlayBackAuditLog>> GetPlayBackAuditLogPage(SearchPlayBackAuditLogDto dto)
|
||||
{
|
||||
var deptments = await _cacheDomain.GetDeptments();
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var query = from a in dncmsbaseRepository.GetRepository<LiveAuditLogPlayBack>().Query().Where(m => m.playBackId == dto.playBackId)
|
||||
join b in dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().Query() on a.logId equals b.id into lapb
|
||||
from pb in lapb.DefaultIfEmpty()
|
||||
select new PlayBackAuditLog
|
||||
{
|
||||
playBackId = a.playBackId,
|
||||
schedulesId = pb.schedulesId,
|
||||
auditStatus = pb.auditStatus,
|
||||
rejectReason = pb.rejectReason,
|
||||
auditRemark = pb.auditRemark,
|
||||
auditAccessory = pb.auditAccessory,
|
||||
creater = pb.creater,
|
||||
ctime = pb.ctime,
|
||||
solver = pb.solver,
|
||||
solveTime = pb.solveTime,
|
||||
solveRemark = pb.solveRemark,
|
||||
solveAccessory = pb.solveAccessory
|
||||
};
|
||||
|
||||
var total = await query.CountAsync();
|
||||
var data = await query.OrderByDescending(x => x.ctime)
|
||||
.Skip((dto.PageIndex - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return new PageResult<PlayBackAuditLog>(dto.PageIndex, dto.PageSize, total, data);
|
||||
}
|
||||
|
||||
public async Task AddLiveAuditLog(AddLiveAuditDto dto)
|
||||
{
|
||||
if (dto.AuditStatus != LiveAuditStatus.违规 && dto.AuditStatus != LiveAuditStatus.审核通过)
|
||||
{
|
||||
throw new ApiException("只接受:违规和合规!");
|
||||
}
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var pbids = dto.playBackIds.Split(',').Select(x => int.Parse(x.Trim())).ToList();
|
||||
if (!pbids.Any())
|
||||
{
|
||||
throw new ApiException("请选择审核录像!");
|
||||
}
|
||||
CMS_LiveAuditLog log = new CMS_LiveAuditLog();
|
||||
log.auditRemark = dto.AuditRemark;
|
||||
log.auditAccessory = dto.AuditAccessory;
|
||||
log.auditStatus = LiveAuditStatus.违规;
|
||||
log.rejectReason = dto.RejectReason;
|
||||
log.schedulesId = dto.SchedulesId;
|
||||
log.creater = dto.Operator;
|
||||
log.ctime = DateTime.Now;
|
||||
log.auditStatus = dto.AuditStatus;
|
||||
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().InsertAsync(log);
|
||||
List<LiveAuditLogPlayBack> pblist = pbids.Select(m => new LiveAuditLogPlayBack() { logId = log.id, playBackId = m }).ToList();
|
||||
await dncmsbaseRepository.GetRepository<LiveAuditLogPlayBack>().BatchInsertAsync(pblist);
|
||||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SolveLiveAudit(SolveLiveAuditDto dto)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
|
||||
var data = await dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().Query()
|
||||
.FirstOrDefaultAsync(x => x.id == dto.logId) ?? throw new ApiException("审核记录不存在或已删除!");
|
||||
|
||||
data.solveAccessory = dto.SolveAccessory;
|
||||
data.solver = dto.Operator;
|
||||
data.solveRemark = dto.SolveRemark;
|
||||
data.solveTime = DateTime.Now;
|
||||
data.auditStatus = LiveAuditStatus.已整改;
|
||||
|
||||
using var transaction = await dncmsbaseRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await dncmsbaseRepository.GetRepository<CMS_LiveAuditLog>().UpdateAsync(data);
|
||||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetWeeksName(string weeks)
|
||||
{
|
||||
if (string.IsNullOrEmpty(weeks)) return "";
|
||||
|
||||
string str = "";
|
||||
string[] s = Regex.Split(weeks, @",", RegexOptions.IgnoreCase);
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s[i])) continue;
|
||||
str += Enum.GetName(typeof(WeeksEnum), Convert.ToInt32(s[i])) + ",";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
#endregion 直播审核2
|
||||
|
||||
public async Task CreateLiveAuditRectification(CreateLiveAuditRectificationDto dto)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var data = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.FirstOrDefaultAsync(x => x.Id == dto.AuditId) ?? throw new ApiException("审核记录不存在或已删除!");
|
||||
|
||||
data.AuditStatus = LiveAuditStatus.已整改;
|
||||
|
||||
var log = _mapper.Map<CreateLiveAuditRectificationDto, LiveAuditLog>(dto);
|
||||
|
||||
log.Ctime = DateTime.Now;
|
||||
log.Schedule = data.Schedule;
|
||||
log.StarTime = data.StarTime;
|
||||
log.AuditStatus = data.AuditStatus;
|
||||
log.LiveId = data.LiveId;
|
||||
|
||||
using var transaction = await hgActionRepository.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
await hgActionRepository.GetRepository<LiveAudit>().UpdateAsync(data, x => new
|
||||
{
|
||||
x.AuditStatus,
|
||||
x.AuditTime,
|
||||
x.Auditer
|
||||
});
|
||||
await hgActionRepository.GetRepository<LiveAuditLog>().InsertAsync(log);
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
await transaction.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public List<SelectItem> GetRejectReasonSelect()
|
||||
{
|
||||
var result = new List<SelectItem>();
|
||||
foreach (LiveAuditRejectReason item in Enum.GetValues(typeof(LiveAuditRejectReason)))
|
||||
{
|
||||
result.Add(new SelectItem(item, item.GetDescription()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<SelectItem> GetAuditStatusSelect()
|
||||
{
|
||||
var result = new List<SelectItem>();
|
||||
foreach (LiveAuditStatus item in Enum.GetValues(typeof(LiveAuditStatus)))
|
||||
{
|
||||
result.Add(new SelectItem(item, item.GetDescription()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<SelectItem>> GetPlatformSelect()
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var result = await dncmsbaseRepository.GetRepository<LivePlatform>().Query()
|
||||
.Select(x => new SelectItem(x.Id, x.Platform))
|
||||
.ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<LiveAuditDetailDto> GetLiveAuditDetail(int auditId)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var data = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.FirstOrDefaultAsync(x => x.Id == auditId) ?? throw new ApiException("审核记录不存在或已删除!");
|
||||
|
||||
var log = await hgActionRepository.GetRepository<LiveAuditLog>().Query()
|
||||
.OrderByDescending(x => x.Ctime)
|
||||
.FirstOrDefaultAsync(x => x.AuditId == auditId && x.AuditStatus == LiveAuditStatus.已整改);
|
||||
|
||||
var result = new LiveAuditDetailDto()
|
||||
{
|
||||
AuditStatus = data.AuditStatus,
|
||||
Id = auditId,
|
||||
LiveRoomInfo = data.LiveRoomInfo,
|
||||
LiveUrl = data.LiveUrl,
|
||||
RectificationAccessory = log?.RectificationAccessory,
|
||||
RectificationRemark = log?.RectificationRemark,
|
||||
LiveDate = data.LiveDate,
|
||||
ScheduleId = data.ScheduleId,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步直播数据到审核数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task SyncLiveData()
|
||||
{
|
||||
await CreateOrUpdateLiveInfo();
|
||||
var now = DateTime.Now;
|
||||
var date = now.ToString("yyyy-MM-dd");
|
||||
var week = now.DayOfWeek.ToString("d");
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var data = new List<LiveAudit>();
|
||||
// 固化数据
|
||||
if (!await hgActionRepository.GetRepository<LiveAudit>().Query().AnyAsync(x => x.LiveDate == date))
|
||||
{
|
||||
data = await (from a in dncmsbaseRepository.GetRepository<ZhiboSystemSchedules>().Query()
|
||||
join b in dncmsbaseRepository.GetRepository<ZhiboSystemSchedulesToRoom>().Query() on a.Id equals b.Scheduleid into temAB
|
||||
from b in temAB.DefaultIfEmpty()
|
||||
join c in dncmsbaseRepository.GetRepository<ZhiboSystemRoom>().Query() on b.Roomid equals c.Id into temBC
|
||||
from c in temBC.DefaultIfEmpty()
|
||||
where a.Status == 1 && a.Weeks.Contains(week) && c.Status == 1
|
||||
select new LiveAudit
|
||||
{
|
||||
Deptid = int.Parse(a.Dept),
|
||||
LiveDate = date,
|
||||
Ctime = now,
|
||||
ScheduleId = a.Id,
|
||||
Schedule = a.Title,
|
||||
LiveId = c.Id,
|
||||
Liver = a.Lecturer,
|
||||
LiveRoomInfo = JsonHelper.ToJson(new { name = c.Title }),
|
||||
StarTime = DateTime.Parse($"{date} {a.Starttime}"),
|
||||
EndTime = DateTime.Parse($"{date} {a.Endtime}"),
|
||||
LiveUrl = $"https://app.hc.dn8188.com/zhibo.html?roomid={c.Id}&agenttype=2"
|
||||
}).ToListAsync();
|
||||
|
||||
await CreateLiveAudits(data, now);
|
||||
return;
|
||||
}
|
||||
|
||||
var source = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.Where(x => x.LiveDate == date)
|
||||
.ToListAsync();
|
||||
var liveids = source.Select(x => x.LiveId).ToList();
|
||||
|
||||
data = await (from a in dncmsbaseRepository.GetRepository<ZhiboSystemSchedules>().Query()
|
||||
join b in dncmsbaseRepository.GetRepository<ZhiboSystemSchedulesToRoom>().Query() on a.Id equals b.Scheduleid into temAB
|
||||
from b in temAB.DefaultIfEmpty()
|
||||
join c in dncmsbaseRepository.GetRepository<ZhiboSystemRoom>().Query() on b.Roomid equals c.Id into temBC
|
||||
from c in temBC.DefaultIfEmpty()
|
||||
where a.Status == 1 && a.Weeks.Contains(week) && c.Status == 1
|
||||
select new LiveAudit
|
||||
{
|
||||
Deptid = int.Parse(a.Dept),
|
||||
LiveDate = date,
|
||||
Ctime = now,
|
||||
ScheduleId = a.Id,
|
||||
Schedule = a.Title,
|
||||
LiveId = c.Id,
|
||||
Liver = a.Lecturer,
|
||||
LiveRoomInfo = JsonHelper.ToJson(new { name = c.Title }),
|
||||
StarTime = DateTime.Parse($"{date} {a.Starttime}"),
|
||||
EndTime = DateTime.Parse($"{date} {a.Endtime}"),
|
||||
LiveUrl = $"https://app.hc.dn8188.com/zhibo.html?roomid={c.Id}&agenttype=2"
|
||||
}).ToListAsync();
|
||||
|
||||
// 差异新增
|
||||
if (data.Any(x => !liveids.Contains(x.LiveId)))
|
||||
{
|
||||
await CreateLiveAudits(data.Where(x => !liveids.Contains(x.LiveId)).ToList(), now);
|
||||
}
|
||||
|
||||
// 差异修改
|
||||
if (data.Any(x => liveids.Contains(x.LiveId)))
|
||||
{
|
||||
await UpdateLiveAudits(data, source);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建直播审核数据
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="now"></param>
|
||||
/// <returns></returns>
|
||||
private async Task CreateLiveAudits(List<LiveAudit> data, DateTime now)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var lecturerids = GetLecturerids(data);
|
||||
var lecturers = await dncmsbaseRepository.GetRepository<Lecturer>().Query()
|
||||
.Where(x => lecturerids.Contains(x.Id))
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.Title
|
||||
}).ToListAsync();
|
||||
var liveids = data.Select(x => x.LiveId).Distinct().ToList();
|
||||
var sourceData = await hgActionRepository.GetRepository<LiveAudit>().Query()
|
||||
.Where(x => x.LiveDate == now.AddDays(-1).ToString("yyyy-MM-dd") && liveids.Contains(x.LiveId))
|
||||
.Select(x => new
|
||||
{
|
||||
x.LiveId,
|
||||
x.AuditStatus,
|
||||
x.AuditTime,
|
||||
x.Auditer
|
||||
}).ToListAsync();
|
||||
var platform = await dncmsbaseRepository.GetRepository<LivePlatform>().Query().FirstAsync();
|
||||
foreach (var item in data)
|
||||
{
|
||||
var livers = item.Liver.Split(',').Select(x => int.Parse(x)).ToList();
|
||||
item.Liver = string.Join(",", lecturers.Where(x => livers.Contains(x.Id)).Select(x => x.Title).ToList());
|
||||
var source = sourceData.FirstOrDefault(x => x.LiveId == item.LiveId);
|
||||
item.PlatformId = platform.Id;
|
||||
item.Platform = platform.Platform;
|
||||
item.AuditStatus = LiveAuditStatus.待审核;
|
||||
}
|
||||
|
||||
await hgActionRepository.GetRepository<LiveAudit>().BatchInsertAsync(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新直播审核数据
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
private async Task UpdateLiveAudits(List<LiveAudit> data, List<LiveAudit> source)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var lecturerids = GetLecturerids(data);
|
||||
var lecturers = await dncmsbaseRepository.GetRepository<Lecturer>().Query()
|
||||
.Where(x => lecturerids.Contains(x.Id))
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.Title
|
||||
}).ToListAsync();
|
||||
foreach (var item in data)
|
||||
{
|
||||
var livers = item.Liver.Split(',').Select(x => int.Parse(x)).ToList();
|
||||
item.Liver = string.Join(",", lecturers.Where(x => livers.Contains(x.Id)).Select(x => x.Title).ToList());
|
||||
}
|
||||
var editData = new List<LiveAudit>();
|
||||
foreach (var sourceItem in source)
|
||||
{
|
||||
var item = data.FirstOrDefault(x => x.LiveId == sourceItem.LiveId);
|
||||
if (item != null && (sourceItem.EndTime != item.EndTime
|
||||
|| sourceItem.StarTime != item.StarTime
|
||||
|| sourceItem.Liver != item.Liver
|
||||
|| sourceItem.LiveRoomInfo != item.LiveRoomInfo))
|
||||
{
|
||||
item.StarTime = sourceItem.StarTime;
|
||||
item.EndTime = sourceItem.EndTime;
|
||||
item.Liver = sourceItem.Liver;
|
||||
item.LiveRoomInfo = sourceItem.LiveRoomInfo;
|
||||
editData.Add(item);
|
||||
}
|
||||
}
|
||||
// 差异修改
|
||||
if (editData.Any())
|
||||
{
|
||||
await hgActionRepository.GetRepository<LiveAudit>().BatchUpdateAsync(editData, x => new
|
||||
{
|
||||
x.StarTime,
|
||||
x.EndTime,
|
||||
x.Liver,
|
||||
x.LiveRoomInfo
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取老师id
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
private static List<int> GetLecturerids(List<LiveAudit> data)
|
||||
{
|
||||
var lecturerids = new List<int>();
|
||||
var lectureridList = data.Select(y => y.Liver.Split(',').Select(x => int.Parse(x)).ToList()).ToList();
|
||||
foreach (var lecturerid in lectureridList)
|
||||
{
|
||||
lecturerids.AddRange(lecturerid);
|
||||
}
|
||||
lecturerids = lecturerids.Distinct().ToList();
|
||||
return lecturerids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步直播数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task CreateOrUpdateLiveInfo()
|
||||
{
|
||||
using var scope = _serviceProvider.CreateAsyncScope();
|
||||
var hgActionRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<HgAtionDbContext>>();
|
||||
var dncmsbaseRepository = scope.ServiceProvider.GetRequiredService<IBaseRepository<DncmsbaseDbContext>>();
|
||||
var platform = await dncmsbaseRepository.GetRepository<LivePlatform>().Query().FirstAsync();
|
||||
|
||||
var lives = await hgActionRepository.GetRepository<LiveInfo>().Query().ToListAsync();
|
||||
|
||||
var query = from a in dncmsbaseRepository.GetRepository<ZhiboSystemSchedules>().Query()
|
||||
join b in dncmsbaseRepository.GetRepository<ZhiboSystemSchedulesToRoom>().Query() on a.Id equals b.Scheduleid into temAB
|
||||
from b in temAB.DefaultIfEmpty()
|
||||
join c in dncmsbaseRepository.GetRepository<ZhiboSystemRoom>().Query() on b.Roomid equals c.Id into temBC
|
||||
from c in temBC.DefaultIfEmpty()
|
||||
where a.Status == 1 && c.Status == 1
|
||||
select new LiveInfo
|
||||
{
|
||||
LiveId = c.Id,
|
||||
Deptid = int.Parse(a.Dept),
|
||||
ScheduleId = a.Id,
|
||||
Schedule = a.Title,
|
||||
Liver = a.Lecturer,
|
||||
LiveUrl = $"https://app.hc.dn8188.com/zhibo.html?roomid={c.Id}&agenttype=2",
|
||||
PlatformId = platform.Id,
|
||||
Platform = platform.Platform,
|
||||
LiveTitle = c.Title,
|
||||
Ctime = DateTime.Now,
|
||||
};
|
||||
|
||||
var data = await query.If(lives.Any(), x => x.Where(x => !lives.Select(y => y.LiveId).Contains(x.LiveId)))
|
||||
.ToListAsync();
|
||||
|
||||
if (data.Any())
|
||||
{
|
||||
await hgActionRepository.GetRepository<LiveInfo>().BatchInsertAsync(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace Hg.Complaint.WebApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class BaseController : ControllerBase
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Hg.Complaint.WebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 投诉处理
|
||||
/// </summary>
|
||||
[ApiSignatureFilterForbid]
|
||||
public class ComplaintController : BaseController
|
||||
{
|
||||
private readonly IComplaintDomain _complaintDomain;
|
||||
|
||||
/// <summary>
|
||||
/// 投诉处理
|
||||
/// </summary>
|
||||
/// <param name="complaintDomain"></param>
|
||||
public ComplaintController(IComplaintDomain complaintDomain)
|
||||
{
|
||||
_complaintDomain = complaintDomain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投诉申请接口
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("apply")]
|
||||
public async Task<bool> ApplyComplaint([FromBody] ApplyComplaintDto dto)
|
||||
{
|
||||
return await _complaintDomain.ApplyComplaint(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取队列信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Queues")]
|
||||
public async Task<List<ComplaintLogMessageDto>> GetQueues()
|
||||
=> await _complaintDomain.GetQueues();
|
||||
|
||||
/// <summary>
|
||||
/// 获取投诉申请分页
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Page")]
|
||||
public async Task<PageResult<ComplaintDto>> GetPage([FromQuery] SearchComplaintDto dto, [FromHeader] string? appid)
|
||||
=> await _complaintDomain.GetPage(dto, appid);
|
||||
|
||||
/// <summary>
|
||||
/// 重新发起队列
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("SyncQueue")]
|
||||
public async Task<List<ComplaintLogMessageDto>> SyncQueue()
|
||||
=> await _complaintDomain.SyncQueue();
|
||||
|
||||
/// <summary>
|
||||
/// 获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Detail")]
|
||||
public async Task<ComplaintDetailDto> GetComplaintDetail(int id)
|
||||
=> await _complaintDomain.GetComplaintDetail(id);
|
||||
|
||||
/// <summary>
|
||||
/// 根据资源id和业务线获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="resid"></param>
|
||||
/// <param name="deptid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("DetailByRes")]
|
||||
public async Task<ComplaintDetailDto> GetComplaintDetail(string? resid, int deptid)
|
||||
=> await _complaintDomain.GetComplaintDetail(resid, deptid);
|
||||
|
||||
/// <summary>
|
||||
/// 根据appid和业务线获取投诉详情
|
||||
/// </summary>
|
||||
/// <param name="appid"></param>
|
||||
/// <param name="appuserid"></param>
|
||||
/// <param name="deptid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("DetailByAppid")]
|
||||
public async Task<ComplaintDetailDto> GetComplaintDetail(string? appid, string? appuserid, int deptid)
|
||||
=> await _complaintDomain.GetComplaintDetail(appid, appuserid, deptid);
|
||||
|
||||
/// <summary>
|
||||
/// 更新投诉状态
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("Status")]
|
||||
public async Task<bool> UpdateComplaintStatus([FromBody] UpdateComplaintStatusDto dto, [FromHeader] string? appid)
|
||||
=> await _complaintDomain.UpdateComplaintStatus(dto, appid);
|
||||
|
||||
/// <summary>
|
||||
/// 获取投诉状态
|
||||
/// </summary>
|
||||
/// <param name="udid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("StatusDetail")]
|
||||
public async Task<ComplainStatusModel> GetComplaintStatus(int udid)
|
||||
{
|
||||
return await _complaintDomain.GetComplaintStatus(udid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记客户
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("MarkCustomer")]
|
||||
public async Task<bool> MarkCustomer([FromBody] MarkCustomerDto dto)
|
||||
{
|
||||
return await _complaintDomain.MarkCustomer(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量分配客户给客服
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="appid"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("BatchAssign")]
|
||||
public async Task<bool> BatchAssignComplaint([FromBody] BatchAssignComplaintDto dto, [FromHeader] string? appid)
|
||||
{
|
||||
return await _complaintDomain.BatchAssignComplaint(dto, appid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记水军
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("MarkTrolls")]
|
||||
public async Task<bool> MarkTrolls([FromBody] MarkTrollsDto dto)
|
||||
{
|
||||
return await _complaintDomain.MarkTrolls(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取潜在风险用户标签
|
||||
/// </summary>
|
||||
/// <param name="resId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Label")]
|
||||
public async Task<int> ComplaintLabel([Required(ErrorMessage = "请输入客户ID")] string resId)
|
||||
{
|
||||
return await _complaintDomain.ComplaintLabel(resId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Hg.Complaint.WebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 直播审核
|
||||
/// </summary>
|
||||
[ApiSignatureFilterForbid]
|
||||
public class LiveAuditController : BaseController
|
||||
{
|
||||
private readonly ILiveAuditDomain _liveAuditDomain;
|
||||
|
||||
#region 直播审核 1.0
|
||||
/// <summary>
|
||||
/// 直播审核
|
||||
/// </summary>
|
||||
/// <param name="liveAuditDomain"></param>
|
||||
public LiveAuditController(ILiveAuditDomain liveAuditDomain)
|
||||
{
|
||||
_liveAuditDomain = liveAuditDomain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直播审核统计分页
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("live/page")]
|
||||
public async Task<PageResult<LiveInfoDto>> GetLivePage([FromQuery] SearchLiveDto dto)
|
||||
{
|
||||
return await _liveAuditDomain.GetLivePage(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直播审核
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("page")]
|
||||
public async Task<PageResult<LiveAuditDto>> GetLiveAuditPage([FromQuery] SearchLiveAuditDto dto)
|
||||
{
|
||||
return await _liveAuditDomain.GetLiveAuditPage(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直播审核日志
|
||||
/// </summary>
|
||||
/// <param name="auditId"></param>
|
||||
/// <param name="date"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("logs")]
|
||||
public async Task<List<LiveAuditLogDto>> GetLiveAuditLogs([Required] int auditId, [Required] string? date)
|
||||
{
|
||||
return await _liveAuditDomain.GetLiveAuditLogs(auditId, date);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加审核记录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("audit")]
|
||||
public async Task CreateLiveAudit([FromBody] CreateLiveAuditDto dto)
|
||||
{
|
||||
await _liveAuditDomain.CreateLiveAudit(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加整改记录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("rectification")]
|
||||
public async Task CreateLiveAuditRectification([FromBody] CreateLiveAuditRectificationDto dto)
|
||||
{
|
||||
await _liveAuditDomain.CreateLiveAuditRectification(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 驳回理由选项
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("select/reason")]
|
||||
public List<SelectItem> GetRejectReasonSelect()
|
||||
{
|
||||
return _liveAuditDomain.GetRejectReasonSelect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态选项
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("select/status")]
|
||||
public List<SelectItem> GetAuditStatusSelect()
|
||||
{
|
||||
return _liveAuditDomain.GetAuditStatusSelect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取直播平台选项
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("select/platform")]
|
||||
public async Task<List<SelectItem>> GetPlatformSelect()
|
||||
{
|
||||
return await _liveAuditDomain.GetPlatformSelect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取审核明细
|
||||
/// </summary>
|
||||
/// <param name="auditId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("detail")]
|
||||
public async Task<LiveAuditDetailDto> GetLiveAuditDetail([Required] int auditId)
|
||||
{
|
||||
return await _liveAuditDomain.GetLiveAuditDetail(auditId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 直播审核统计分页
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("live/schedulePage")]
|
||||
public async Task<PageResult<LiveAuditSchedules>> GetLiveSchedulePage([FromQuery] SearchLiveScheduleDto dto)
|
||||
{
|
||||
return await _liveAuditDomain.GetLiveSchedulePage(dto);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加违规记录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("addAudit")]
|
||||
public async Task AddAudit([FromBody] AddLiveAuditDto dto)
|
||||
{
|
||||
await _liveAuditDomain.AddLiveAuditLog(dto);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解决违规
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("solveAudit")]
|
||||
public async Task SolveAudit([FromBody] SolveLiveAuditDto dto)
|
||||
{
|
||||
await _liveAuditDomain.SolveLiveAudit(dto);
|
||||
}
|
||||
/// <summary>
|
||||
/// 直播回放
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("live/playBackPage")]
|
||||
public async Task<PageResult<LiveAuditPlayBack>> GetLivePlayBackPage([FromQuery] SearchLivePlayBackDto dto)
|
||||
{
|
||||
return await _liveAuditDomain.GetLivePlayBackPage(dto);
|
||||
}
|
||||
/// <summary>
|
||||
/// 回放审核记录
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("live/playBacklogPage")]
|
||||
public async Task<PageResult<PlayBackAuditLog>> GetBackAuditLogPage([FromQuery] SearchPlayBackAuditLogDto dto)
|
||||
{
|
||||
return await _liveAuditDomain.GetPlayBackAuditLogPage(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#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/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
#设置时间为中国上海
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# 设置包源为阿里
|
||||
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \
|
||||
&& apt-get clean
|
||||
|
||||
# 安装 tzdata 软件包
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y tzdata \
|
||||
&& ln -fs /usr/share/zoneinfo/$TZ /etc/localtime \
|
||||
&& rm -rf /var/lib/apt/lists/ \
|
||||
&& dpkg-reconfigure -f noninteractive tzdata
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["Hg.Complaint.WebApi/Hg.Complaint.WebApi.csproj", "Hg.Complaint.WebApi/"]
|
||||
COPY ["Hg.Complaint.Domain/Hg.Complaint.Domain.csproj", "Hg.Complaint.Domain/"]
|
||||
COPY ["Hg.Core.EntityFramework/Hg.Core.EntityFramework.csproj", "Hg.Core.EntityFramework/"]
|
||||
COPY ["Hg.Core.Entity/Hg.Core.Entity.csproj", "Hg.Core.Entity/"]
|
||||
COPY ["Hg.Core.Shared/Hg.Core.Shared.csproj", "Hg.Core.Shared/"]
|
||||
RUN dotnet restore "Hg.Complaint.WebApi/Hg.Complaint.WebApi.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/Hg.Complaint.WebApi"
|
||||
RUN dotnet build "Hg.Complaint.WebApi.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "Hg.Complaint.WebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "Hg.Complaint.WebApi.dll"]
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>24a88d5e-8b6a-403a-a290-9c54069b6af2</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="appsettings.Production.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Hg.Complaint.Domain\Hg.Complaint.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="DG.EntityFramework" />
|
||||
<Using Include="DG.Core" />
|
||||
<Using Include="DG.Redis" />
|
||||
<Using Include="Hg.Complaint.Domain" />
|
||||
<Using Include="Hg.Complaint.Domain.Impl" />
|
||||
<Using Include="Hg.Core.EntityFramework" />
|
||||
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="Microsoft.AspNetCore.Mvc" />
|
||||
<Using Include="Hg.Complaint.Domain.Config" />
|
||||
<Using Include="Exceptionless" />
|
||||
<Using Include="Hg.Complaint.Domain.Dto" />
|
||||
<Using Include="Hg.Complaint.WebApi.Workers" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
using Hg.Complaint.WebApi.workers;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
|
||||
try
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("Serilog.json")
|
||||
.AddJsonFile($"Serilog.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
|
||||
.Build();
|
||||
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(configuration)
|
||||
.WriteTo.Exceptionless(builder.Configuration.GetValue<string>("Exceptionless:ApiKey"), builder.Configuration.GetValue<string>("Exceptionless:ServerUrl"), new string[] { "hg-complaint-webapi" })
|
||||
.CreateLogger();
|
||||
Log.Logger = logger;
|
||||
builder.Services.AddLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddSerilog(logger);
|
||||
});
|
||||
// Add services to the container.
|
||||
builder.Services.AddDGEntityFramework<ZxdDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(builder.Configuration.GetConnectionString("zxdcrm"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("zxdcrm")));
|
||||
});
|
||||
builder.Services.AddDGEntityFramework<CrmDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(builder.Configuration.GetConnectionString("crm"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("crm")));
|
||||
});
|
||||
builder.Services.AddDGEntityFramework<HgAtionDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(builder.Configuration.GetConnectionString("hgaction"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("hgaction")));
|
||||
});
|
||||
builder.Services.AddDGEntityFramework<DncmsbaseDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(builder.Configuration.GetConnectionString("dncmsbase"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("dncmsbase")));
|
||||
});
|
||||
builder.Services.AddDGEntityFramework<UserCenterDbContext>(options =>
|
||||
{
|
||||
options.UseMySql(builder.Configuration.GetConnectionString("usercenter"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("usercenter")));
|
||||
});
|
||||
builder.Services.AddRedis(builder.Configuration);
|
||||
builder.Services
|
||||
.AddAutoIoc(typeof(IScopedDependency), LifeCycle.Scoped)
|
||||
.AddAutoIoc(typeof(ISingletonDependency), LifeCycle.Singleton)
|
||||
.AddAutoIoc(typeof(ITransientDependency), LifeCycle.Transient)
|
||||
.AddMapper();
|
||||
builder.Services.AddCors(option =>
|
||||
{
|
||||
option.AddPolicy(MyAllowSpecificOrigins,
|
||||
policy =>
|
||||
{
|
||||
policy.AllowAnyOrigin()
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
builder.Services.AddExceptionless(builder.Configuration);
|
||||
builder.Services.AddResponseCompression(opts => //添加压缩中间件服务
|
||||
{
|
||||
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
|
||||
new[] { "application/octet-stream" });
|
||||
})
|
||||
.AddControllers()
|
||||
.AddApiResult()
|
||||
.AddApiSignature()
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(new JsonOptionsExtensions());
|
||||
});
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
|
||||
{
|
||||
Version = "v1",
|
||||
Title = "HG COMPLAINT API",
|
||||
Description = "HG COMPLAINT API"
|
||||
});
|
||||
var xmlFilename = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Hg.Complaint.Domain.xml"));
|
||||
});
|
||||
builder.Services.AddDGHttpClient();
|
||||
//if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != "PreProduction")
|
||||
//{
|
||||
// builder.Services.AddHostedService<ComplaintMessageWorker>();
|
||||
// builder.Services.AddHostedService<NegativeMessageWorker>();
|
||||
//}
|
||||
builder.Services.AddSingleton<ComplaintEventSingleton>();
|
||||
builder.Services.AddHostedService<DueComplaintWorker>();
|
||||
builder.Services.AddHostedService<ComplaintMessageWorker>();
|
||||
builder.Services.AddHostedService<NegativeMessageWorker>();
|
||||
builder.Services.AddHostedService<LiveDataWorker>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment() || Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "PreProduction")
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
//app.UseHttpLogging();
|
||||
}
|
||||
app.UseCors(MyAllowSpecificOrigins);
|
||||
app.UseHttpsRedirection();
|
||||
app.UseExceptionless();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Hg.Complaint.WebApi": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "https://localhost:7263;http://localhost:5174"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||
"environmentVariables": {},
|
||||
"publishAllPorts": true,
|
||||
"useSSL": true,
|
||||
"httpPort": 5261,
|
||||
"sslPort": 5262
|
||||
}
|
||||
},
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:43953",
|
||||
"sslPort": 44321
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.AspNetCore" ],
|
||||
"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", "Serilog.AspNetCore" ],
|
||||
"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,162 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=zxdcrm;user id=qianbenjie;password=Hcqianbenjie@123;Old Guids=true;SslMode=None",
|
||||
"crm": "Data Source=mysql98ff96c3dffa.rds.ivolces.com;Port=3306;Initial Catalog=db_crm;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",
|
||||
"hgaction": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=hgaction;user id=hguser;password=nH5L$&Hxxco;SslMode=None",
|
||||
"usercenter": "Data Source=pc-wz927dkkv6y71jao7.rwlb.rds.aliyuncs.com;Port=3306;Initial Catalog=usercenter;user id=hguser;password=nH5L$&Hxxco;SslMode=None"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.11.9:5000",
|
||||
"ApiKey": "3j2K4Vew67kXOjwuZN2C5KG3Ca5SLo6YSZ9fWVJI"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "172.18.11.77:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
},
|
||||
{
|
||||
"Host": "172.18.11.76:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
},
|
||||
{
|
||||
"Host": "172.18.11.75:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
}
|
||||
],
|
||||
"SystemConfig": {
|
||||
"Appid": "qt_compliance",
|
||||
"AppSecret": "AdC+vVj58wG48swyjyW2WM6aC6CxYNKt8pP0c8sdozs=",
|
||||
"SsoUrl": "http://conf.soft.dn8188.com",
|
||||
"ZxdUrl": "http://centerapi.soft.dn8188.com",
|
||||
"ZxdCoreUrl": "http://120.77.165.155:8089",
|
||||
"CrmUrl": "http://api.crm.tcfortune.com:8282",
|
||||
"SsoOrganizationUrl": "/v1/api/open/data/sync/organization",
|
||||
"UserCenterRiaServiceUrl": "https://contract.soft.dn8188.com",
|
||||
"PreviewUrl": "/v1/api/certification/idcard/image/preview/",
|
||||
"AuditUrl": "/v1/api/certification/idcard/image/audit",
|
||||
"Riskinfo": "/v1/api/h5/get_riskinfo",
|
||||
"ContractStatus": "/v1/api/contract/update/contract/status",
|
||||
"ClientKey": [
|
||||
{
|
||||
"Id": "UPWEBSITE",
|
||||
"Name": "UP网站",
|
||||
"AccessKey": "1622a92d"
|
||||
},
|
||||
{
|
||||
"Id": "TDORDERSITE",
|
||||
"Name": "订单接口",
|
||||
"AccessKey": "622a92d1"
|
||||
},
|
||||
{
|
||||
"Id": "UPPRODUCT",
|
||||
"Name": "UP产品端",
|
||||
"AccessKey": "c268a2cd"
|
||||
},
|
||||
{
|
||||
"Id": "gd_crm",
|
||||
"Name": "UPCRM",
|
||||
"AccessKey": "upchina."
|
||||
},
|
||||
{
|
||||
"Id": "nj_crm",
|
||||
"Name": "UPCRM",
|
||||
"AccessKey": "pchina.1"
|
||||
},
|
||||
{
|
||||
"Id": "AYCRM2_CTI",
|
||||
"Name": "CTI",
|
||||
"AccessKey": "ac910f51"
|
||||
}
|
||||
],
|
||||
"ClearCacheUrls": [
|
||||
"http://hg.soft.dn8188.com/cache/clear"
|
||||
],
|
||||
"CompanyList": [
|
||||
{
|
||||
"Code": "QBJZ",
|
||||
"Name": "北京一部",
|
||||
"VideoUrl": "http://bj1rec.crm.tcfortune.com:8282",
|
||||
"WxMessageUrl": "http://1.202.216.226:909"
|
||||
},
|
||||
{
|
||||
"Code": "QBJX",
|
||||
"Name": "北京二部",
|
||||
"VideoUrl": "http://bj2rec.crm.tcfortune.com:8282",
|
||||
"WxMessageUrl": ""
|
||||
},
|
||||
{
|
||||
"Code": "DNZZ",
|
||||
"Name": "东方软件一、二中心",
|
||||
"VideoUrl": "http://120.238.224.24:8098",
|
||||
"WxMessageUrl": "http://120.236.219.28:909"
|
||||
},
|
||||
{
|
||||
"Code": "DNYY",
|
||||
"Name": "东方软件三中心",
|
||||
"VideoUrl": "http://120.238.224.24:38080",
|
||||
"WxMessageUrl": "http://192.168.11.216:909"
|
||||
},
|
||||
{
|
||||
"Code": "SHZZ",
|
||||
"Name": "首华",
|
||||
"VideoUrl": "http://120.238.224.24:28080",
|
||||
"WxMessageUrl": "http://120.238.224.24:4906"
|
||||
},
|
||||
{
|
||||
"Code": "DNG8",
|
||||
"Name": "投顾业务中心",
|
||||
"VideoUrl": "http://120.238.224.24:2080",
|
||||
"WxMessageUrl": "http://120.238.224.24:2909"
|
||||
},
|
||||
{
|
||||
"Code": "DNBB",
|
||||
"Name": "内容二、三中心",
|
||||
"VideoUrl": "",
|
||||
"WxMessageUrl": "http://192.168.11.226:909"
|
||||
},
|
||||
{
|
||||
"Code": "PTD2",
|
||||
"Name": "平台2",
|
||||
"VideoUrl": "http://10.22.11.122",
|
||||
"WxMessageUrl": ""
|
||||
},
|
||||
{
|
||||
"Code": "HGBM",
|
||||
"Name": "合规",
|
||||
"VideoUrl": "http://120.238.224.24:2332",
|
||||
"WxMessageUrl": "http://192.168.11.66:909"
|
||||
}
|
||||
]
|
||||
},
|
||||
"SignConfig": {
|
||||
"AppId": "qt_compliance",
|
||||
"Secret": "AdC+vVj58wG48swyjyW2WM6aC6CxYNKt8pP0c8sdozs="
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "Hg",
|
||||
"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,162 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"zxdcrm": "Server=192.168.11.141;Database=zxdcrm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"crm": "Server=192.168.11.141;Database=db_crm;UserId=tafadmin;Password=tafadmin2017;port=3306;",
|
||||
"dncmsbase": "Server=192.168.11.41;Database=dncmsbase;UserId=root;Password=sa123456.;port=3306;",
|
||||
"hgaction": "Server=192.168.11.41;Database=hgaction;UserId=root;Password=sa123456.;port=3306;",
|
||||
"usercenter": "Server=192.168.11.41;Database=usercenter;UserId=tafadmin;Password=tafadmin2017;port=3306;"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Exceptionless": {
|
||||
"ServerUrl": "http://10.22.12.9:5000",
|
||||
"ApiKey": "BWuxVItUb5KaBwi6AQZ0RFZlRNtiSTWw2p7bjqx0"
|
||||
},
|
||||
"Consumers": [
|
||||
{
|
||||
"Host": "192.168.11.100:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
},
|
||||
{
|
||||
"Host": "192.168.11.101:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
},
|
||||
{
|
||||
"Host": "192.168.11.104:9092",
|
||||
"GroupId": "crm",
|
||||
"Topic": "dwd-negative_kmessage"
|
||||
}
|
||||
],
|
||||
"SystemConfig": {
|
||||
"Appid": "qt_compliance",
|
||||
"AppSecret": "CqlNBxRof0yl7eJM1f4IbOBhgribfooZJ1zwuIj5NzQ=",
|
||||
"SsoUrl": "http://192.168.11.141:24434",
|
||||
"SsoOrganizationUrl": "/v1/api/open/data/sync/organization",
|
||||
"UserCenterRiaServiceUrl": "https://certcontract.wantest.tcfortune.com:11188",
|
||||
"ZxdUrl": "http://192.168.11.81:8087",
|
||||
"ZxdCoreUrl": "http://192.168.11.81:8089",
|
||||
"CrmUrl": "http://192.168.11.81:8088",
|
||||
"PreviewUrl": "/v1/api/certification/idcard/image/preview/",
|
||||
"AuditUrl": "/v1/api/certification/idcard/image/audit",
|
||||
"Riskinfo": "/v1/api/h5/get_riskinfo",
|
||||
"ContractStatus": "/v1/api/contract/update/contract/status",
|
||||
"ClientKey": [
|
||||
{
|
||||
"Id": "UPWEBSITE",
|
||||
"Name": "UP网站",
|
||||
"AccessKey": "1622a92d"
|
||||
},
|
||||
{
|
||||
"Id": "TDORDERSITE",
|
||||
"Name": "订单接口",
|
||||
"AccessKey": "622a92d1"
|
||||
},
|
||||
{
|
||||
"Id": "UPPRODUCT",
|
||||
"Name": "UP产品端",
|
||||
"AccessKey": "c268a2cd"
|
||||
},
|
||||
{
|
||||
"Id": "gd_crm",
|
||||
"Name": "UPCRM",
|
||||
"AccessKey": "upchina."
|
||||
},
|
||||
{
|
||||
"Id": "nj_crm",
|
||||
"Name": "UPCRM",
|
||||
"AccessKey": "pchina.1"
|
||||
},
|
||||
{
|
||||
"Id": "AYCRM2_CTI",
|
||||
"Name": "CTI",
|
||||
"AccessKey": "ac910f51"
|
||||
}
|
||||
],
|
||||
"ClearCacheUrls": [
|
||||
"http://192.168.11.46:28099/cache/clear"
|
||||
],
|
||||
"CompanyList": [
|
||||
{
|
||||
"Code": "QBJZ",
|
||||
"Name": "北京一部",
|
||||
"VideoUrl": "http://bj1rec.crm.tcfortune.com:8282",
|
||||
"WxMessageUrl": "http://1.202.216.226:909"
|
||||
},
|
||||
{
|
||||
"Code": "QBJX",
|
||||
"Name": "北京二部",
|
||||
"VideoUrl": "http://bj2rec.crm.tcfortune.com:8282",
|
||||
"WxMessageUrl": ""
|
||||
},
|
||||
{
|
||||
"Code": "DNZZ",
|
||||
"Name": "东方软件一、二中心",
|
||||
"VideoUrl": "http://120.238.224.24:8098",
|
||||
"WxMessageUrl": "http://120.236.219.28:909"
|
||||
},
|
||||
{
|
||||
"Code": "DNYY",
|
||||
"Name": "东方软件三中心",
|
||||
"VideoUrl": "http://120.238.224.24:38080",
|
||||
"WxMessageUrl": "http://192.168.11.216:909"
|
||||
},
|
||||
{
|
||||
"Code": "SHZZ",
|
||||
"Name": "首华",
|
||||
"VideoUrl": "http://120.238.224.24:28080",
|
||||
"WxMessageUrl": "http://120.238.224.24:4906"
|
||||
},
|
||||
{
|
||||
"Code": "DNG8",
|
||||
"Name": "投顾业务中心",
|
||||
"VideoUrl": "http://120.238.224.24:2080",
|
||||
"WxMessageUrl": "http://120.238.224.24:2909"
|
||||
},
|
||||
{
|
||||
"Code": "DNBB",
|
||||
"Name": "内容二、三中心",
|
||||
"VideoUrl": "",
|
||||
"WxMessageUrl": "http://192.168.11.226:909"
|
||||
},
|
||||
{
|
||||
"Code": "PTD2",
|
||||
"Name": "平台2",
|
||||
"VideoUrl": "http://10.22.11.122",
|
||||
"WxMessageUrl": ""
|
||||
},
|
||||
{
|
||||
"Code": "HGBM",
|
||||
"Name": "合规",
|
||||
"VideoUrl": "http://120.238.224.24:2332",
|
||||
"WxMessageUrl": "http://192.168.11.66:909"
|
||||
}
|
||||
]
|
||||
},
|
||||
"SignConfig": {
|
||||
"AppId": "qt_compliance",
|
||||
"Secret": "CqlNBxRof0yl7eJM1f4IbOBhgribfooZJ1zwuIj5NzQ="
|
||||
},
|
||||
"Redis": [
|
||||
{
|
||||
"Name": "Hg",
|
||||
"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,38 @@
|
|||
namespace Hg.Complaint.WebApi.Workers
|
||||
{
|
||||
internal class ComplaintMessageWorker : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public ComplaintMessageWorker(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
var scope = _serviceProvider.CreateScope();
|
||||
var complaintDomain = scope.ServiceProvider.GetRequiredService<IComplaintDomain>();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var queue = await complaintDomain.GetQueue();
|
||||
if (queue > 0)
|
||||
{
|
||||
var dto = await complaintDomain.DequeueQueue();
|
||||
if (dto != null && dto.Id > 0)
|
||||
{
|
||||
await complaintDomain.AnalyseComplaintLog(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "分析投诉任务报错!");
|
||||
}
|
||||
|
||||
await Task.Delay(500, stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
namespace Hg.Complaint.WebApi.workers
|
||||
{
|
||||
internal class DueComplaintWorker : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public DueComplaintWorker(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
var firstTime = true;
|
||||
var scope = _serviceProvider.CreateScope();
|
||||
var complaintDomain = scope.ServiceProvider.GetRequiredService<IComplaintDomain>();
|
||||
try
|
||||
{
|
||||
//await complaintDomain.SyncResid();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (firstTime)
|
||||
{
|
||||
await complaintDomain.InitOverdueComplaint();
|
||||
}
|
||||
await complaintDomain.OverdueComplaint();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "分析投诉任务报错!");
|
||||
}
|
||||
|
||||
await Task.Delay(60 * 1000, stoppingToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "分析投诉任务报错!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
namespace Hg.Complaint.WebApi.workers
|
||||
{
|
||||
internal class LiveDataWorker : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
public LiveDataWorker(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
var scope = _serviceProvider.CreateScope();
|
||||
var liveAuditDomain = scope.ServiceProvider.GetRequiredService<ILiveAuditDomain>();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Information("直播数据分析任务");
|
||||
await liveAuditDomain.SyncLiveData();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "直播数据分析任务报错!");
|
||||
}
|
||||
|
||||
await Task.Delay(5 * 60 * 1000, stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue