注册证init
commit
913a8d75da
|
@ -0,0 +1,175 @@
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
# CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
|
||||||
|
dotnet_diagnostic.CS8618.severity = silent
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_indent_labels = no_change
|
||||||
|
csharp_using_directive_placement = outside_namespace:silent
|
||||||
|
csharp_style_expression_bodied_methods = false:silent
|
||||||
|
csharp_style_expression_bodied_constructors = false:silent
|
||||||
|
csharp_style_expression_bodied_operators = false:silent
|
||||||
|
csharp_style_expression_bodied_properties = true:silent
|
||||||
|
csharp_style_expression_bodied_indexers = true:silent
|
||||||
|
csharp_style_expression_bodied_accessors = true:silent
|
||||||
|
csharp_style_expression_bodied_lambdas = true:silent
|
||||||
|
csharp_style_expression_bodied_local_functions = false:silent
|
||||||
|
csharp_style_conditional_delegate_call = true:suggestion
|
||||||
|
csharp_style_var_for_built_in_types = false:silent
|
||||||
|
csharp_style_var_when_type_is_apparent = false:silent
|
||||||
|
csharp_style_var_elsewhere = false:silent
|
||||||
|
|
||||||
|
[*.{cs,vb}]
|
||||||
|
end_of_line = crlf
|
||||||
|
tab_width = 4
|
||||||
|
indent_size = 4
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_qualification_for_field = false:silent
|
||||||
|
dotnet_style_qualification_for_property = false:silent
|
||||||
|
dotnet_style_qualification_for_method = false:silent
|
||||||
|
dotnet_style_qualification_for_event = false:silent
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||||
|
dotnet_code_quality_unused_parameters = all:suggestion
|
||||||
|
dotnet_style_readonly_field = true:suggestion
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
|
||||||
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
|
dotnet_style_null_propagation = true:suggestion
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||||
|
dotnet_style_prefer_auto_properties = true:silent
|
||||||
|
dotnet_style_object_initializer = true:suggestion
|
||||||
|
dotnet_style_collection_initializer = true:suggestion
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||||
|
dotnet_style_explicit_tuple_names = true:suggestion
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||||
|
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||||
|
dotnet_style_namespace_match_folder = true:suggestion
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||||
|
dotnet_style_predefined_type_for_member_access = true:silent
|
||||||
|
[*.cs]
|
||||||
|
#### 命名样式 ####
|
||||||
|
|
||||||
|
# 命名规则
|
||||||
|
|
||||||
|
dotnet_naming_rule.接口_should_be_以_i_开始.severity = suggestion
|
||||||
|
dotnet_naming_rule.接口_should_be_以_i_开始.symbols = 接口
|
||||||
|
dotnet_naming_rule.接口_should_be_以_i_开始.style = 以_i_开始
|
||||||
|
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||||
|
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||||
|
|
||||||
|
# 符号规范
|
||||||
|
|
||||||
|
dotnet_naming_symbols.接口.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.接口.applicable_accessibilities = public, internal, private, protected, protected_internal
|
||||||
|
dotnet_naming_symbols.接口.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.类型.applicable_accessibilities = public, internal, private, protected, protected_internal
|
||||||
|
dotnet_naming_symbols.类型.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, internal, private, protected, protected_internal
|
||||||
|
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||||
|
|
||||||
|
# 命名样式
|
||||||
|
|
||||||
|
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||||
|
dotnet_naming_style.以_i_开始.required_suffix =
|
||||||
|
dotnet_naming_style.以_i_开始.word_separator =
|
||||||
|
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||||
|
csharp_prefer_simple_using_statement = true:suggestion
|
||||||
|
csharp_prefer_braces = true:silent
|
||||||
|
csharp_style_namespace_declarations = block_scoped:silent
|
||||||
|
csharp_prefer_static_local_function = true:suggestion
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||||
|
csharp_style_prefer_switch_expression = true:suggestion
|
||||||
|
csharp_style_prefer_pattern_matching = true:silent
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||||
|
csharp_style_prefer_not_pattern = true:suggestion
|
||||||
|
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||||
|
csharp_style_throw_expression = true:suggestion
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||||
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||||
|
csharp_style_prefer_index_operator = true:suggestion
|
||||||
|
csharp_style_prefer_range_operator = true:suggestion
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_prefer_tuple_swap = true:suggestion
|
||||||
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||||
|
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||||
|
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||||
|
|
||||||
|
[*.vb]
|
||||||
|
#### 命名样式 ####
|
||||||
|
|
||||||
|
# 命名规则
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
|
||||||
|
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
|
||||||
|
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||||
|
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
|
||||||
|
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||||
|
|
||||||
|
# 符号规范
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||||
|
dotnet_naming_symbols.类型.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||||
|
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||||
|
|
||||||
|
# 命名样式
|
||||||
|
|
||||||
|
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||||
|
dotnet_naming_style.以_i_开始.required_suffix =
|
||||||
|
dotnet_naming_style.以_i_开始.word_separator =
|
||||||
|
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||||
|
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
|
@ -0,0 +1,63 @@
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
|
@ -0,0 +1,373 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
/UploadFile/Check
|
||||||
|
/TrialData/281bdb09-f792-4faa-de18-08da0e042672/50d0cf71-ee4d-4e54-af06-490f8be1bff1/72b8ef0b-4adc-465e-fa25-08da122bbd9c/eb53c5e2-6307-42f3-d710-08da122bbde1/Dicom
|
||||||
|
/TrialData/4067198c-f9c4-47de-705a-08da12df3a17/6dedb49c-874c-4f7c-5c0d-08d947774c19
|
||||||
|
/TrialData/2a864970-1832-4cf9-f3ab-08da0cd341a0/01a4d468-caa4-41a2-ab36-c42ba30130ac/3210c828-cf32-4a70-fa40-08da0cd72d16/9a3b5449-ac01-4df1-bf24-08da0cd72d2a/Dicom/d287dde0-b9d1-9b37-28bb-371b6a445cf1
|
||||||
|
TrialData
|
||||||
|
/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
|
||||||
|
|
||||||
|
|
||||||
|
IRaCISData
|
||||||
|
UploadFile
|
|
@ -0,0 +1,185 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.API", "IRaCIS.Core.API\IRaCIS.Core.API.csproj", "{F15CE209-6039-46A6-AE7F-E81ADA795F28}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Domain", "IRaCIS.Core.Domain\IRaCIS.Core.Domain.csproj", "{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Application", "IRaCIS.Core.Application\IRaCIS.Core.Application.csproj", "{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Domain.Share", "IRaCIS.Core.Domain.Share\IRaCIS.Core.Domain.Share.csproj", "{7CBC76F5-3817-46B7-8D9D-79253A89B578}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Test", "IRaCIS.Core.Test\IRaCIS.Core.Test.csproj", "{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore", "IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj", "{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EI_Image_Viewer_Installer", "Start\EI_Image_Viewer_Installer.csproj", "{D96F4B52-359C-43C9-8110-BAD1437F9280}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Install", "Install\Install.csproj", "{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnInstall", "UnInstall\UnInstall.csproj", "{60B9AC72-5744-4517-93A5-A1ECD573A529}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EI_Image_Viewer_Activation", "EI_Image_Viewer_Activation\EI_Image_Viewer_Activation.csproj", "{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EI_TestProject", "EI_TestProject\EI_TestProject.csproj", "{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|x64.Build.0 = Release|x64
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F15CE209-6039-46A6-AE7F-E81ADA795F28}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|x64.Build.0 = Release|x64
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{D4DF27AC-3739-4264-BFB8-AED6DC2B84C7}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{037E7DE9-0AE2-4987-8C69-F51D5B9CA19D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|x64.Build.0 = Release|x64
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|x64.Build.0 = Release|x64
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{D96F4B52-359C-43C9-8110-BAD1437F9280}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F5820DF0-DE23-4F4A-8D49-7E22F67B784D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|x64.Build.0 = Release|x64
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{60B9AC72-5744-4517-93A5-A1ECD573A529}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|x64.Build.0 = Release|x64
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{1D8AC441-D578-4B38-BCEE-686BD5D59E5A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{47F99CA7-E55B-4A0E-A511-7EDF34C57A20}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BCC2EB19-3914-489B-B1D7-B7303E0218A3}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "5.0.9",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
//using Autofac;
|
||||||
|
//using Autofac.Extensions.DependencyInjection;
|
||||||
|
//using IRaCIS.Core.API;
|
||||||
|
//using IRaCIS.Core.Application.Filter;
|
||||||
|
//using IRaCIS.Core.Application.MediatR.Handlers;
|
||||||
|
//using LogDashboard;
|
||||||
|
//using MassTransit;
|
||||||
|
//using MassTransit.NewIdProviders;
|
||||||
|
//using MediatR;
|
||||||
|
//using Microsoft.AspNetCore.Builder;
|
||||||
|
//using Microsoft.AspNetCore.Http.Features;
|
||||||
|
//using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
//using Microsoft.AspNetCore.SignalR;
|
||||||
|
//using Microsoft.Extensions.Configuration;
|
||||||
|
//using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//using Microsoft.Extensions.Hosting;
|
||||||
|
//using Serilog;
|
||||||
|
//using System;
|
||||||
|
|
||||||
|
//var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
|
||||||
|
// //以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||||||
|
// var config = new ConfigurationBuilder()
|
||||||
|
// .AddEnvironmentVariables()
|
||||||
|
// .Build();
|
||||||
|
|
||||||
|
// var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
||||||
|
|
||||||
|
// if (string.IsNullOrWhiteSpace(enviromentName))
|
||||||
|
// {
|
||||||
|
|
||||||
|
// var index = Array.IndexOf(args, "--env");
|
||||||
|
// enviromentName = index > -1
|
||||||
|
// ? args[index + 1]
|
||||||
|
// : "Development";
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||||
|
// .ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||||||
|
// {
|
||||||
|
// containerBuilder.RegisterModule<AutofacModuleSetup>();
|
||||||
|
// })
|
||||||
|
// .UseWindowsService().UseSerilog();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//// Add services to the container.
|
||||||
|
|
||||||
|
////本地化
|
||||||
|
//builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
|
||||||
|
|
||||||
|
//// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||||
|
//builder.Services.AddControllers(options =>
|
||||||
|
//{
|
||||||
|
// //options.Filters.Add<LogActionFilter>();
|
||||||
|
// options.Filters.Add<ModelActionFilter>();
|
||||||
|
// options.Filters.Add<ProjectExceptionFilter>();
|
||||||
|
// //options.Filters.Add<UnitOfWorkFilter>();
|
||||||
|
|
||||||
|
// //if (_configuration.GetSection("BasicSystemConfig").GetValue<bool>("OpenLoginLimit"))
|
||||||
|
// //{
|
||||||
|
// // options.Filters.Add<LimitUserRequestAuthorization>();
|
||||||
|
|
||||||
|
// //}
|
||||||
|
|
||||||
|
|
||||||
|
//}).AddNewtonsoftJsonSetup(); // NewtonsoftJson 序列化 处理
|
||||||
|
|
||||||
|
////动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
||||||
|
//builder.Services.AddDynamicWebApiSetup();
|
||||||
|
////AutoMapper
|
||||||
|
//builder.Services.AddAutoMapperSetup();
|
||||||
|
////EF ORM QueryWithNoLock
|
||||||
|
//builder.Services.AddEFSetup(builder.Configuration);
|
||||||
|
////Http 响应压缩
|
||||||
|
//builder.Services.AddResponseCompressionSetup();
|
||||||
|
////Swagger Api 文档
|
||||||
|
//builder.Services.AddSwaggerSetup();
|
||||||
|
////JWT Token 验证
|
||||||
|
//builder.Services.AddJWTAuthSetup(builder.Configuration);
|
||||||
|
//// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||||||
|
//builder.Services.AddMediatR(typeof(ConsistencyVerificationHandler).Assembly);
|
||||||
|
//// EasyCaching 缓存
|
||||||
|
//builder.Services.AddEasyCachingSetup();
|
||||||
|
|
||||||
|
////services.AddDistributedMemoryCache();
|
||||||
|
|
||||||
|
////// hangfire 定时任务框架 有界面,更友好~
|
||||||
|
//builder.Services.AddhangfireSetup(builder.Configuration);
|
||||||
|
////// QuartZ 定时任务框架 使用了hangfire 暂时不用,后续需要可以打开,已经配好
|
||||||
|
////builder.Services.AddQuartZSetup(_configuration);
|
||||||
|
|
||||||
|
//// 保护上传文件
|
||||||
|
////services.AddStaticFileAuthorizationSetup();
|
||||||
|
|
||||||
|
|
||||||
|
//////HttpReports 暂时废弃
|
||||||
|
////services.AddHttpReports().AddHttpTransport();
|
||||||
|
////Serilog 日志可视化 LogDashboard日志
|
||||||
|
//builder.Services.AddLogDashboardSetup();
|
||||||
|
////上传限制 配置
|
||||||
|
//builder.Services.Configure<FormOptions>(options =>
|
||||||
|
//{
|
||||||
|
// options.MultipartBodyLengthLimit = int.MaxValue;
|
||||||
|
// options.ValueCountLimit = int.MaxValue;
|
||||||
|
// options.ValueLengthLimit = int.MaxValue;
|
||||||
|
//});
|
||||||
|
////IP 限流 可设置白名单 或者黑名单
|
||||||
|
////services.AddIpPolicyRateLimitSetup(_configuration);
|
||||||
|
////用户类型 策略授权
|
||||||
|
//builder.Services.AddAuthorizationPolicySetup(builder.Configuration);
|
||||||
|
|
||||||
|
//builder.Services.AddJsonConfigSetup(builder.Configuration);
|
||||||
|
|
||||||
|
////转发头设置 获取真实IP
|
||||||
|
//builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
//{
|
||||||
|
// options.ForwardedHeaders =
|
||||||
|
// ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
//});
|
||||||
|
////Dicom影像渲染图片 跨平台
|
||||||
|
//builder.Services.AddDicomSetup();
|
||||||
|
|
||||||
|
//// 实时应用
|
||||||
|
//builder.Services.AddSignalR();
|
||||||
|
|
||||||
|
|
||||||
|
//builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
|
||||||
|
|
||||||
|
//builder.Services.AddControllers();
|
||||||
|
//// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
////builder.Services.AddEndpointsApiExplorer();
|
||||||
|
////builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
////SerilogExtension.AddSerilogSetup(enviromentName, builder.Host.confi);
|
||||||
|
|
||||||
|
|
||||||
|
//var app = builder.Build();
|
||||||
|
|
||||||
|
//// Configure the HTTP request pipeline.
|
||||||
|
|
||||||
|
////本地化
|
||||||
|
//app.UseLocalization();
|
||||||
|
|
||||||
|
//app.UseForwardedHeaders();
|
||||||
|
|
||||||
|
|
||||||
|
////不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||||
|
//app.UseStaticFiles();
|
||||||
|
|
||||||
|
//app.UseIRacisHostStaticFileStore(app.Environment);
|
||||||
|
|
||||||
|
////LogDashboard
|
||||||
|
//app.UseLogDashboard("/LogDashboard");
|
||||||
|
|
||||||
|
////hangfire
|
||||||
|
////app.UseHangfireConfig(app.Environment);
|
||||||
|
|
||||||
|
//////暂时废弃
|
||||||
|
////app.UseHttpReports();
|
||||||
|
|
||||||
|
//////限流 中间件
|
||||||
|
////app.UseIpRateLimiting();
|
||||||
|
|
||||||
|
////响应压缩
|
||||||
|
//app.UseResponseCompression();
|
||||||
|
|
||||||
|
//if (app.Environment.IsDevelopment())
|
||||||
|
//{
|
||||||
|
// app.UseDeveloperExceptionPage();
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
|
||||||
|
// //app.UseHsts();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//SwaggerSetup.Configure(app, app.Environment);
|
||||||
|
|
||||||
|
//Console.WriteLine("当前环境: " + builder.Environment.EnvironmentName);
|
||||||
|
|
||||||
|
////app.UseMiddleware<AuthMiddleware>();
|
||||||
|
|
||||||
|
//// 特殊异常处理 比如 404
|
||||||
|
//app.UseStatusCodePagesWithReExecute("/Error/{0}");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////serilog 记录请求的用户信息
|
||||||
|
//app.UseSerilogConfig(app.Environment);
|
||||||
|
|
||||||
|
//app.UseRouting();
|
||||||
|
|
||||||
|
//app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
||||||
|
|
||||||
|
|
||||||
|
//app.UseAuthentication();
|
||||||
|
////app.UseJwtBearerQueryString();
|
||||||
|
//app.UseAuthorization();
|
||||||
|
|
||||||
|
//////文件伺服 必须带Token 访问
|
||||||
|
//////app.UseIRacisHostStaticFileStore(env);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////app.UseEndpoints(endpoints =>
|
||||||
|
////{
|
||||||
|
|
||||||
|
|
||||||
|
//// endpoints.MapControllers();
|
||||||
|
|
||||||
|
//// endpoints.MapHub<UploadHub>("/UploadHub")/*.RequireCors(t=>t.WithOrigins(new string[] {"null"}).AllowAnyMethod().AllowAnyHeader().AllowCredentials())*/;
|
||||||
|
////});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//app.MapControllers();
|
||||||
|
//app.MapHub<UploadHub>("/UploadHub")/*.RequireCors(t=>t.WithOrigins(new string[] {"null"}).AllowAnyMethod().AllowAnyHeader().AllowCredentials())*/;
|
||||||
|
|
||||||
|
|
||||||
|
//app.Run();
|
||||||
|
|
||||||
|
//测试同步
|
|
@ -0,0 +1,39 @@
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Panda.DynamicWebApi.Attributes;
|
||||||
|
|
||||||
|
namespace EasyCaching.Demo.Interceptors.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
[NonDynamicWebApi]
|
||||||
|
public class ErrorController : ControllerBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 主要处理 前端404等错误 全局业务异常已统一处理了,非业务错误会来到这里
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Route("error/{code:int}")]
|
||||||
|
[HttpGet]
|
||||||
|
public IResponseOutput Error(int code)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (code < 500)
|
||||||
|
{
|
||||||
|
//LogDashboard 要求返回码必须是401不能覆盖,否则 认证有问题
|
||||||
|
if (code == 401)
|
||||||
|
{
|
||||||
|
ControllerContext.HttpContext.Response.StatusCode = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseOutput.NotOk($"Client error, actual request error status code({code})");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
return ResponseOutput.NotOk($"Server error , actual request error status code({code})");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using gRPC.ZHiZHUN.AuthServer.protos;
|
||||||
|
using Grpc.Net.Client;
|
||||||
|
using Grpc.Net.Client.Configuration;
|
||||||
|
using IRaCIS.Application.Interfaces;
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Application.Auth;
|
||||||
|
using IRaCIS.Core.Application.Filter;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using IRaCIS.Core.Application.Interfaces;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IRaCIS.Application.Services;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace IRaCIS.Api.Controllers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 医生基本信息 、工作信息 专业信息、审核状态
|
||||||
|
/// </summary>
|
||||||
|
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||||
|
public class ExtraController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取医生详情
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attachmentService"></param>
|
||||||
|
/// <param name="_doctorService"></param>
|
||||||
|
/// <param name="_educationService"></param>
|
||||||
|
/// <param name="_trialExperienceService"></param>
|
||||||
|
/// <param name="_researchPublicationService"></param>
|
||||||
|
/// <param name="_vacationService"></param>
|
||||||
|
/// <param name="doctorId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet, Route("doctor/getDetail/{doctorId:guid}")]
|
||||||
|
|
||||||
|
public async Task<IResponseOutput<DoctorDetailDTO>> GetDoctorDetail([FromServices] IAttachmentService attachmentService, [FromServices] IDoctorService _doctorService,
|
||||||
|
[FromServices] IEducationService _educationService, [FromServices] ITrialExperienceService _trialExperienceService,
|
||||||
|
[FromServices] IResearchPublicationService _researchPublicationService, [FromServices] IVacationService _vacationService, Guid doctorId)
|
||||||
|
{
|
||||||
|
var education = await _educationService.GetEducation(doctorId);
|
||||||
|
|
||||||
|
var sowList = _doctorService.GetDoctorSowList(doctorId);
|
||||||
|
var ackSowList = _doctorService.GetDoctorAckSowList(doctorId);
|
||||||
|
|
||||||
|
var doctorDetail = new DoctorDetailDTO
|
||||||
|
{
|
||||||
|
AuditView =await _doctorService.GetAuditState(doctorId),
|
||||||
|
BasicInfoView = await _doctorService.GetBasicInfo(doctorId),
|
||||||
|
EmploymentView = await _doctorService.GetEmploymentInfo(doctorId),
|
||||||
|
AttachmentList = await attachmentService.GetAttachments(doctorId),
|
||||||
|
|
||||||
|
EducationList = education.EducationList,
|
||||||
|
PostgraduateList = education.PostgraduateList,
|
||||||
|
|
||||||
|
TrialExperienceView = await _trialExperienceService.GetTrialExperience(doctorId),
|
||||||
|
ResearchPublicationView = await _researchPublicationService.GetResearchPublication(doctorId),
|
||||||
|
|
||||||
|
SpecialtyView =await _doctorService.GetSpecialtyInfo(doctorId),
|
||||||
|
InHoliday = (await _vacationService.OnVacation(doctorId)).IsSuccess,
|
||||||
|
IntoGroupInfo = _doctorService.GetDoctorIntoGroupInfo(doctorId),
|
||||||
|
SowList = sowList,
|
||||||
|
AckSowList = ackSowList
|
||||||
|
};
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(doctorDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> 系统用户登录接口[New] </summary>
|
||||||
|
[HttpPost, Route("user/login")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IResponseOutput<LoginReturnDTO>> Login(UserLoginDTO loginUser, [FromServices] IEasyCachingProvider provider, [FromServices] IUserService _userService,
|
||||||
|
[FromServices] ITokenService _tokenService, [FromServices] IConfiguration configuration)
|
||||||
|
{
|
||||||
|
|
||||||
|
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
|
||||||
|
|
||||||
|
if (returnModel.IsSuccess)
|
||||||
|
{
|
||||||
|
#region GRPC 调用鉴权中心,因为服务器IIS问题 http/2 故而没法使用
|
||||||
|
|
||||||
|
////重试策略
|
||||||
|
//var defaultMethodConfig = new MethodConfig
|
||||||
|
//{
|
||||||
|
// Names = { MethodName.Default },
|
||||||
|
// RetryPolicy = new RetryPolicy
|
||||||
|
// {
|
||||||
|
// MaxAttempts = 3,
|
||||||
|
// InitialBackoff = TimeSpan.FromSeconds(1),
|
||||||
|
// MaxBackoff = TimeSpan.FromSeconds(5),
|
||||||
|
// BackoffMultiplier = 1.5,
|
||||||
|
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
|
||||||
|
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
|
||||||
|
|
||||||
|
//var httpHandler = new HttpClientHandler();
|
||||||
|
//// Return `true` to allow certificates that are untrusted/invalid
|
||||||
|
//httpHandler.ServerCertificateCustomValidationCallback =
|
||||||
|
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
|
|
||||||
|
|
||||||
|
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
|
||||||
|
//AppContext.SetSwitch(
|
||||||
|
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
|
||||||
|
////var grpcAdress = "http://localhost:7200";
|
||||||
|
|
||||||
|
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
|
||||||
|
//{
|
||||||
|
// HttpHandler = httpHandler,
|
||||||
|
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
|
||||||
|
|
||||||
|
//});
|
||||||
|
////var channel = GrpcChannel.ForAddress(grpcAdress);
|
||||||
|
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
|
||||||
|
|
||||||
|
//var userInfo = returnModel.Data.BasicInfo;
|
||||||
|
|
||||||
|
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
|
||||||
|
//{
|
||||||
|
// Id = userInfo.Id.ToString(),
|
||||||
|
// ReviewerCode = userInfo.ReviewerCode,
|
||||||
|
// IsAdmin = userInfo.IsAdmin,
|
||||||
|
// RealName = userInfo.RealName,
|
||||||
|
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
|
||||||
|
// UserTypeShortName = userInfo.UserTypeShortName,
|
||||||
|
// UserName = userInfo.UserName
|
||||||
|
//});
|
||||||
|
|
||||||
|
//returnModel.Data.JWTStr = tokenResponse.Token;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||||
|
|
||||||
|
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
|
||||||
|
var option = new CookieOptions
|
||||||
|
{
|
||||||
|
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
|
||||||
|
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
|
||||||
|
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
|
||||||
|
Secure = false // 确保 cookie 只能通过 HTTPS 访问
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpContext.Response.Cookies.Append("access_token", returnModel.Data.JWTStr, option);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = returnModel.Data.BasicInfo.Id.ToString();
|
||||||
|
//provider.Set(userId, userId, TimeSpan.FromMinutes(AppSettings.LoginExpiredTimeSpan));
|
||||||
|
|
||||||
|
await provider.SetAsync(userId.ToString(), returnModel.Data.JWTStr, TimeSpan.FromDays(7));
|
||||||
|
return returnModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet, Route("imageShare/ShareImage")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IResponseOutput ShareImage([FromServices] ITokenService _tokenService)
|
||||||
|
{
|
||||||
|
var token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
|
||||||
|
{
|
||||||
|
Id = Guid.Empty,
|
||||||
|
IsReviewer = false,
|
||||||
|
IsAdmin = false,
|
||||||
|
RealName = "Share001",
|
||||||
|
UserName = "Share001",
|
||||||
|
Sex = 0,
|
||||||
|
//UserType = "ShareType",
|
||||||
|
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||||
|
Code = "ShareCode001",
|
||||||
|
}));
|
||||||
|
return ResponseOutput.Ok("/showdicom?studyId=f7b67793-8155-0223-2f15-118f2642efb8&type=Share&token=" + token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("User/UserRedirect")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<IActionResult> UserRedirect([FromServices] IRepository<User> _userRepository, string url ,[FromServices]ILogger<ExtraController> _logger)
|
||||||
|
{
|
||||||
|
|
||||||
|
var decodeUrl = System.Web.HttpUtility.UrlDecode(url);
|
||||||
|
|
||||||
|
var userId = decodeUrl.Substring(decodeUrl.IndexOf("UserId=") + "UserId=".Length , 36) ;
|
||||||
|
|
||||||
|
var token = decodeUrl.Substring(decodeUrl.IndexOf("access_token=") + "access_token=".Length);
|
||||||
|
|
||||||
|
var domainStrList = decodeUrl.Split("/").ToList().Take(3).ToList();
|
||||||
|
|
||||||
|
var errorUrl = domainStrList[0]+"//"+ domainStrList[2]+ "/error";
|
||||||
|
|
||||||
|
|
||||||
|
if (!await _userRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd))
|
||||||
|
{
|
||||||
|
decodeUrl = errorUrl+ $"?ErrorMessage={System.Web.HttpUtility.UrlEncode("您的初始化链接已过期")} ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect(decodeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet, Route("ip")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IResponseOutput Get([FromServices] IHttpContextAccessor _context/*, [FromServices] IUserService _userService*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"RemoteIpAddress:{_context.HttpContext.Connection.RemoteIpAddress}");
|
||||||
|
|
||||||
|
if (Request.Headers.ContainsKey("X-Real-IP"))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request.Headers.ContainsKey("X-Forwarded-For"))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}");
|
||||||
|
}
|
||||||
|
return ResponseOutput.Ok(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet, Route("ip2")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public IResponseOutput Get2([FromServices] IHttpContextAccessor _context, [FromServices] IRepository _userService)
|
||||||
|
{
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"RemoteIpAddress:{_context.HttpContext.Connection.RemoteIpAddress}");
|
||||||
|
|
||||||
|
if (Request.Headers.ContainsKey("X-Real-IP"))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Request.Headers.ContainsKey("X-Forwarded-For"))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}");
|
||||||
|
}
|
||||||
|
return ResponseOutput.Ok(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,323 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using IRaCIS.Application.Interfaces;
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Application.Filter;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IRaCIS.Application.Services;
|
||||||
|
using IRaCIS.Core.Application.Service.Inspection.DTO;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Application.Auth;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Controllers.Special
|
||||||
|
{
|
||||||
|
//谨慎修改 涉及到财务模块
|
||||||
|
|
||||||
|
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")]
|
||||||
|
public class FinancialChangeController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ITrialService _trialService;
|
||||||
|
private readonly ICalculateService _calculateService;
|
||||||
|
|
||||||
|
public FinancialChangeController(ITrialService trialService, ICalculateService calculateService
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_trialService = trialService;
|
||||||
|
_calculateService = calculateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////[TrialAudit(AuditType.TrialAudit, AuditOptType.AddOrUpdateTrial)]
|
||||||
|
|
||||||
|
///// <summary> 添加实验项目-返回新增Id[AUTH]</summary>
|
||||||
|
///// <returns>新记录Id</returns>
|
||||||
|
//[HttpPost, Route("Inspection/trial/addOrUpdateTrial")]
|
||||||
|
//[UnitOfWork]
|
||||||
|
|
||||||
|
//public async Task<IResponseOutput> AddOrUpdateTrialInspection(DataInspectionDto<TrialCommand> opt)
|
||||||
|
//{
|
||||||
|
// var fun =await AddOrUpdateTrial(opt.Data);
|
||||||
|
|
||||||
|
// return fun;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> 添加实验项目-返回新增Id[AUTH]</summary>
|
||||||
|
/// <param name="param"></param>
|
||||||
|
/// <returns>新记录Id</returns>
|
||||||
|
[HttpPost, Route("trial/addOrUpdateTrial")]
|
||||||
|
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
|
||||||
|
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AddOrUpdateTrial", "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })]
|
||||||
|
public async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand param, [FromServices] ITrialConfigService _ITrialConfigService)
|
||||||
|
{
|
||||||
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
|
var result = await _trialService.AddOrUpdateTrial(param, _ITrialConfigService);
|
||||||
|
|
||||||
|
if (_trialService.TrialExpeditedChange)
|
||||||
|
{
|
||||||
|
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||||
|
|
||||||
|
calcList.ForEach(t =>
|
||||||
|
{
|
||||||
|
if (needCalReviewerIds.Contains(t.DoctorId))
|
||||||
|
{
|
||||||
|
_calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
t.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(t.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加或更新工作量[AUTH]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_trialWorkloadService"></param>
|
||||||
|
/// <param name="workLoadAddOrUpdateModel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
|
||||||
|
[HttpPost, Route("doctorWorkload/workLoadAddOrUpdate")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
public async Task<IResponseOutput> WorkLoadAddOrUpdate([FromServices] IDoctorWorkloadService _trialWorkloadService, WorkloadCommand workLoadAddOrUpdateModel)
|
||||||
|
{
|
||||||
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
|
var result = await _trialWorkloadService.AddOrUpdateWorkload(workLoadAddOrUpdateModel, userId);
|
||||||
|
if (result.IsSuccess && workLoadAddOrUpdateModel.DataFrom == 2)
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
workLoadAddOrUpdateModel.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = workLoadAddOrUpdateModel.WorkTime
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpDelete, Route("doctorWorkload/deleteWorkLoad/{id:guid}/{trialId:guid}")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
public async Task<IResponseOutput> DeleteWorkLoad([FromServices] IDoctorWorkloadService _trialWorkloadService, Guid id)
|
||||||
|
{
|
||||||
|
//先判断该工作量的费用是否被锁定,如果被锁定,则不能删除
|
||||||
|
var workload = await _trialWorkloadService.GetWorkloadDetailById(id);
|
||||||
|
var yearMonth = workload.WorkTime.ToString("yyyy-MM");
|
||||||
|
var isLock = await _calculateService.IsLock(workload.DoctorId, yearMonth);
|
||||||
|
|
||||||
|
if (isLock)
|
||||||
|
{
|
||||||
|
return ResponseOutput.NotOk("Expenses have been settled and workload can not be reset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleteResult = await _trialWorkloadService.DeleteWorkload(id);
|
||||||
|
if (workload.DataFrom == (int)Domain.Share.WorkLoadFromStatus.FinalConfirm)
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
workload.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = workload.WorkTime
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
return deleteResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加或更新汇率(会触发没有对锁定的费用计算)
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[HttpPost, Route("exchangeRate/addOrUpdateExchangeRate")]
|
||||||
|
public async Task<IResponseOutput> AddOrUpdateExchangeRate([FromServices] IExchangeRateService _exchangeRateService, [FromServices] IPaymentAdjustmentService _costAdjustmentService, ExchangeRateCommand addOrUpdateModel)
|
||||||
|
{
|
||||||
|
var result = await _exchangeRateService.AddOrUpdateExchangeRate(addOrUpdateModel);
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, addOrUpdateModel.YearMonth);
|
||||||
|
foreach (var item in calcList)
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
item.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await _costAdjustmentService.CalculateCNY(addOrUpdateModel.YearMonth, addOrUpdateModel.Rate);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加或更新 职称单价[AUTH]
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[HttpPost, Route("rankPrice/addOrUpdateRankPrice")]
|
||||||
|
public async Task<IResponseOutput> AddOrUpdateRankPrice([FromServices] IReviewerPayInfoService _reviewerPayInfoService, [FromServices] IRankPriceService _rankPriceService, RankPriceCommand addOrUpdateModel)
|
||||||
|
{
|
||||||
|
if (addOrUpdateModel.Id != Guid.Empty && addOrUpdateModel.Id != null)
|
||||||
|
{
|
||||||
|
var needCalReviewerIds =await _reviewerPayInfoService.GetReviewerIdByRankId(Guid.Parse(addOrUpdateModel.Id.ToString()));
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||||
|
|
||||||
|
foreach (var item in calcList)
|
||||||
|
{
|
||||||
|
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
item.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
|
return await _rankPriceService.AddOrUpdateRankPrice(addOrUpdateModel, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加或更新(替换)医生支付展信息[AUTH]
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[HttpPost, Route("reviewerPayInfo/addOrUpdateReviewerPayInfo")]
|
||||||
|
public async Task<IResponseOutput> AddOrUpdateReviewerPayInfo([FromServices] IReviewerPayInfoService _doctorPayInfoService, ReviewerPayInfoCommand addOrUpdateModel)
|
||||||
|
{
|
||||||
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
|
var result =await _doctorPayInfoService.AddOrUpdateReviewerPayInfo(addOrUpdateModel, userId);
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(addOrUpdateModel.DoctorId, string.Empty);
|
||||||
|
foreach (var item in calcList)
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
item.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH]
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[HttpPost, Route("trialPaymentPrice/addOrUpdateTrialPaymentPrice")]
|
||||||
|
public async Task<IResponseOutput> AddOrUpdateTrialPaymentPrice([FromServices] ITrialPaymentPriceService _trialPaymentPriceService, TrialPaymentPriceCommand addOrUpdateModel)
|
||||||
|
{
|
||||||
|
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||||
|
var result =await _trialPaymentPriceService.AddOrUpdateTrialPaymentPrice(addOrUpdateModel);
|
||||||
|
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(addOrUpdateModel.TrialId);
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||||
|
|
||||||
|
foreach (var item in calcList)
|
||||||
|
{
|
||||||
|
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
item.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量更新奖励费用[AUTH]
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[HttpPost, Route("volumeReward/addOrUpdatevolumeRewardPriceList")]
|
||||||
|
public async Task<IResponseOutput> AddOrUpdateAwardPriceList([FromServices] IVolumeRewardService _volumeRewardService, IEnumerable<AwardPriceCommand> addOrUpdateModel)
|
||||||
|
{
|
||||||
|
|
||||||
|
var result =await _volumeRewardService.AddOrUpdateVolumeRewardPriceList(addOrUpdateModel);
|
||||||
|
|
||||||
|
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||||
|
foreach (var item in calcList)
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||||
|
{
|
||||||
|
NeedCalculateReviewers = new List<Guid>()
|
||||||
|
{
|
||||||
|
item.DoctorId
|
||||||
|
},
|
||||||
|
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||||
|
}, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算医生月度费用,并将计算的结果存入费用表
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost, Route("financial/calculateMonthlyPayment")]
|
||||||
|
public async Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return ResponseOutput.NotOk("Invalid parameter.");
|
||||||
|
}
|
||||||
|
return await _calculateService.CalculateMonthlyPayment(param, User.FindFirst("id").Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Financials /Monthly Payment 列表查询接口
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost, Route("financial/getMonthlyPaymentList")]
|
||||||
|
public async Task<IResponseOutput<PaymentDTO>> GetMonthlyPaymentList([FromServices] IPaymentService _paymentService, [FromServices] IExchangeRateService _exchangeRateService, MonthlyPaymentQueryDTO queryParam)
|
||||||
|
{
|
||||||
|
return ResponseOutput.Ok(new PaymentDTO
|
||||||
|
{
|
||||||
|
CostList = await _paymentService.GetMonthlyPaymentList(queryParam),
|
||||||
|
ExchangeRate = await _exchangeRateService.GetExchangeRateByMonth(queryParam.StatisticsDate.ToString("yyyy-MM"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,460 @@
|
||||||
|
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
using IRaCIS.Application.Interfaces;
|
||||||
|
using IRaCIS.Core.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Application.Filter;
|
||||||
|
using IRaCIS.Core.Application.Image.QA;
|
||||||
|
using IRaCIS.Core.Application.Interfaces;
|
||||||
|
using IRaCIS.Core.Application.Service;
|
||||||
|
using IRaCIS.Core.Application.Service.Inspection.DTO;
|
||||||
|
using IRaCIS.Core.Application.Service.Inspection.Interface;
|
||||||
|
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||||
|
using IRaCIS.Core.Application.ViewModel;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||||
|
[UnitOfWork]
|
||||||
|
public class InspectionController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IRepository _repository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
private readonly ITrialDocumentService _trialDocumentService;
|
||||||
|
private readonly IQCListService _qCListService;
|
||||||
|
private readonly IReadingImageTaskService _iReadingImageTaskService;
|
||||||
|
private readonly IHttpContextAccessor _httpContext;
|
||||||
|
private readonly ITrialConfigService _trialConfigService;
|
||||||
|
private readonly INoneDicomStudyService _noneDicomStudyService;
|
||||||
|
private readonly ISubjectService _subjectService;
|
||||||
|
private readonly IReadingClinicalDataService _readingClinicalDataService;
|
||||||
|
private readonly ISubjectVisitService _subjectVisitService;
|
||||||
|
private readonly IQCOperationService _qCOperationService;
|
||||||
|
private readonly IClinicalDataService _clinicalDataService;
|
||||||
|
private readonly IVisitPlanService _visitPlanService;
|
||||||
|
|
||||||
|
private readonly IInspectionService _inspectionService;
|
||||||
|
private readonly IReadingMedicalReviewService _readingMedicalReviewService;
|
||||||
|
private readonly IReadingMedicineQuestionService _readingMedicineQuestionService;
|
||||||
|
private readonly IRepository<DataInspection> _dataInspectionRepository;
|
||||||
|
private delegate Task<IResponseOutput> executionFun(dynamic data);
|
||||||
|
|
||||||
|
public InspectionController(IRepository repository,
|
||||||
|
IRepository<DataInspection> _repositoryDataInspection,
|
||||||
|
IMapper mapper, IUserInfo userInfo,
|
||||||
|
ITrialDocumentService trialDocumentService,
|
||||||
|
IRepository<DataInspection> dataInspectionRepository,
|
||||||
|
IQCListService _qCListService,
|
||||||
|
IReadingImageTaskService _iReadingImageTaskService,
|
||||||
|
IHttpContextAccessor httpContext,
|
||||||
|
IInspectionService sinspectionService,
|
||||||
|
IReadingMedicalReviewService readingMedicalReviewService,
|
||||||
|
IReadingMedicineQuestionService readingMedicineQuestionService,
|
||||||
|
ITrialConfigService _trialConfigService,
|
||||||
|
INoneDicomStudyService noneDicomStudyService,
|
||||||
|
ISubjectService _subjectService,
|
||||||
|
IReadingClinicalDataService _readingClinicalDataService,
|
||||||
|
ISubjectVisitService subjectVisitService,
|
||||||
|
IQCOperationService qCOperationService,
|
||||||
|
IClinicalDataService clinicalDataService,
|
||||||
|
IVisitPlanService visitPlanService
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this._repository = repository;
|
||||||
|
this._mapper = mapper;
|
||||||
|
this._userInfo = userInfo;
|
||||||
|
this._inspectionService = sinspectionService;
|
||||||
|
this._readingMedicalReviewService = readingMedicalReviewService;
|
||||||
|
this._readingMedicineQuestionService = readingMedicineQuestionService;
|
||||||
|
this._trialDocumentService = trialDocumentService;
|
||||||
|
this._qCListService = _qCListService;
|
||||||
|
this._iReadingImageTaskService = _iReadingImageTaskService;
|
||||||
|
this._httpContext = httpContext;
|
||||||
|
this._trialConfigService = _trialConfigService;
|
||||||
|
this._noneDicomStudyService = noneDicomStudyService;
|
||||||
|
this._subjectService = _subjectService;
|
||||||
|
this._readingClinicalDataService = _readingClinicalDataService;
|
||||||
|
this._subjectVisitService = subjectVisitService;
|
||||||
|
this._qCOperationService = qCOperationService;
|
||||||
|
this._clinicalDataService = clinicalDataService;
|
||||||
|
this._visitPlanService = visitPlanService;
|
||||||
|
this._dataInspectionRepository = dataInspectionRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 获取稽查数据
|
||||||
|
/// <summary>
|
||||||
|
/// 获取稽查数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/GetInspectionList")]
|
||||||
|
public async Task<PageOutput<GetDataInspectionOutDto>> GetInspectionList(GetDataInspectionDto dto)
|
||||||
|
{
|
||||||
|
return await _inspectionService.GetInspectionList(dto);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交肿瘤学阅片任务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingImageTask/SubmitOncologyReadingInfo")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SetOncologyReadingInfo(DataInspectionDto<SubmitOncologyReadingInfoInDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _iReadingImageTaskService.SubmitOncologyReadingInfo(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交Diocm阅片
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingImageTask/SubmitDicomVisitTask")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SubmitDicomVisitTask(DataInspectionDto<SubmitDicomVisitTaskInDto> opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _iReadingImageTaskService.SubmitDicomVisitTask(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交全局阅片任务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingImageTask/SubmitGlobalReadingInfo")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SubmitGlobalReadingInfo(DataInspectionDto<SubmitGlobalReadingInfoInDto> opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _iReadingImageTaskService.SubmitGlobalReadingInfo(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目阅片信息签名
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialReadingInfoSign")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> TrialReadingInfoSign(DataInspectionDto<TrialReadingInfoSignInDto> opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _trialConfigService.TrialReadingInfoSign(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 医学审核完成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingMedicalReview/FinishMedicalReview")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> FinishMedicalReview(DataInspectionDto<FinishMedicalReviewInDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _readingMedicalReviewService.FinishMedicalReview(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确认项目医学审核问题
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingMedicineQuestion/ConfirmReadingMedicineQuestion")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> ConfirmReadingMedicineQuestion(DataInspectionDto<ConfirmReadingMedicineQuestionInDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _readingMedicineQuestionService.ConfirmReadingMedicineQuestion(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交阅片问题
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingImageTask/SubmitVisitTaskQuestions")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SubmitVisitTaskQuestions(DataInspectionDto<SubmitVisitTaskQuestionsInDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _iReadingImageTaskService.SubmitVisitTaskQuestions(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 提交阅片裁判问题
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadingImageTask/SubmitJudgeVisitTaskResult")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SubmitJudgeVisitTaskResult(DataInspectionDto<SaveJudgeVisitTaskResult> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _iReadingImageTaskService.SubmitJudgeVisitTaskResult(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 基础逻辑信息并确认
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialBasicInfoConfirm")]
|
||||||
|
[UnitOfWork]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
|
||||||
|
public async Task<IResponseOutput> ConfigTrialBasicInfoConfirm(DataInspectionDto<BasicTrialConfig> opt)
|
||||||
|
{
|
||||||
|
|
||||||
|
opt.Data.IsTrialBasicLogicConfirmed = true;
|
||||||
|
var singid= await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _trialConfigService.ConfigTrialBasicInfo(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置流程并确认
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialProcessInfoConfirm")]
|
||||||
|
[UnitOfWork]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
|
||||||
|
public async Task<IResponseOutput> ConfigTrialProcessInfoConfirm(DataInspectionDto<TrialProcessConfig> opt)
|
||||||
|
{
|
||||||
|
opt.Data.IsTrialProcessConfirmed = true;
|
||||||
|
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _trialConfigService.ConfigTrialProcessInfo(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置加急信息并确认
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialUrgentInfoConfirm")]
|
||||||
|
[UnitOfWork]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
|
||||||
|
public async Task<IResponseOutput> ConfigTrialUrgentInfoConfirm(DataInspectionDto<TrialUrgentConfig> opt)
|
||||||
|
{
|
||||||
|
opt.Data.IsTrialUrgentConfirmed = true;
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result= await _trialConfigService.ConfigTrialUrgentInfo(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 签名确认
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialConfigSignatureConfirm")]
|
||||||
|
[UnitOfWork]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
|
||||||
|
public async Task<IResponseOutput> TrialConfigSignatureConfirm(DataInspectionDto<SignConfirmDTO> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _trialConfigService.TrialConfigSignatureConfirm(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IC RequestToQC 批量提交
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/QCOperation/CRCRequestToQC")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> CRCRequestToQC(DataInspectionDto<CRCRequestToQCCommand> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _qCOperationService.CRCRequestToQC(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置QC 通过或者不通过 7:QC failed 8:QC passed
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost, Route("Inspection/QCOperation/QCPassedOrFailed")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> QCPassedOrFailed(DataInspectionDto<QCPassedOrFailedDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result= await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一致性核查 回退 对话记录不清除 只允许PM回退
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost, Route("Inspection/QCOperation/CheckBack")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> CheckBack(DataInspectionDto<IDDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _qCOperationService.CheckBack(opt.Data.Id);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 影像阅片临床数据签名
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/ReadClinicalData/ReadClinicalDataSign")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> ReadClinicalDataSign(DataInspectionDto<ReadingClinicalDataSignIndto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _readingClinicalDataService.ReadClinicalDataSign(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IC 设置已经重传完成
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost, Route("Inspection/QCOperation/SetReuploadFinished")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> SetReuploadFinished(DataInspectionDto<CRCReuploadFinishedCommand> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _qCOperationService.SetReuploadFinished(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新项目状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/TrialConfig/updateTrialState")]
|
||||||
|
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> UpdateTrialState(DataInspectionDto<UpdateTrialStateDto> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _trialConfigService.UpdateTrialState(opt.Data.trialId, opt.Data.trialStatusStr, opt.Data.reason);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户 签名某个文档
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/TrialDocument/userConfirm")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IResponseOutput> UserConfirm(DataInspectionDto<UserConfirmCommand> opt)
|
||||||
|
{
|
||||||
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
opt.Data.SignText = opt.SignInfo.SignText;
|
||||||
|
var result = await _trialDocumentService.UserConfirm(opt.Data);
|
||||||
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重阅同意
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost, Route("Inspection/VisitTask/ConfirmReReading")]
|
||||||
|
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||||
|
[UnitOfWork]
|
||||||
|
|
||||||
|
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt , [FromServices] IVisitTaskHelpeService _visitTaskCommonService,[FromServices] IVisitTaskService _visitTaskService)
|
||||||
|
{
|
||||||
|
var singId = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _visitTaskService.ConfirmReReading(opt.Data, _visitTaskCommonService);
|
||||||
|
await _inspectionService.CompletedSign(singId, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,69 @@
|
||||||
|
// 使用的是proto3版本
|
||||||
|
syntax = "proto3";
|
||||||
|
// 定义命名空间,后续生成代码时就会生成对应的命名空间
|
||||||
|
option csharp_namespace = "gRPC.ZHiZHUN.AuthServer.protos";
|
||||||
|
|
||||||
|
/*
|
||||||
|
每一句需要用分号结尾
|
||||||
|
message 用来定义请求和返回数据格式
|
||||||
|
tag message后面的值数字代表是字段的标识(tag),不是赋值,
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||||
|
message GetTokenReuqest{
|
||||||
|
string id=1;
|
||||||
|
string userName=2;
|
||||||
|
string realName=3;
|
||||||
|
string reviewerCode=4;
|
||||||
|
int32 userTypeEnumInt=5;
|
||||||
|
string userTypeShortName=6;
|
||||||
|
bool isAdmin=7;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增时返回的消息格式
|
||||||
|
message GetTokenResponse {
|
||||||
|
int32 code=1;
|
||||||
|
string token =2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// service 用标识定义服务的,里面写对应的方法
|
||||||
|
service TokenGrpcService{
|
||||||
|
// 获取token
|
||||||
|
rpc GetUserToken(GetTokenReuqest) returns (GetTokenResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||||
|
message AddUserReuqest{
|
||||||
|
string name=1;
|
||||||
|
int32 age=2;
|
||||||
|
bool isBoy=3;
|
||||||
|
}
|
||||||
|
// 新增时返回的消息格式
|
||||||
|
message ResultResponse {
|
||||||
|
int32 code=1;
|
||||||
|
string msg =2;
|
||||||
|
}
|
||||||
|
//传递的查询条件信息格式,可理解为平时传入的查询条件对象
|
||||||
|
message QueryUserReuqest{
|
||||||
|
string name=1;
|
||||||
|
}
|
||||||
|
//查询返回的用户信息格式,可理解为返回的类
|
||||||
|
message UserInfoResponse {
|
||||||
|
string name=1;
|
||||||
|
int32 age=2;
|
||||||
|
string gender=3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// service 用标识定义服务的,里面写对应的方法
|
||||||
|
service UserService{
|
||||||
|
// 新增用户
|
||||||
|
rpc AddUser(AddUserReuqest) returns (ResultResponse);
|
||||||
|
// 查询用户
|
||||||
|
rpc GetAllUser(QueryUserReuqest) returns (UserInfoResponse);
|
||||||
|
}
|
||||||
|
*/
|
|
@ -0,0 +1,107 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<UserSecretsId>354572d4-9e15-4099-807c-63a2d29ff9f2</UserSecretsId>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<NoWarn>1701;1702;1591;</NoWarn>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<DocumentationFile>bin\Release\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<Compile Remove="UploadFile\**" />
|
||||||
|
<Content Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<Content Remove="UploadFile\**" />
|
||||||
|
<EmbeddedResource Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<EmbeddedResource Remove="UploadFile\**" />
|
||||||
|
<None Remove="Controllers\ReviewerApi\**" />
|
||||||
|
<None Remove="UploadFile\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="web.config" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.swagger.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove=".preview.jpg" />
|
||||||
|
<None Remove="GrpcToken.proto" />
|
||||||
|
<None Remove="IRaCIS.Core.API.xml" />
|
||||||
|
<None Remove="Protos\GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.swagger.js" />
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Protos\GrpcToken.proto">
|
||||||
|
<GrpcServices>Client</GrpcServices>
|
||||||
|
</Protobuf>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCoreRateLimit" Version="4.0.1" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" />
|
||||||
|
<PackageReference Include="EasyCaching.InMemory" Version="1.4.1" />
|
||||||
|
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.4.1" />
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.19.1" />
|
||||||
|
<PackageReference Include="Grpc.Net.Client" Version="2.41.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="2.42.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Hangfire.Tags.SqlServer" Version="1.8.0" />
|
||||||
|
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||||
|
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="1.1.4" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Email" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Application\IRaCIS.Core.Application.csproj" />
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\PublishProfiles\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="NLog.config">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ProjectExtensions><VisualStudio><UserProperties anonymizetagsetting_1json__JsonSchema="http://json.schemastore.org/jovo-language-model" /></VisualStudio></ProjectExtensions>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,179 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
<UserSecretsId>354572d4-9e15-4099-807c-63a2d29ff9f2</UserSecretsId>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<Copyright>武汉行藏科技有限公司版权所有</Copyright>
|
||||||
|
<AssemblyVersion></AssemblyVersion>
|
||||||
|
<FileVersion>1.0.1.001</FileVersion>
|
||||||
|
<Product>医学影像处理软件</Product>
|
||||||
|
<Version>1.0.1.001</Version>
|
||||||
|
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||||
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
|
<AssemblyName>EI_Image_Viewer</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<NoWarn>1701;1702;1591;</NoWarn>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<NoWarn>1701;1702;1591;</NoWarn>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||||
|
<DocumentationFile>.\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<NoWarn>1701;1702;1591;</NoWarn>
|
||||||
|
<OutputPath>..\bin\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<DocumentationFile>bin\Release\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<DocumentationFile>bin\Release\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
|
||||||
|
<DocumentationFile>bin\Release\IRaCIS.Core.API.xml</DocumentationFile>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="wwwroot\**" />
|
||||||
|
<EmbeddedResource Remove="UploadFile\**" />
|
||||||
|
<EmbeddedResource Remove="wwwroot\**" />
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="web.config" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\abp.swagger.js" />
|
||||||
|
<Content Remove="wwwroot\swagger\ui\Index.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove=".preview.jpg" />
|
||||||
|
<None Remove="GrpcToken.proto" />
|
||||||
|
<None Remove="IRaCIS.Core.API.xml" />
|
||||||
|
<None Remove="Protos\GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="GrpcToken.proto" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="favicon.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\abp.swagger.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="wwwroot\swagger\ui\Index.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Protos\GrpcToken.proto">
|
||||||
|
<GrpcServices>Client</GrpcServices>
|
||||||
|
</Protobuf>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCoreRateLimit" Version="4.0.2" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
|
||||||
|
<PackageReference Include="EasyCaching.InMemory" Version="1.7.0" />
|
||||||
|
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.7.0" />
|
||||||
|
<PackageReference Include="EntityFrameworkCore.Triggered.Extensions" Version="3.2.1" />
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.21.8" />
|
||||||
|
<PackageReference Include="Grpc.Net.Client" Version="2.49.0" />
|
||||||
|
<PackageReference Include="Grpc.Tools" Version="2.50.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Hangfire.Tags.SqlServer" Version="1.8.1" />
|
||||||
|
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||||
|
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.10" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.10" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.6.2" />
|
||||||
|
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.6.2" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="1.2.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Email" Version="2.4.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Application\IRaCIS.Core.Application.csproj" />
|
||||||
|
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\AdminResetUser.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\EmailConfigTest.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialSiteSurveyReject.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorExistJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserExistJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\AdminAddUser.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialDoctorFirstJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\SubjectEnrollConfirmOrPDProgress.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\UserOptCommon.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="wwwroot\EmailTemplate\TrialUserFirstJoin.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\PublishProfiles\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,557 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<doc>
|
||||||
|
<assembly>
|
||||||
|
<name>EI_Image_Viewer</name>
|
||||||
|
</assembly>
|
||||||
|
<members>
|
||||||
|
<member name="M:EasyCaching.Demo.Interceptors.Controllers.ErrorController.Error(System.Int32)">
|
||||||
|
<summary>
|
||||||
|
主要处理 前端404等错误 全局业务异常已统一处理了,非业务错误会来到这里
|
||||||
|
</summary>
|
||||||
|
<param name="code"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:IRaCIS.Api.Controllers.ExtraController">
|
||||||
|
<summary>
|
||||||
|
医生基本信息 、工作信息 专业信息、审核状态
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Api.Controllers.ExtraController.GetDoctorDetail(IRaCIS.Application.Interfaces.IAttachmentService,IRaCIS.Application.Interfaces.IDoctorService,IRaCIS.Application.Interfaces.IEducationService,IRaCIS.Application.Interfaces.ITrialExperienceService,IRaCIS.Application.Interfaces.IResearchPublicationService,IRaCIS.Application.Interfaces.IVacationService,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
获取医生详情
|
||||||
|
</summary>
|
||||||
|
<param name="attachmentService"></param>
|
||||||
|
<param name="_doctorService"></param>
|
||||||
|
<param name="_educationService"></param>
|
||||||
|
<param name="_trialExperienceService"></param>
|
||||||
|
<param name="_researchPublicationService"></param>
|
||||||
|
<param name="_vacationService"></param>
|
||||||
|
<param name="doctorId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Api.Controllers.ExtraController.Login(IRaCIS.Application.Contracts.UserLoginDTO,EasyCaching.Core.IEasyCachingProvider,IRaCIS.Application.Services.IUserService,IRaCIS.Core.Application.Auth.ITokenService,Microsoft.Extensions.Configuration.IConfiguration)">
|
||||||
|
<summary> 系统用户登录接口[New] </summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrial(IRaCIS.Application.Contracts.TrialCommand,IRaCIS.Application.Interfaces.ITrialConfigService)">
|
||||||
|
<summary> 添加实验项目-返回新增Id[AUTH]</summary>
|
||||||
|
<param name="param"></param>
|
||||||
|
<returns>新记录Id</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.WorkLoadAddOrUpdate(IRaCIS.Application.Services.IDoctorWorkloadService,IRaCIS.Application.Contracts.WorkloadCommand)">
|
||||||
|
<summary>
|
||||||
|
添加或更新工作量[AUTH]
|
||||||
|
</summary>
|
||||||
|
<param name="_trialWorkloadService"></param>
|
||||||
|
<param name="workLoadAddOrUpdateModel"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateExchangeRate(IRaCIS.Application.Interfaces.IExchangeRateService,IRaCIS.Application.Interfaces.IPaymentAdjustmentService,IRaCIS.Application.Contracts.ExchangeRateCommand)">
|
||||||
|
<summary>
|
||||||
|
添加或更新汇率(会触发没有对锁定的费用计算)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateRankPrice(IRaCIS.Application.Interfaces.IReviewerPayInfoService,IRaCIS.Application.Interfaces.IRankPriceService,IRaCIS.Application.Contracts.RankPriceCommand)">
|
||||||
|
<summary>
|
||||||
|
添加或更新 职称单价[AUTH]
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateReviewerPayInfo(IRaCIS.Application.Interfaces.IReviewerPayInfoService,IRaCIS.Application.Contracts.ReviewerPayInfoCommand)">
|
||||||
|
<summary>
|
||||||
|
添加或更新(替换)医生支付展信息[AUTH]
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateTrialPaymentPrice(IRaCIS.Application.Interfaces.ITrialPaymentPriceService,IRaCIS.Application.Contracts.TrialPaymentPriceCommand)">
|
||||||
|
<summary>
|
||||||
|
保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH]
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.AddOrUpdateAwardPriceList(IRaCIS.Application.Interfaces.IVolumeRewardService,System.Collections.Generic.IEnumerable{IRaCIS.Application.Interfaces.AwardPriceCommand})">
|
||||||
|
<summary>
|
||||||
|
批量更新奖励费用[AUTH]
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.CalculateMonthlyPayment(IRaCIS.Application.Contracts.CalculateDoctorAndMonthDTO)">
|
||||||
|
<summary>
|
||||||
|
计算医生月度费用,并将计算的结果存入费用表
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.Special.FinancialChangeController.GetMonthlyPaymentList(IRaCIS.Application.Interfaces.IPaymentService,IRaCIS.Application.Interfaces.IExchangeRateService,IRaCIS.Application.Contracts.MonthlyPaymentQueryDTO)">
|
||||||
|
<summary>
|
||||||
|
Financials /Monthly Payment 列表查询接口
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.GetInspectionList(IRaCIS.Core.Application.Service.Inspection.DTO.GetDataInspectionDto)">
|
||||||
|
<summary>
|
||||||
|
获取稽查数据
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SetOncologyReadingInfo(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SubmitOncologyReadingInfoInDto})">
|
||||||
|
<summary>
|
||||||
|
提交肿瘤学阅片任务
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitDicomVisitTask(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SubmitDicomVisitTaskInDto})">
|
||||||
|
<summary>
|
||||||
|
提交Diocm阅片
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitGlobalReadingInfo(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SubmitGlobalReadingInfoInDto})">
|
||||||
|
<summary>
|
||||||
|
提交全局阅片任务
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.TrialReadingInfoSign(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.TrialReadingInfoSignInDto})">
|
||||||
|
<summary>
|
||||||
|
项目阅片信息签名
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.FinishMedicalReview(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.FinishMedicalReviewInDto})">
|
||||||
|
<summary>
|
||||||
|
医学审核完成
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfirmReadingMedicineQuestion(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.ViewModel.ConfirmReadingMedicineQuestionInDto})">
|
||||||
|
<summary>
|
||||||
|
确认项目医学审核问题
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitVisitTaskQuestions(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SubmitVisitTaskQuestionsInDto})">
|
||||||
|
<summary>
|
||||||
|
提交阅片问题
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitJudgeVisitTaskResult(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SaveJudgeVisitTaskResult})">
|
||||||
|
<summary>
|
||||||
|
提交阅片裁判问题
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfigTrialBasicInfoConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.BasicTrialConfig})">
|
||||||
|
<summary>
|
||||||
|
配置 基础逻辑信息并确认
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfigTrialProcessInfoConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.TrialProcessConfig})">
|
||||||
|
<summary>
|
||||||
|
配置流程并确认
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfigTrialUrgentInfoConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.TrialUrgentConfig})">
|
||||||
|
<summary>
|
||||||
|
配置加急信息并确认
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.TrialConfigSignatureConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.SignConfirmDTO})">
|
||||||
|
<summary>
|
||||||
|
签名确认
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.CRCRequestToQC(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.CRCRequestToQCCommand})">
|
||||||
|
<summary>
|
||||||
|
IC RequestToQC 批量提交
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.QCPassedOrFailed(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Inspection.DTO.QCPassedOrFailedDto})">
|
||||||
|
<summary>
|
||||||
|
设置QC 通过或者不通过 7:QC failed 8:QC passed
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.CheckBack(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.IDDto})">
|
||||||
|
<summary>
|
||||||
|
一致性核查 回退 对话记录不清除 只允许PM回退
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ReadClinicalDataSign(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Inspection.DTO.ReadingClinicalDataSignIndto})">
|
||||||
|
<summary>
|
||||||
|
影像阅片临床数据签名
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SetReuploadFinished(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.CRCReuploadFinishedCommand})">
|
||||||
|
<summary>
|
||||||
|
IC 设置已经重传完成
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.UpdateTrialState(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Inspection.DTO.UpdateTrialStateDto})">
|
||||||
|
<summary>
|
||||||
|
更新项目状态
|
||||||
|
</summary>
|
||||||
|
<param name="opt"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.UserConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.UserConfirmCommand})">
|
||||||
|
<summary>
|
||||||
|
用户 签名某个文档
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfirmReReading(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.ViewModel.ConfirmReReadingCommand},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService)">
|
||||||
|
<summary>
|
||||||
|
重阅同意
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.SingleFileUploadAsync(System.Func{System.String,System.ValueTuple{System.String,System.String}})">
|
||||||
|
<summary> 流式上传 直接返回</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.FileUploadAsync(System.Func{System.String,System.Threading.Tasks.Task{System.String}})">
|
||||||
|
<summary> 流式上传 通用封装 不返回任何数据,后续还有事情处理 </summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Int32,System.Threading.Tasks.Task},System.String)">
|
||||||
|
<summary> 流式上传 Dicom上传 </summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
||||||
|
<summary>Dicom 归档</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitClinicalData(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传临床数据 多文件
|
||||||
|
</summary>
|
||||||
|
<param name="subjectVisitId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadClinicalTemplate(System.Nullable{System.Guid})">
|
||||||
|
<summary>
|
||||||
|
上传临床数据模板
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadReadClinicalData(System.Guid,System.Guid,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传阅片临床数据
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<param name="subjectId"></param>
|
||||||
|
<param name="readingId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadPrintscreen(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传截图
|
||||||
|
</summary>
|
||||||
|
<param name="subjectId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadReadingAnswerImage(System.Guid,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传Reading问题的图像
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<param name="visitTaskId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadJudgeTaskImage(System.Guid,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传裁判任务的图像
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<param name="visitTaskId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadMedicalReviewImage(System.Guid,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传医学审核图片
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<param name="taskMedicalReviewId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(Microsoft.AspNetCore.Http.IFormCollection,System.Guid,System.Guid,System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
|
||||||
|
<summary>
|
||||||
|
上传非Dicom 文件 支持压缩包 多文件上传
|
||||||
|
</summary>
|
||||||
|
<param name="formCollection"></param>
|
||||||
|
<param name="subjectVisitId"></param>
|
||||||
|
<param name="noneDicomStudyId"></param>
|
||||||
|
<param name="studyMonitorId"></param>
|
||||||
|
<param name="_noneDicomStudyRepository"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
一致性核查 excel上传 支持三种格式
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:IRaCIS.Core.API.Controllers.FileController">
|
||||||
|
<summary>医生文件上传下载</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.UploadOrdinaryFile(System.String,System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传文件[FileUpload]
|
||||||
|
</summary>
|
||||||
|
<param name="attachmentType">附件类型</param>
|
||||||
|
<param name="doctorId">医生Id</param>
|
||||||
|
<returns>返回文件信息</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.UploadNonDoctorFile(System.String)">
|
||||||
|
<summary>
|
||||||
|
上传文件( 不是医生个人的文件)[FileUpload]
|
||||||
|
例如:阅片章程等
|
||||||
|
</summary>
|
||||||
|
<param name="type">文件类型</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadAttachment(System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载多个医生的所有附件
|
||||||
|
</summary>
|
||||||
|
<param name="doctorIds"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadOfficialResume(System.Int32,System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载医生官方简历
|
||||||
|
</summary>
|
||||||
|
<param name="language"></param>
|
||||||
|
<param name="doctorIds"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.FileController.DownloadAttachmentById(System.Guid,System.Guid[])">
|
||||||
|
<summary>
|
||||||
|
下载指定医生的指定附件
|
||||||
|
</summary>
|
||||||
|
<param name="doctorId">医生Id</param>
|
||||||
|
<param name="attachmentIds">要下载的附件Id</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.LocalFilePreview(System.String)">
|
||||||
|
<summary> 缩略图 </summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadCommonFile(System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument})">
|
||||||
|
<summary> 通用文件下载 </summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadTrialClinicalFile(System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataTrialSet})">
|
||||||
|
<summary>
|
||||||
|
下载项目临床数据文件
|
||||||
|
</summary>
|
||||||
|
<param name="clinicalDataTrialSetId"></param>
|
||||||
|
<param name="_clinicalDataTrialSetRepository"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.DownloadSystemClinicalFile(System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataSystemSet})">
|
||||||
|
<summary>
|
||||||
|
下载系统临床数据文件
|
||||||
|
</summary>
|
||||||
|
<param name="clinicalDataSystemSetId"></param>
|
||||||
|
<param name="_clinicalDataSystemSetRepository"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadTrialDoc(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
上传项目签名文档
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadSysTemDoc">
|
||||||
|
<summary>
|
||||||
|
上传系统签名文档
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadCommonDoc">
|
||||||
|
<summary>
|
||||||
|
上传通用文档 比如一致性核查的 比如导出的excel 模板
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadSystemNoticeDoc">
|
||||||
|
<summary>
|
||||||
|
上传系统通知文档
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
|
||||||
|
<summary>
|
||||||
|
IPLimit限流 启动服务
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.API.NullToEmptyStringResolver.CreateProperties(System.Type,Newtonsoft.Json.MemberSerialization)">
|
||||||
|
<summary>
|
||||||
|
创建属性
|
||||||
|
</summary>
|
||||||
|
<param name="type">类型</param>
|
||||||
|
<param name="memberSerialization">序列化成员</param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.WX.CoreApi.Auth.AuthMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext)">
|
||||||
|
<summary>
|
||||||
|
为了前端 一段时间无操作,需要重新登陆
|
||||||
|
</summary>
|
||||||
|
<param name="httpContext"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomHSJWTService">
|
||||||
|
<summary>
|
||||||
|
对称可逆加密
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomHSJWTService.GetToken(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
用户登录成功以后,用来生成Token的方法
|
||||||
|
</summary>
|
||||||
|
<param name="UserName"></param>
|
||||||
|
<param name="password"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.CustomRSSJWTervice">
|
||||||
|
<summary>
|
||||||
|
非对称可逆加密
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.RSAHelper.TryGetKeyParameters(System.String,System.Boolean,System.Security.Cryptography.RSAParameters@)">
|
||||||
|
<summary>
|
||||||
|
从本地文件中读取用来签发 Token 的 RSA Key
|
||||||
|
</summary>
|
||||||
|
<param name="filePath">存放密钥的文件夹路径</param>
|
||||||
|
<param name="withPrivate"></param>
|
||||||
|
<param name="keyParameters"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt.RSAHelper.GenerateAndSaveKey(System.String,System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
生成并保存 RSA 公钥与私钥
|
||||||
|
</summary>
|
||||||
|
<param name="filePath"></param>
|
||||||
|
<param name="withPrivate"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection">
|
||||||
|
<summary>Holder for reflection information generated from Protos/GrpcToken.proto</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection.Descriptor">
|
||||||
|
<summary>File descriptor for Protos/GrpcToken.proto</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest">
|
||||||
|
<summary>
|
||||||
|
新增用户时需要传递数据消息, 可理解为一个类
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IdFieldNumber">
|
||||||
|
<summary>Field number for the "id" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserNameFieldNumber">
|
||||||
|
<summary>Field number for the "userName" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.RealNameFieldNumber">
|
||||||
|
<summary>Field number for the "realName" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.ReviewerCodeFieldNumber">
|
||||||
|
<summary>Field number for the "reviewerCode" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeEnumIntFieldNumber">
|
||||||
|
<summary>Field number for the "userTypeEnumInt" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeShortNameFieldNumber">
|
||||||
|
<summary>Field number for the "userTypeShortName" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IsAdminFieldNumber">
|
||||||
|
<summary>Field number for the "isAdmin" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse">
|
||||||
|
<summary>
|
||||||
|
新增时返回的消息格式
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.CodeFieldNumber">
|
||||||
|
<summary>Field number for the "code" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.TokenFieldNumber">
|
||||||
|
<summary>Field number for the "token" field.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService">
|
||||||
|
<summary>
|
||||||
|
service 用标识定义服务的,里面写对应的方法
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.Descriptor">
|
||||||
|
<summary>Service descriptor</summary>
|
||||||
|
</member>
|
||||||
|
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient">
|
||||||
|
<summary>Client for TokenGrpcService</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.ChannelBase)">
|
||||||
|
<summary>Creates a new client for TokenGrpcService</summary>
|
||||||
|
<param name="channel">The channel to use to make remote calls.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.CallInvoker)">
|
||||||
|
<summary>Creates a new client for TokenGrpcService that uses a custom <c>CallInvoker</c>.</summary>
|
||||||
|
<param name="callInvoker">The callInvoker to use to make remote calls.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor">
|
||||||
|
<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.#ctor(Grpc.Core.ClientBase.ClientBaseConfiguration)">
|
||||||
|
<summary>Protected constructor to allow creation of configured clients.</summary>
|
||||||
|
<param name="configuration">The client configuration.</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserToken(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.Metadata,System.Nullable{System.DateTime},System.Threading.CancellationToken)">
|
||||||
|
<summary>
|
||||||
|
获取token
|
||||||
|
</summary>
|
||||||
|
<param name="request">The request to send to the server.</param>
|
||||||
|
<param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
|
||||||
|
<param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
|
||||||
|
<param name="cancellationToken">An optional token for canceling the call.</param>
|
||||||
|
<returns>The response received from the server.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserToken(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.CallOptions)">
|
||||||
|
<summary>
|
||||||
|
获取token
|
||||||
|
</summary>
|
||||||
|
<param name="request">The request to send to the server.</param>
|
||||||
|
<param name="options">The options for the call.</param>
|
||||||
|
<returns>The response received from the server.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserTokenAsync(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.Metadata,System.Nullable{System.DateTime},System.Threading.CancellationToken)">
|
||||||
|
<summary>
|
||||||
|
获取token
|
||||||
|
</summary>
|
||||||
|
<param name="request">The request to send to the server.</param>
|
||||||
|
<param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
|
||||||
|
<param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
|
||||||
|
<param name="cancellationToken">An optional token for canceling the call.</param>
|
||||||
|
<returns>The call object.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.GetUserTokenAsync(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.CallOptions)">
|
||||||
|
<summary>
|
||||||
|
获取token
|
||||||
|
</summary>
|
||||||
|
<param name="request">The request to send to the server.</param>
|
||||||
|
<param name="options">The options for the call.</param>
|
||||||
|
<returns>The call object.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceClient.NewInstance(Grpc.Core.ClientBase.ClientBaseConfiguration)">
|
||||||
|
<summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
</doc>
|
|
@ -0,0 +1,186 @@
|
||||||
|
using System;
|
||||||
|
using Autofac.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Serilog;
|
||||||
|
using MediatR;
|
||||||
|
using IRaCIS.Core.Application.MediatR.Handlers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MassTransit;
|
||||||
|
using MassTransit.NewIdProviders;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public readonly string environment;
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(enviromentName))
|
||||||
|
{
|
||||||
|
|
||||||
|
var index = Array.IndexOf(args, "--env");
|
||||||
|
enviromentName = index > -1
|
||||||
|
? args[index + 1]
|
||||||
|
: "Development";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Dicom 浏览
|
||||||
|
//ImageManager.SetImplementation(WinFormsImageManager.Instance);
|
||||||
|
|
||||||
|
var host = CreateHostBuilder(args)
|
||||||
|
.UseEnvironment(enviromentName) //命令行传入环境
|
||||||
|
.ConfigureAppConfiguration((hostContext, config) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
//Console.WriteLine(hostContext.HostingEnvironment.EnvironmentName);
|
||||||
|
config.AddJsonFile("appsettings.json", false, true)
|
||||||
|
.AddJsonFile($"appsettings.{enviromentName}.json", false, true);
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//// Serilog
|
||||||
|
SerilogExtension.AddSerilogSetup(enviromentName, host.Services);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 认证程序
|
||||||
|
//if (!File.Exists($@"C:\ProgramData\.xingcang\config.json"))
|
||||||
|
//{
|
||||||
|
// Console.WriteLine("当前未注册");
|
||||||
|
// Log.Logger.Error("当前未注册");
|
||||||
|
// Console.ReadLine();
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// var json = File.ReadAllText($@"C:\ProgramData\.xingcang\config.json");
|
||||||
|
|
||||||
|
// JObject jsonObject = JObject.Parse(json);
|
||||||
|
|
||||||
|
// var key = jsonObject["key"].ToString();
|
||||||
|
|
||||||
|
// var value = jsonObject["value"].ToString();
|
||||||
|
|
||||||
|
|
||||||
|
// var physicalAddressList = NetworkInterface.GetAllNetworkInterfaces().Select(t => t.GetPhysicalAddress().ToString());
|
||||||
|
|
||||||
|
// // 判断文件里面的机器码是否是本机的
|
||||||
|
// if (!physicalAddressList.Contains(key))
|
||||||
|
// {
|
||||||
|
// Console.WriteLine("机器码和本机不对应");
|
||||||
|
// Log.Logger.Error("机器码和本机不对应");
|
||||||
|
// Console.ReadLine();
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// var secrete = MD5Helper.Md5($"{key}_XINGCANG");
|
||||||
|
|
||||||
|
// if (value != secrete)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine("机器码和注册码不匹配");
|
||||||
|
// Log.Logger.Error("机器码和注册码不匹配");
|
||||||
|
// Console.ReadLine();
|
||||||
|
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//缓存项目的状态 匿名化数据
|
||||||
|
await InitCache(host);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
Log.Logger.Warning($"当前环境:{enviromentName}");
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log.Logger.Error(e.InnerException is null ? e.Message + e.StackTrace : e.InnerException?.Message + e.InnerException?.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.UseWindowsService()
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.ConfigureKestrel((context, options) =>
|
||||||
|
{
|
||||||
|
//设置应用服务器Kestrel请求体最大为1GB // if don't set default value is: 30 MB
|
||||||
|
options.Limits.MaxRequestBodySize = long.MaxValue;
|
||||||
|
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30);
|
||||||
|
options.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(20);
|
||||||
|
|
||||||
|
});
|
||||||
|
//webBuilder.UseSerilog();//在宿主机启动的时候配置serilog,与微软ILogger进行整合
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
}).UseSerilog()
|
||||||
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory());//使用Autofac替代本身容器
|
||||||
|
//ConfigureLogging(logging =>
|
||||||
|
//{
|
||||||
|
// logging.ClearProviders();
|
||||||
|
// logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
|
||||||
|
//})
|
||||||
|
//.UseNLog()
|
||||||
|
// NLog: Setup NLog for Dependency injection;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static async Task InitCache(IHost host)
|
||||||
|
{
|
||||||
|
var _mediator = host.Services.GetService(typeof(IMediator)) as IMediator;
|
||||||
|
|
||||||
|
await _mediator.Send(new AnonymizeCacheRequest());
|
||||||
|
|
||||||
|
await _mediator.Send(new TrialStateCacheRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:3305",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IRaCIS.Development": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:6100"
|
||||||
|
},
|
||||||
|
"Docker": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||||
|
"publishAllPorts": true
|
||||||
|
},
|
||||||
|
"IRaCIS.Staging": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Staging"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:6200"
|
||||||
|
},
|
||||||
|
"IRaCIS.Production": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Production"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:6300"
|
||||||
|
},
|
||||||
|
"IRaCIS.CertificateApply": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "CertificateApply"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:6400"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
// 使用的是proto3版本
|
||||||
|
syntax = "proto3";
|
||||||
|
// 定义命名空间,后续生成代码时就会生成对应的命名空间
|
||||||
|
option csharp_namespace = "gRPC.ZHiZHUN.AuthServer.protos";
|
||||||
|
|
||||||
|
/*
|
||||||
|
每一句需要用分号结尾
|
||||||
|
message 用来定义请求和返回数据格式
|
||||||
|
tag message后面的值数字代表是字段的标识(tag),不是赋值,
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||||
|
message GetTokenReuqest{
|
||||||
|
string id=1;
|
||||||
|
string userName=2;
|
||||||
|
string realName=3;
|
||||||
|
string reviewerCode=4;
|
||||||
|
int32 userTypeEnumInt=5;
|
||||||
|
string userTypeShortName=6;
|
||||||
|
bool isAdmin=7;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增时返回的消息格式
|
||||||
|
message GetTokenResponse {
|
||||||
|
int32 code=1;
|
||||||
|
string token =2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// service 用标识定义服务的,里面写对应的方法
|
||||||
|
service TokenGrpcService{
|
||||||
|
// 获取token
|
||||||
|
rpc GetUserToken(GetTokenReuqest) returns (GetTokenResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||||
|
message AddUserReuqest{
|
||||||
|
string name=1;
|
||||||
|
int32 age=2;
|
||||||
|
bool isBoy=3;
|
||||||
|
}
|
||||||
|
// 新增时返回的消息格式
|
||||||
|
message ResultResponse {
|
||||||
|
int32 code=1;
|
||||||
|
string msg =2;
|
||||||
|
}
|
||||||
|
//传递的查询条件信息格式,可理解为平时传入的查询条件对象
|
||||||
|
message QueryUserReuqest{
|
||||||
|
string name=1;
|
||||||
|
}
|
||||||
|
//查询返回的用户信息格式,可理解为返回的类
|
||||||
|
message UserInfoResponse {
|
||||||
|
string name=1;
|
||||||
|
int32 age=2;
|
||||||
|
string gender=3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// service 用标识定义服务的,里面写对应的方法
|
||||||
|
service UserService{
|
||||||
|
// 新增用户
|
||||||
|
rpc AddUser(AddUserReuqest) returns (ResultResponse);
|
||||||
|
// 查询用户
|
||||||
|
rpc GetAllUser(QueryUserReuqest) returns (UserInfoResponse);
|
||||||
|
}
|
||||||
|
*/
|
|
@ -0,0 +1,58 @@
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public interface IUploadClient
|
||||||
|
{
|
||||||
|
Task ReceivProgressAsync(string studyInstanceUid, int haveReceivedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class IRaCISUserIdProvider : IUserIdProvider
|
||||||
|
{
|
||||||
|
public virtual string GetUserId(HubConnectionContext connection)
|
||||||
|
{
|
||||||
|
return connection.User?.FindFirst(JwtIRaCISClaimType.Id)?.Value!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[DisableCors]
|
||||||
|
public class UploadHub : Hub<IUploadClient>
|
||||||
|
{
|
||||||
|
|
||||||
|
public ILogger<UploadHub> _logger { get; set; }
|
||||||
|
//public IUserInfo _userInfo { get; set; }
|
||||||
|
public UploadHub(/*IUserInfo userInfo,*/ ILogger<UploadHub> logger)
|
||||||
|
{
|
||||||
|
//_userInfo = userInfo;
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
//base.Context.User.id
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogError("连接: " + Context.ConnectionId);
|
||||||
|
|
||||||
|
|
||||||
|
return base.OnConnectedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
//public async Task SendProgress(string studyInstanceUid, int haveReceivedCount)
|
||||||
|
//{
|
||||||
|
|
||||||
|
|
||||||
|
// await Clients.All.ReceivProgressAsync(studyInstanceUid, haveReceivedCount);
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
using Autofac;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System;
|
||||||
|
using IRaCIS.Core.Application.Filter;
|
||||||
|
using LogDashboard;
|
||||||
|
using MediatR;
|
||||||
|
using IRaCIS.Core.Application.MediatR.Handlers;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using AspNetCoreRateLimit;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using System.Globalization;
|
||||||
|
using Microsoft.AspNetCore.Localization;
|
||||||
|
using Localization;
|
||||||
|
using Magicodes.ExporterAndImporter.Core.Filters;
|
||||||
|
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
|
||||||
|
using IRaCIS.Core.Infra.EFCore.Common;
|
||||||
|
using Invio.Extensions.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
public ILogger<Startup> _logger { get; }
|
||||||
|
|
||||||
|
public IConfiguration _configuration { get; }
|
||||||
|
|
||||||
|
//// ConfigureContainer is where you can register things directly
|
||||||
|
//// with Autofac. This runs after ConfigureServices so the things
|
||||||
|
//// here will override registrations made in ConfigureServices.
|
||||||
|
//// Don't build the container; that gets done for you by the factory.
|
||||||
|
// for castle
|
||||||
|
public void ConfigureContainer(ContainerBuilder containerBuilder)
|
||||||
|
{
|
||||||
|
containerBuilder.RegisterModule<AutofacModuleSetup>();
|
||||||
|
|
||||||
|
#region Test
|
||||||
|
//containerBuilder.RegisterType<ClinicalDataService>().PropertiesAutowired().InstancePerLifetimeScope();//注册仓储
|
||||||
|
|
||||||
|
//var container = containerBuilder.Build();
|
||||||
|
|
||||||
|
//// Now you can resolve services using Autofac. For example,
|
||||||
|
//// this line will execute the lambda expression registered
|
||||||
|
//// to the IConfigReader service.
|
||||||
|
//using (var scope = container.BeginLifetimeScope())
|
||||||
|
//{
|
||||||
|
// var reader = scope.Resolve<BaseService>();
|
||||||
|
|
||||||
|
// var test = scope.Resolve<ClinicalDataService>();
|
||||||
|
// var test2 = scope.Resolve<IClinicalDataService>();
|
||||||
|
|
||||||
|
// var test3 = scope.Resolve<IEFUnitOfWork<IRaCISDBContext>>();
|
||||||
|
//}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
//本地化
|
||||||
|
services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
|
||||||
|
|
||||||
|
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||||
|
services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
//options.Filters.Add<LogActionFilter>();
|
||||||
|
options.Filters.Add<ModelActionFilter>();
|
||||||
|
options.Filters.Add<ProjectExceptionFilter>();
|
||||||
|
options.Filters.Add<UnitOfWorkFilter>();
|
||||||
|
|
||||||
|
if (_configuration.GetSection("BasicSystemConfig").GetValue<bool>("OpenLoginLimit"))
|
||||||
|
{
|
||||||
|
options.Filters.Add<LimitUserRequestAuthorization>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.AddNewtonsoftJsonSetup(); // NewtonsoftJson 序列化 处理
|
||||||
|
|
||||||
|
services.AddOptions().Configure<SystemEmailSendConfig>( _configuration.GetSection("SystemEmailSendConfig"));
|
||||||
|
services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
||||||
|
services.AddDynamicWebApiSetup();
|
||||||
|
//AutoMapper
|
||||||
|
services.AddAutoMapperSetup();
|
||||||
|
//EF ORM QueryWithNoLock
|
||||||
|
services.AddEFSetup(_configuration);
|
||||||
|
//Http 响应压缩
|
||||||
|
services.AddResponseCompressionSetup();
|
||||||
|
//Swagger Api 文档
|
||||||
|
services.AddSwaggerSetup();
|
||||||
|
//JWT Token 验证
|
||||||
|
services.AddJWTAuthSetup(_configuration);
|
||||||
|
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||||||
|
services.AddMediatR(typeof(ConsistencyVerificationHandler).Assembly);
|
||||||
|
// EasyCaching 缓存
|
||||||
|
services.AddEasyCachingSetup();
|
||||||
|
|
||||||
|
//services.AddDistributedMemoryCache();
|
||||||
|
|
||||||
|
// hangfire 定时任务框架 有界面,更友好~
|
||||||
|
//services.AddhangfireSetup(_configuration);
|
||||||
|
|
||||||
|
// QuartZ 定时任务框架 使用了hangfire 暂时不用,后续需要可以打开,已经配好
|
||||||
|
services.AddQuartZSetup(_configuration);
|
||||||
|
|
||||||
|
// 保护上传文件
|
||||||
|
//services.AddStaticFileAuthorizationSetup();
|
||||||
|
|
||||||
|
|
||||||
|
////HttpReports 暂时废弃
|
||||||
|
//services.AddHttpReports().AddHttpTransport();
|
||||||
|
//Serilog 日志可视化 LogDashboard日志
|
||||||
|
services.AddLogDashboardSetup();
|
||||||
|
//上传限制 配置
|
||||||
|
services.Configure<FormOptions>(options =>
|
||||||
|
{
|
||||||
|
options.MultipartBodyLengthLimit = int.MaxValue;
|
||||||
|
options.ValueCountLimit = int.MaxValue;
|
||||||
|
options.ValueLengthLimit = int.MaxValue;
|
||||||
|
});
|
||||||
|
//IP 限流 可设置白名单 或者黑名单
|
||||||
|
//services.AddIpPolicyRateLimitSetup(_configuration);
|
||||||
|
// 用户类型 策略授权
|
||||||
|
//services.AddAuthorizationPolicySetup(_configuration);
|
||||||
|
|
||||||
|
services.AddJsonConfigSetup(_configuration);
|
||||||
|
//转发头设置 获取真实IP
|
||||||
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ForwardedHeaders =
|
||||||
|
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
});
|
||||||
|
//Dicom影像渲染图片 跨平台
|
||||||
|
services.AddDicomSetup();
|
||||||
|
|
||||||
|
// 实时应用
|
||||||
|
services.AddSignalR();
|
||||||
|
|
||||||
|
|
||||||
|
services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
|
||||||
|
|
||||||
|
//services.AddSingleton<IImportResultFilter, ImportResultFilteTest>();
|
||||||
|
|
||||||
|
services.AddMemoryCache();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
//本地化
|
||||||
|
app.UseLocalization();
|
||||||
|
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
|
||||||
|
//响应压缩
|
||||||
|
app.UseResponseCompression();
|
||||||
|
|
||||||
|
|
||||||
|
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||||||
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
|
||||||
|
//LogDashboard
|
||||||
|
app.UseLogDashboard("/LogDashboard");
|
||||||
|
|
||||||
|
////hangfire
|
||||||
|
//app.UseHangfireConfig(env);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//app.UseHsts();
|
||||||
|
}
|
||||||
|
Console.WriteLine("当前环境: " + env.EnvironmentName);
|
||||||
|
|
||||||
|
|
||||||
|
// 特殊异常处理 比如 404
|
||||||
|
app.UseStatusCodePagesWithReExecute("/Error/{0}");
|
||||||
|
|
||||||
|
SwaggerSetup.Configure(app, env);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////serilog 记录请求的用户信息
|
||||||
|
app.UseSerilogConfig(env);
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
||||||
|
|
||||||
|
app.UseIRacisHostStaticFileStore(env);
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
endpoints.MapControllers();
|
||||||
|
|
||||||
|
endpoints.MapHub<UploadHub>("/UploadHub");
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace EFSaving.Concurrency
|
||||||
|
{
|
||||||
|
public class Sample
|
||||||
|
{
|
||||||
|
public static void Run()
|
||||||
|
{
|
||||||
|
// Ensure database is created and has a person in it
|
||||||
|
using (var setupContext = new PersonContext())
|
||||||
|
{
|
||||||
|
setupContext.Database.EnsureDeleted();
|
||||||
|
setupContext.Database.EnsureCreated();
|
||||||
|
|
||||||
|
setupContext.People.Add(new Person { FirstName = "John", LastName = "Doe" });
|
||||||
|
setupContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region ConcurrencyHandlingCode
|
||||||
|
using var context = new PersonContext();
|
||||||
|
// Fetch a person from database and change phone number
|
||||||
|
var person = context.People.Single(p => p.PersonId == 1);
|
||||||
|
person.PhoneNumber = "555-555-5555";
|
||||||
|
|
||||||
|
// Change the person's name in the database to simulate a concurrency conflict
|
||||||
|
context.Database.ExecuteSqlRaw(
|
||||||
|
"UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");
|
||||||
|
|
||||||
|
var saved = false;
|
||||||
|
while (!saved)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Attempt to save changes to the database
|
||||||
|
context.SaveChanges();
|
||||||
|
saved = true;
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException ex)
|
||||||
|
{
|
||||||
|
foreach (var entry in ex.Entries)
|
||||||
|
{
|
||||||
|
if (entry.Entity is Person)
|
||||||
|
{
|
||||||
|
var proposedValues = entry.CurrentValues;
|
||||||
|
var databaseValues = entry.GetDatabaseValues();
|
||||||
|
|
||||||
|
foreach (var property in proposedValues.Properties)
|
||||||
|
{
|
||||||
|
var proposedValue = proposedValues[property];
|
||||||
|
var databaseValue = databaseValues[property];
|
||||||
|
|
||||||
|
// TODO: decide which value should be written to database
|
||||||
|
// proposedValues[property] = <value to be saved>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh original values to bypass next concurrency check
|
||||||
|
entry.OriginalValues.SetValues(databaseValues);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotSupportedException(
|
||||||
|
"Don't know how to handle concurrency conflicts for "
|
||||||
|
+ entry.Metadata.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PersonContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Person> People { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
// Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer
|
||||||
|
optionsBuilder.UseSqlServer(
|
||||||
|
@"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public int PersonId { get; set; }
|
||||||
|
|
||||||
|
[ConcurrencyCheck]
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
[ConcurrencyCheck]
|
||||||
|
public string LastName { get; set; }
|
||||||
|
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Filter
|
||||||
|
{
|
||||||
|
public class EnableBufferingAttribute : Attribute, IResourceFilter
|
||||||
|
{
|
||||||
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
{
|
||||||
|
context.HttpContext.Request.EnableBuffering();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Utility
|
||||||
|
{
|
||||||
|
public static class FileHelpers
|
||||||
|
{
|
||||||
|
private static readonly byte[] _allowedChars = { };
|
||||||
|
// For more file signatures, see the File Signatures Database (https://www.filesignatures.net/)
|
||||||
|
// and the official specifications for the file types you wish to add.
|
||||||
|
private static readonly Dictionary<string, List<byte[]>> _fileSignature = new Dictionary<string, List<byte[]>>
|
||||||
|
{
|
||||||
|
{ ".gif", new List<byte[]> { new byte[] { 0x47, 0x49, 0x46, 0x38 } } },
|
||||||
|
{ ".png", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
|
||||||
|
{ ".jpeg", new List<byte[]>
|
||||||
|
{
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ ".jpg", new List<byte[]>
|
||||||
|
{
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
|
||||||
|
new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ ".zip", new List<byte[]>
|
||||||
|
{
|
||||||
|
new byte[] { 0x50, 0x4B, 0x03, 0x04 },
|
||||||
|
new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x45 },
|
||||||
|
new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 },
|
||||||
|
new byte[] { 0x50, 0x4B, 0x05, 0x06 },
|
||||||
|
new byte[] { 0x50, 0x4B, 0x07, 0x08 },
|
||||||
|
new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// **WARNING!**
|
||||||
|
// In the following file processing methods, the file's content isn't scanned.
|
||||||
|
// In most production scenarios, an anti-virus/anti-malware scanner API is
|
||||||
|
// used on the file before making the file available to users or other
|
||||||
|
// systems. For more information, see the topic that accompanies this sample
|
||||||
|
// app.
|
||||||
|
|
||||||
|
public static async Task<byte[]> ProcessFormFile<T>(IFormFile formFile,
|
||||||
|
ModelStateDictionary modelState, string[] permittedExtensions,
|
||||||
|
long sizeLimit)
|
||||||
|
{
|
||||||
|
var fieldDisplayName = string.Empty;
|
||||||
|
|
||||||
|
// Use reflection to obtain the display name for the model
|
||||||
|
// property associated with this IFormFile. If a display
|
||||||
|
// name isn't found, error messages simply won't show
|
||||||
|
// a display name.
|
||||||
|
MemberInfo property =
|
||||||
|
typeof(T).GetProperty(
|
||||||
|
formFile.Name.Substring(formFile.Name.IndexOf(".",
|
||||||
|
StringComparison.Ordinal) + 1));
|
||||||
|
|
||||||
|
if (property != null)
|
||||||
|
{
|
||||||
|
if (property.GetCustomAttribute(typeof(DisplayAttribute)) is
|
||||||
|
DisplayAttribute displayAttribute)
|
||||||
|
{
|
||||||
|
fieldDisplayName = $"{displayAttribute.Name} ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't trust the file name sent by the client. To display
|
||||||
|
// the file name, HTML-encode the value.
|
||||||
|
var trustedFileNameForDisplay = WebUtility.HtmlEncode(
|
||||||
|
formFile.FileName);
|
||||||
|
|
||||||
|
// Check the file length. This check doesn't catch files that only have
|
||||||
|
// a BOM as their content.
|
||||||
|
if (formFile.Length == 0)
|
||||||
|
{
|
||||||
|
modelState.AddModelError(formFile.Name,
|
||||||
|
$"{fieldDisplayName}({trustedFileNameForDisplay}) is empty.");
|
||||||
|
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formFile.Length > sizeLimit)
|
||||||
|
{
|
||||||
|
var megabyteSizeLimit = sizeLimit / 1048576;
|
||||||
|
modelState.AddModelError(formFile.Name,
|
||||||
|
$"{fieldDisplayName}({trustedFileNameForDisplay}) exceeds " +
|
||||||
|
$"{megabyteSizeLimit:N1} MB.");
|
||||||
|
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
await formFile.CopyToAsync(memoryStream);
|
||||||
|
|
||||||
|
// Check the content length in case the file's only
|
||||||
|
// content was a BOM and the content is actually
|
||||||
|
// empty after removing the BOM.
|
||||||
|
if (memoryStream.Length == 0)
|
||||||
|
{
|
||||||
|
modelState.AddModelError(formFile.Name,
|
||||||
|
$"{fieldDisplayName}({trustedFileNameForDisplay}) is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidFileExtensionAndSignature(
|
||||||
|
formFile.FileName, memoryStream, permittedExtensions))
|
||||||
|
{
|
||||||
|
modelState.AddModelError(formFile.Name,
|
||||||
|
$"{fieldDisplayName}({trustedFileNameForDisplay}) file " +
|
||||||
|
"type isn't permitted or the file's signature " +
|
||||||
|
"doesn't match the file's extension.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
modelState.AddModelError(formFile.Name,
|
||||||
|
$"{fieldDisplayName}({trustedFileNameForDisplay}) upload failed. " +
|
||||||
|
$"Please contact the Help Desk for support. Error: {ex.HResult}");
|
||||||
|
}
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<byte[]> ProcessStreamedFile(
|
||||||
|
MultipartSection section, ContentDispositionHeaderValue contentDisposition,
|
||||||
|
ModelStateDictionary modelState, string[] permittedExtensions, long sizeLimit)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
await section.Body.CopyToAsync(memoryStream);
|
||||||
|
|
||||||
|
// Check if the file is empty or exceeds the size limit.
|
||||||
|
if (memoryStream.Length == 0)
|
||||||
|
{
|
||||||
|
modelState.AddModelError("File", "The file is empty.");
|
||||||
|
}
|
||||||
|
else if (memoryStream.Length > sizeLimit)
|
||||||
|
{
|
||||||
|
var megabyteSizeLimit = sizeLimit / 1048576;
|
||||||
|
modelState.AddModelError("File",
|
||||||
|
$"The file exceeds {megabyteSizeLimit:N1} MB.");
|
||||||
|
}
|
||||||
|
else if (!IsValidFileExtensionAndSignature(
|
||||||
|
contentDisposition.FileName.Value, memoryStream,
|
||||||
|
permittedExtensions))
|
||||||
|
{
|
||||||
|
modelState.AddModelError("File",
|
||||||
|
"The file type isn't permitted or the file's " +
|
||||||
|
"signature doesn't match the file's extension.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
modelState.AddModelError("File",
|
||||||
|
"The upload failed. Please contact the Help Desk " +
|
||||||
|
$" for support. Error: {ex.HResult}");
|
||||||
|
// Log the exception
|
||||||
|
}
|
||||||
|
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidFileExtensionAndSignature(string fileName, Stream data, string[] permittedExtensions)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fileName) || data == null || data.Length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(ext) || !permittedExtensions.Contains(ext))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Position = 0;
|
||||||
|
|
||||||
|
using (var reader = new BinaryReader(data))
|
||||||
|
{
|
||||||
|
if (ext.Equals(".txt") || ext.Equals(".csv") || ext.Equals(".prn"))
|
||||||
|
{
|
||||||
|
if (_allowedChars.Length == 0)
|
||||||
|
{
|
||||||
|
// Limits characters to ASCII encoding.
|
||||||
|
for (var i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
if (reader.ReadByte() > sbyte.MaxValue)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Limits characters to ASCII encoding and
|
||||||
|
// values of the _allowedChars array.
|
||||||
|
for (var i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
var b = reader.ReadByte();
|
||||||
|
if (b > sbyte.MaxValue ||
|
||||||
|
!_allowedChars.Contains(b))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment the following code block if you must permit
|
||||||
|
// files whose signature isn't provided in the _fileSignature
|
||||||
|
// dictionary. We recommend that you add file signatures
|
||||||
|
// for files (when possible) for all file types you intend
|
||||||
|
// to allow on the system and perform the file signature
|
||||||
|
// check.
|
||||||
|
|
||||||
|
//if (!_fileSignature.ContainsKey(ext))
|
||||||
|
//{
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
// File signature check
|
||||||
|
// --------------------
|
||||||
|
// With the file signatures provided in the _fileSignature
|
||||||
|
// dictionary, the following code tests the input content's
|
||||||
|
// file signature.
|
||||||
|
|
||||||
|
//var signatures = _fileSignature[ext];
|
||||||
|
//var headerBytes = reader.ReadBytes(signatures.Max(m => m.Length));
|
||||||
|
|
||||||
|
//return signatures.Any(signature =>
|
||||||
|
// headerBytes.Take(signature.Length).SequenceEqual(signature));
|
||||||
|
|
||||||
|
//test
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 对称可逆加密
|
||||||
|
/// </summary>
|
||||||
|
public class CustomHSJWTService : ICustomJWTService
|
||||||
|
{
|
||||||
|
#region Option注入
|
||||||
|
private readonly JWTTokenOptions _JWTTokenOptions;
|
||||||
|
public CustomHSJWTService(IOptionsMonitor<JWTTokenOptions> jwtTokenOptions)
|
||||||
|
{
|
||||||
|
this._JWTTokenOptions = jwtTokenOptions.CurrentValue;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户登录成功以后,用来生成Token的方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="UserName"></param>
|
||||||
|
/// <param name="password"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetToken(string UserName, string password)
|
||||||
|
{
|
||||||
|
#region 有效载荷,大家可以自己写,爱写多少写多少;尽量避免敏感信息
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, UserName),
|
||||||
|
new Claim("NickName",UserName),
|
||||||
|
new Claim("Role","Administrator"),//传递其他信息
|
||||||
|
new Claim("ABCC","ABCC"),
|
||||||
|
new Claim("ABCCDDDDD","ABCCDDDDD"),
|
||||||
|
new Claim("Student","甜酱油")
|
||||||
|
};
|
||||||
|
|
||||||
|
//需要加密:需要加密key:
|
||||||
|
//Nuget引入:Microsoft.IdentityModel.Tokens
|
||||||
|
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_JWTTokenOptions.SecurityKey));
|
||||||
|
|
||||||
|
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
//Nuget引入:System.IdentityModel.Tokens.Jwt
|
||||||
|
JwtSecurityToken token = new JwtSecurityToken(
|
||||||
|
issuer: _JWTTokenOptions.Issuer,
|
||||||
|
audience: _JWTTokenOptions.Audience,
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.Now.AddMinutes(5),//5分钟有效期
|
||||||
|
signingCredentials: creds);
|
||||||
|
|
||||||
|
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
return returnToken;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 非对称可逆加密
|
||||||
|
/// </summary>
|
||||||
|
public class CustomRSSJWTervice : ICustomJWTService
|
||||||
|
|
||||||
|
{
|
||||||
|
#region Option注入
|
||||||
|
private readonly JWTTokenOptions _JWTTokenOptions;
|
||||||
|
public CustomRSSJWTervice(IOptionsMonitor<JWTTokenOptions> jwtTokenOptions)
|
||||||
|
{
|
||||||
|
this._JWTTokenOptions = jwtTokenOptions.CurrentValue;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public string GetToken(string userName, string password)
|
||||||
|
{
|
||||||
|
#region 使用加密解密Key 非对称
|
||||||
|
string keyDir = Directory.GetCurrentDirectory();
|
||||||
|
if (RSAHelper.TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)
|
||||||
|
{
|
||||||
|
keyParams = RSAHelper.GenerateAndSaveKey(keyDir);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//string jtiCustom = Guid.NewGuid().ToString();//用来标识 Token
|
||||||
|
Claim[] claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, userName),
|
||||||
|
new Claim(ClaimTypes.Role,"admin"),
|
||||||
|
new Claim("password",password)
|
||||||
|
};
|
||||||
|
|
||||||
|
SigningCredentials credentials = new SigningCredentials(new RsaSecurityKey(keyParams), SecurityAlgorithms.RsaSha256Signature);
|
||||||
|
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: this._JWTTokenOptions.Issuer,
|
||||||
|
audience: this._JWTTokenOptions.Audience,
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.Now.AddMinutes(60),//5分钟有效期
|
||||||
|
signingCredentials: credentials);
|
||||||
|
|
||||||
|
var handler = new JwtSecurityTokenHandler();
|
||||||
|
string tokenString = handler.WriteToken(token);
|
||||||
|
return tokenString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt
|
||||||
|
{
|
||||||
|
public interface ICustomJWTService
|
||||||
|
{
|
||||||
|
string GetToken(string UserName, string password);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt
|
||||||
|
{
|
||||||
|
public class JWTTokenOptions
|
||||||
|
{
|
||||||
|
public string Audience
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
public string SecurityKey
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
//public SigningCredentials Credentials
|
||||||
|
//{
|
||||||
|
// get;
|
||||||
|
// set;
|
||||||
|
//}
|
||||||
|
public string Issuer
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZhaoXi._001.NET5Demo.Practice.WebApi.Utility.Jwt
|
||||||
|
{
|
||||||
|
public class RSAHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 从本地文件中读取用来签发 Token 的 RSA Key
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">存放密钥的文件夹路径</param>
|
||||||
|
/// <param name="withPrivate"></param>
|
||||||
|
/// <param name="keyParameters"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters)
|
||||||
|
{
|
||||||
|
string filename = withPrivate ? "key.json" : "key.public.json";
|
||||||
|
string fileTotalPath = Path.Combine(filePath, filename);
|
||||||
|
keyParameters = default(RSAParameters);
|
||||||
|
if (!File.Exists(fileTotalPath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyParameters = JsonConvert.DeserializeObject<RSAParameters>(File.ReadAllText(fileTotalPath));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 生成并保存 RSA 公钥与私钥
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath"></param>
|
||||||
|
/// <param name="withPrivate"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static RSAParameters GenerateAndSaveKey(string filePath, bool withPrivate = true)
|
||||||
|
{
|
||||||
|
RSAParameters publicKeys, privateKeys;
|
||||||
|
using (var rsa = new RSACryptoServiceProvider(2048))//即时生成
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
privateKeys = rsa.ExportParameters(true);
|
||||||
|
publicKeys = rsa.ExportParameters(false);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rsa.PersistKeyInCsp = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File.WriteAllText(Path.Combine(filePath, "key.json"), JsonConvert.SerializeObject(privateKeys));
|
||||||
|
File.WriteAllText(Path.Combine(filePath, "key.public.json"), JsonConvert.SerializeObject(publicKeys));
|
||||||
|
return withPrivate ? privateKeys : publicKeys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Utility
|
||||||
|
{
|
||||||
|
public static class MultipartRequestHelper
|
||||||
|
{
|
||||||
|
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq"
|
||||||
|
// The spec at https://tools.ietf.org/html/rfc2046#section-5.1 states that 70 characters is a reasonable limit.
|
||||||
|
public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
|
||||||
|
{
|
||||||
|
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary).Value;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(boundary))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Missing content-type boundary.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boundary.Length > lengthLimit)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException(
|
||||||
|
$"Multipart boundary length limit {lengthLimit} exceeded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsMultipartContentType(string contentType)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(contentType)
|
||||||
|
&& contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasFormDataContentDisposition(ContentDispositionHeaderValue contentDisposition)
|
||||||
|
{
|
||||||
|
// Content-Disposition: form-data; name="key";
|
||||||
|
return contentDisposition != null
|
||||||
|
&& contentDisposition.DispositionType.Equals("form-data")
|
||||||
|
&& string.IsNullOrEmpty(contentDisposition.FileName.Value)
|
||||||
|
&& string.IsNullOrEmpty(contentDisposition.FileNameStar.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
|
||||||
|
{
|
||||||
|
// Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg"
|
||||||
|
return contentDisposition != null
|
||||||
|
&& contentDisposition.DispositionType.Equals("form-data")
|
||||||
|
&& (!string.IsNullOrEmpty(contentDisposition.FileName.Value)
|
||||||
|
|| !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace IRaCIS.WX.CoreApi.Auth
|
||||||
|
{
|
||||||
|
public class AuthMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
public AuthMiddleware(RequestDelegate next, IEasyCachingProvider provider)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///为了前端 一段时间无操作,需要重新登陆
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Invoke(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
|
||||||
|
var isLogin = httpContext.Request.Path.ToString().ToLower().Contains("login");
|
||||||
|
|
||||||
|
var result = await httpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
if (!isLogin)
|
||||||
|
{
|
||||||
|
if (!result.Succeeded)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
await httpContext.Response.WriteAsync("Unauthorized");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var toekn = result.Properties.Items[".Token.access_token"];
|
||||||
|
var jwtHandler = new JwtSecurityTokenHandler();
|
||||||
|
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(toekn);
|
||||||
|
object userId;
|
||||||
|
jwtToken.Payload.TryGetValue("id", out userId);
|
||||||
|
|
||||||
|
var cacheValueExist = await _provider.ExistsAsync(userId.ToString()); //Get<string>(userId.ToString()).ToString();
|
||||||
|
if (!cacheValueExist)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
await httpContext.Response.WriteAsync("Unauthorized");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _provider.SetAsync(userId.ToString(), userId.ToString(), TimeSpan.FromMinutes(15));
|
||||||
|
httpContext.User = result.Principal;
|
||||||
|
await _next.Invoke(httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else await _next.Invoke(httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
using Hangfire;
|
||||||
|
using Hangfire.Dashboard;
|
||||||
|
using IRaCIS.Application.Services.BackGroundJob;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public static class HangfireConfig
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void UseHangfireConfig(this IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseHangfireDashboard("/api/hangfire", new DashboardOptions()
|
||||||
|
{
|
||||||
|
//直接访问,没有带token 获取不到用户身份信息,所以这种自定义授权暂时没法使用
|
||||||
|
//Authorization = new[] { new hangfireAuthorizationFilter() }
|
||||||
|
|
||||||
|
//本地请求 才能看
|
||||||
|
Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() }
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
#region hangfire
|
||||||
|
//// 延迟任务执行 1秒之后执行 有时启动没运行 换成添加到队列中
|
||||||
|
//BackgroundJob.Schedule<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus(), TimeSpan.FromSeconds(1));
|
||||||
|
////添加到后台任务队列,
|
||||||
|
//BackgroundJob.Enqueue<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus());
|
||||||
|
|
||||||
|
//周期性任务,1天执行一次
|
||||||
|
|
||||||
|
RecurringJob.AddOrUpdate<IIRaCISCacheHangfireJob>(t => t.ProjectStartCache(), Cron.Daily);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using Hangfire.Dashboard;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Filter
|
||||||
|
{
|
||||||
|
public class hangfireAuthorizationFilter : IDashboardAuthorizationFilter
|
||||||
|
{
|
||||||
|
public bool Authorize(DashboardContext context)
|
||||||
|
{
|
||||||
|
var httpContext = context.GetHttpContext();
|
||||||
|
|
||||||
|
// Allow all authenticated users to see the Dashboard (potentially dangerous).
|
||||||
|
return httpContext.User.Identity.IsAuthenticated;
|
||||||
|
|
||||||
|
//return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using IRaCIS.Core.Application.Helper;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.FileProviders;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class IRacisHostFileStore
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void UseIRacisHostStaticFileStore(this IApplicationBuilder app, IWebHostEnvironment _hostEnvironment)
|
||||||
|
{
|
||||||
|
|
||||||
|
var iRaCISDataFolder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
|
||||||
|
|
||||||
|
if (!Directory.Exists(iRaCISDataFolder))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(iRaCISDataFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseStaticFiles(new StaticFileOptions
|
||||||
|
{
|
||||||
|
FileProvider = new PhysicalFileProvider(iRaCISDataFolder),
|
||||||
|
RequestPath = $"/{StaticData.Folder.IRaCISDataFolder}",
|
||||||
|
ServeUnknownFileTypes = true,
|
||||||
|
DefaultContentType = "application/octet-stream"
|
||||||
|
|
||||||
|
// // Set up custom content types - associating file extension to MIME type
|
||||||
|
//var provider = new FileExtensionContentTypeProvider();
|
||||||
|
// // Add new mappings
|
||||||
|
// provider.Mappings[".myapp"] = "application/x-msdownload";
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Localization;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class LocalizationConfig
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void UseLocalization(this IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var supportedCultures = new List<CultureInfo>
|
||||||
|
{
|
||||||
|
new CultureInfo("en-US"),
|
||||||
|
new CultureInfo("zh-CN")
|
||||||
|
};
|
||||||
|
|
||||||
|
var options = new RequestLocalizationOptions
|
||||||
|
{
|
||||||
|
//DefaultRequestCulture = new RequestCulture("en-US"),
|
||||||
|
SupportedCultures = supportedCultures,
|
||||||
|
SupportedUICultures = supportedCultures,
|
||||||
|
|
||||||
|
ApplyCurrentCultureToResponseHeaders = true
|
||||||
|
};
|
||||||
|
|
||||||
|
//options.RequestCultureProviders.RemoveAt(0);
|
||||||
|
//options.RequestCultureProviders.RemoveAt(1);
|
||||||
|
|
||||||
|
app.UseRequestLocalization(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using LogDashboard;
|
||||||
|
using LogDashboard.Authorization;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API.Filter
|
||||||
|
{
|
||||||
|
|
||||||
|
public class LogDashBoardAuthFilter : ILogDashboardAuthorizationFilter
|
||||||
|
{
|
||||||
|
//在此可以利用 本系统的UerTypeEnum 判断
|
||||||
|
public bool Authorization(LogDashboardContext context)
|
||||||
|
{
|
||||||
|
return context.HttpContext.User.Identity.IsAuthenticated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Context;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API._PipelineExtensions.Serilog
|
||||||
|
{
|
||||||
|
public class RequestResponseLoggingMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
|
||||||
|
public RequestResponseLoggingMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Invoke(HttpContext context)
|
||||||
|
{
|
||||||
|
var ContentType = context.Request.ContentType;
|
||||||
|
|
||||||
|
var isUploadRelation = false;
|
||||||
|
|
||||||
|
if (ContentType != null)
|
||||||
|
{
|
||||||
|
isUploadRelation = context.Request.ContentType.Contains("multipart/form-data") || context.Request.ContentType.Contains("boundary") || context.Request.ContentType.Contains("octet-stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isUploadRelation)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("RequestBody", string.Empty))
|
||||||
|
{
|
||||||
|
await _next.Invoke(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var requestBodyPayload = await ReadRequestBody(context.Request);
|
||||||
|
|
||||||
|
using (LogContext.PushProperty("RequestBody", requestBodyPayload))
|
||||||
|
{
|
||||||
|
//await _next.Invoke()
|
||||||
|
await _next.Invoke(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//var request = context.Request;
|
||||||
|
|
||||||
|
|
||||||
|
// Read and log request body data
|
||||||
|
|
||||||
|
//SerilogHelper.RequestPayload = requestBodyPayload;
|
||||||
|
|
||||||
|
#region ResponseBody
|
||||||
|
|
||||||
|
//// Read and log response body data
|
||||||
|
//// Copy a pointer to the original response body stream
|
||||||
|
//var originalResponseBodyStream = context.Response.Body;
|
||||||
|
|
||||||
|
//// Create a new memory stream...
|
||||||
|
//using (var responseBody = new MemoryStream())
|
||||||
|
//{
|
||||||
|
// // ...and use that for the temporary response body
|
||||||
|
// context.Response.Body = responseBody;
|
||||||
|
|
||||||
|
// // Continue down the Middleware pipeline, eventually returning to this class
|
||||||
|
//await _next(context);
|
||||||
|
|
||||||
|
// // Copy the contents of the new memory stream (which contains the response) to the original stream, which is then returned to the client.
|
||||||
|
// await responseBody.CopyToAsync(originalResponseBodyStream);
|
||||||
|
//}
|
||||||
|
//string responseBodyPayload = await ReadResponseBody(context.Response);
|
||||||
|
//_diagnosticContext.Set("ResponseBody", responseBodyPayload);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> ReadRequestBody(HttpRequest request)
|
||||||
|
{
|
||||||
|
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
|
||||||
|
request.EnableBuffering();
|
||||||
|
|
||||||
|
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
|
||||||
|
var requestBody = await streamReader.ReadToEndAsync();
|
||||||
|
|
||||||
|
// Reset the request's body stream position for next middleware in the pipeline.
|
||||||
|
request.Body.Position = 0;
|
||||||
|
return requestBody == null ? String.Empty : requestBody.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<string> ReadResponseBody(HttpResponse response)
|
||||||
|
{
|
||||||
|
response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
string responseBody = await new StreamReader(response.Body).ReadToEndAsync();
|
||||||
|
response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return $"{responseBody}";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using Hangfire;
|
||||||
|
using Hangfire.Dashboard;
|
||||||
|
using IRaCIS.Core.API._PipelineExtensions.Serilog;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public static class SerilogConfig
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void UseSerilogConfig(this IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseMiddleware<RequestResponseLoggingMiddleware>();
|
||||||
|
|
||||||
|
app.UseSerilogRequestLogging(opts
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
opts.MessageTemplate = "{TokenUserRealName} {TokenUserType} {ClientIp} {RequestIP} {Host} {Protocol} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
|
||||||
|
opts.EnrichDiagnosticContext = SerilogHelper.EnrichFromRequest;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class SerilogHelper
|
||||||
|
{
|
||||||
|
//public static string RequestPayload = "";
|
||||||
|
|
||||||
|
public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext)
|
||||||
|
{
|
||||||
|
var request = httpContext.Request;
|
||||||
|
|
||||||
|
// Set all the common properties available for every request
|
||||||
|
diagnosticContext.Set("Host", request.Host);
|
||||||
|
|
||||||
|
//这种获取的Ip不准 配置服务才行
|
||||||
|
diagnosticContext.Set("RequestIP", httpContext.Connection.RemoteIpAddress.ToString());
|
||||||
|
|
||||||
|
//这种方式可以,但是serilog提供了 就不用了
|
||||||
|
//diagnosticContext.Set("TestIP", httpContext.GetUserIp());
|
||||||
|
|
||||||
|
diagnosticContext.Set("Protocol", request.Protocol);
|
||||||
|
diagnosticContext.Set("Scheme", request.Scheme);
|
||||||
|
|
||||||
|
//这种方式不行 读取的body为空字符串 必须在中间件中读取
|
||||||
|
//diagnosticContext.Set("RequestBody", await ReadRequestBody(httpContext.Request));
|
||||||
|
//diagnosticContext.Set("RequestBody", RequestPayload);
|
||||||
|
|
||||||
|
// Only set it if available. You're not sending sensitive data in a querystring right?!
|
||||||
|
if (request.QueryString.HasValue)
|
||||||
|
{
|
||||||
|
diagnosticContext.Set("QueryString", request.QueryString.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the content-type of the Response at this point
|
||||||
|
diagnosticContext.Set("ContentType", httpContext.Response.ContentType);
|
||||||
|
|
||||||
|
diagnosticContext.Set("TokenUserRealName", httpContext?.User?.FindFirst("realName")?.Value);
|
||||||
|
|
||||||
|
diagnosticContext.Set("TokenUserType", httpContext?.User?.FindFirst("userTypeEnumName")?.Value);
|
||||||
|
|
||||||
|
// Retrieve the IEndpointFeature selected for the request
|
||||||
|
var endpoint = httpContext.GetEndpoint();
|
||||||
|
if (endpoint is object) // endpoint != null
|
||||||
|
{
|
||||||
|
diagnosticContext.Set("EndpointName", endpoint.DisplayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class ApiResponseHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||||
|
{
|
||||||
|
public ApiResponseHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.ContentType = "application/json";
|
||||||
|
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||||
|
await Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("您无权访问该接口", ApiResponseCodeEnum.NoToken)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
Response.ContentType = "application/json";
|
||||||
|
Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||||
|
await Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("您的权限不允许进行该操作",ApiResponseCodeEnum.HaveTokenNotAccess)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
using IRaCIS.Core.Application.Auth;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class AuthorizationPolicySetup
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void AddAuthorizationPolicySetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddAuthorization(options =>
|
||||||
|
{
|
||||||
|
//影像质控策略 只允许 IC IQC进行操作
|
||||||
|
options.AddPolicy(IRaCISPolicy.CRC_IQC, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.IQC).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
//一致性核查策略 只允许 IC PM APM 进行操作
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_APM_CRC, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.APM).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_APM, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_IQC, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.IQC).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.IQC, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.IQC).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_APM_CRC_QC, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(),((int)UserTypeEnum.ClinicalResearchCoordinator).ToString(), ((int)UserTypeEnum.APM).ToString(), ((int)UserTypeEnum.IQC).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.SPM_CPM, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.SPM).ToString(), ((int)UserTypeEnum.CPM).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_APM_SPM_CPM, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString(),((int)UserTypeEnum.SPM).ToString(), ((int)UserTypeEnum.CPM).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddPolicy(IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM, policyBuilder =>
|
||||||
|
{
|
||||||
|
policyBuilder.RequireClaim("userTypeEnumInt", ((int)UserTypeEnum.ProjectManager).ToString(), ((int)UserTypeEnum.APM).ToString(), ((int)UserTypeEnum.SPM).ToString(),
|
||||||
|
((int)UserTypeEnum.CPM).ToString(), ((int)UserTypeEnum.SMM).ToString(), ((int)UserTypeEnum.CMM).ToString());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
using IRaCIS.Core.Application.Auth;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class JWTAuthSetup
|
||||||
|
{
|
||||||
|
public static void AddJWTAuthSetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.Configure<JwtSetting>(configuration.GetSection("JwtSetting"));
|
||||||
|
|
||||||
|
var jwtSetting = new JwtSetting();
|
||||||
|
configuration.Bind("JwtSetting", jwtSetting);
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddAuthentication(o =>
|
||||||
|
{
|
||||||
|
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
o.DefaultChallengeScheme = nameof(ApiResponseHandler);
|
||||||
|
o.DefaultForbidScheme = nameof(ApiResponseHandler);
|
||||||
|
})
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidIssuer = jwtSetting.Issuer,
|
||||||
|
ValidAudience = jwtSetting.Audience,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecurityKey)),
|
||||||
|
// 默认 300s
|
||||||
|
ClockSkew = TimeSpan.Zero
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
options.Events = new JwtBearerEvents
|
||||||
|
{
|
||||||
|
OnMessageReceived = (context) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
if (context.Request.Query.TryGetValue("access_token", out StringValues values))
|
||||||
|
{
|
||||||
|
var queryToken = values.FirstOrDefault();
|
||||||
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(queryToken))
|
||||||
|
{
|
||||||
|
context.Token = queryToken;
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//仅仅是访问文件的时候才会去取token认证 前端对cookie设置了有效期
|
||||||
|
|
||||||
|
if (context.Request.Path.ToString().Contains("IRaCISData") || context.Request.Path.ToString().Contains("SystemData") )
|
||||||
|
{
|
||||||
|
var cookieToken = context.Request.Cookies["access_token"];
|
||||||
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(cookieToken))
|
||||||
|
{
|
||||||
|
context.Token = cookieToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// OPTION 1: use `Invio.Extensions.Authentication.JwtBearer`
|
||||||
|
|
||||||
|
//options.AddQueryStringAuthentication();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// OPTION 2: do it manually
|
||||||
|
|
||||||
|
#region
|
||||||
|
//options.Events = new JwtBearerEvents
|
||||||
|
//{
|
||||||
|
// OnMessageReceived = (context) => {
|
||||||
|
|
||||||
|
// if (!context.Request.Query.TryGetValue("access_token", out StringValues values))
|
||||||
|
// {
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (values.Count > 1)
|
||||||
|
// {
|
||||||
|
// context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
// context.Fail(
|
||||||
|
// "Only one 'access_token' query string parameter can be defined. " +
|
||||||
|
// $"However, {values.Count:N0} were included in the request."
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var token = values.Single();
|
||||||
|
|
||||||
|
// if (String.IsNullOrWhiteSpace(token))
|
||||||
|
// {
|
||||||
|
// context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||||
|
// context.Fail(
|
||||||
|
// "The 'access_token' query string parameter was defined, " +
|
||||||
|
// "but a value to represent the token was not included."
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// context.Token = token;
|
||||||
|
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
//};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
})
|
||||||
|
.AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using AutoMapper.EquivalencyExpression;
|
||||||
|
using IRaCIS.Core.Application.Service;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class AutoMapperSetup
|
||||||
|
{
|
||||||
|
public static void AddAutoMapperSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
|
||||||
|
services.AddAutoMapper(automapper =>
|
||||||
|
{
|
||||||
|
//AutoMapper.Collection.EntityFrameworkCore
|
||||||
|
automapper.AddCollectionMappers();
|
||||||
|
|
||||||
|
#region 会使 IncludeMembers 失效 不能全局使用
|
||||||
|
//mapping an EntityFramework Core DbContext-object.
|
||||||
|
//automapper.UseEntityFrameworkCoreModel<IRaCISDBContext>(services);
|
||||||
|
|
||||||
|
|
||||||
|
//automapper.ForAllMaps((a, b) => b.ForAllMembers(opt => opt.Condition((src, dest, srcMember, desMenber) =>
|
||||||
|
//{
|
||||||
|
// //// Can test When Guid? -> Guid if source is null will change to Guid.Empty
|
||||||
|
// //Console.WriteLine("srcMember:" + srcMember + "desMenber:" + desMenber);
|
||||||
|
// return srcMember != null && srcMember.ToString() != Guid.Empty.ToString();
|
||||||
|
// // not want to map a null Guid? value to db Guid value
|
||||||
|
//})));
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}, typeof(QCConfig).Assembly);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
using Autofac;
|
||||||
|
using Autofac.Extras.DynamicProxy;
|
||||||
|
using IRaCIS.Core.Application;
|
||||||
|
using IRaCIS.Core.Application.AOP;
|
||||||
|
using IRaCIS.Core.Application.BackGroundJob;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Panda.DynamicWebApi;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using MediatR;
|
||||||
|
using IRaCIS.Application.Services;
|
||||||
|
using IRaCIS.Application.Interfaces;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
// ReSharper disable once IdentifierTypo
|
||||||
|
public class AutofacModuleSetup : Autofac.Module
|
||||||
|
{
|
||||||
|
protected override void Load(ContainerBuilder containerBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
#region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
|
||||||
|
|
||||||
|
containerBuilder.RegisterGeneric(typeof(Repository<>))
|
||||||
|
.As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
|
||||||
|
|
||||||
|
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
//containerBuilder.RegisterType<Mapper>().As<IMapper>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
//containerBuilder.RegisterGeneric(typeof(EFUnitOfWork<>))
|
||||||
|
// .As(typeof(IEFUnitOfWork<>)).InstancePerLifetimeScope();//注册仓储
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
|
||||||
|
|
||||||
|
//获取所有控制器类型并使用属性注入
|
||||||
|
containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
||||||
|
.Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
||||||
|
.PropertiesAutowired();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//containerBuilder.RegisterType<BaseService>().As<IBaseService>().PropertiesAutowired().InstancePerLifetimeScope();
|
||||||
|
//containerBuilder.RegisterType<DictionaryService>().As<IDictionaryService>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.Application.dll");
|
||||||
|
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
||||||
|
.PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors();
|
||||||
|
|
||||||
|
//Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore");
|
||||||
|
//containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces();
|
||||||
|
|
||||||
|
containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
|
||||||
|
containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
|
||||||
|
//containerBuilder.RegisterType<Dictionary>().InstancePerLifetimeScope();
|
||||||
|
//Autofac 注册拦截器 需要注意的是生成api上服务上的动态代理AOP失效 间接掉用不影响
|
||||||
|
//containerBuilder.RegisterType<TrialStatusAutofacAOP>();
|
||||||
|
//containerBuilder.RegisterType<UserAddAOP>();
|
||||||
|
//containerBuilder.RegisterType<QANoticeAOP>();
|
||||||
|
//containerBuilder.RegisterType<LogService>().As<ILogService>().SingleInstance();
|
||||||
|
|
||||||
|
|
||||||
|
//注册hangfire任务 依赖注入
|
||||||
|
containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Imaging;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class DicomSetup
|
||||||
|
{
|
||||||
|
public static void AddDicomSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
new DicomSetupBuilder()
|
||||||
|
.RegisterServices(s => s.AddFellowOakDicom()
|
||||||
|
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
|
.AddImageManager<ImageSharpImageManager>()
|
||||||
|
)
|
||||||
|
.SkipValidation()
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Panda.DynamicWebApi;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class DynamicWebApiSetup
|
||||||
|
{
|
||||||
|
//20210910 避免冗余的控制器层代码编写,仅仅包了一层前后台定义的格式 这里采用动态webAPi+IResultFilter 替代大部分情况
|
||||||
|
public static void AddDynamicWebApiSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//动态webApi 目前存在的唯一小坑是生成api上服务上的动态代理AOP失效 间接掉用不影响
|
||||||
|
services.AddDynamicWebApi(dynamicWebApiOption =>
|
||||||
|
{
|
||||||
|
//默认是 api
|
||||||
|
dynamicWebApiOption.DefaultApiPrefix = "";
|
||||||
|
//首字母小写
|
||||||
|
dynamicWebApiOption.GetRestFulActionName = (actionName) => char.ToLower(actionName[0]) + actionName.Substring(1);
|
||||||
|
//删除 Service后缀
|
||||||
|
dynamicWebApiOption.RemoveControllerPostfixes.Add("Service");
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
using IRaCIS.Core.Application.Triggers;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class EFSetup
|
||||||
|
{
|
||||||
|
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
//services.AddScoped<DbContext, IRaCISDBContext>();
|
||||||
|
|
||||||
|
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||||
|
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||||
|
services.AddDbContext<IRaCISDBContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||||
|
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||||
|
|
||||||
|
options.EnableSensitiveDataLogging();
|
||||||
|
|
||||||
|
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||||
|
|
||||||
|
options.UseProjectables();
|
||||||
|
|
||||||
|
//options.AddInterceptors(new AuditingInterceptor(configuration.GetSection("ConnectionStrings:RemoteNew").Value));
|
||||||
|
|
||||||
|
//options.UseTriggers(triggerOptions => triggerOptions.AddTrigger<SubjectVisitImageDateTrigger>());
|
||||||
|
|
||||||
|
//options.UseTriggers(triggerOptions => triggerOptions.AddAssemblyTriggers(typeof(SubjectVisitTrigger).Assembly));
|
||||||
|
|
||||||
|
|
||||||
|
options.UseTriggers(triggerOptions =>
|
||||||
|
{
|
||||||
|
triggerOptions.AddTrigger<AddSubjectTrigger>();
|
||||||
|
triggerOptions.AddTrigger<ChallengeStateTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectStateTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectVisitCheckPassedTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectVisitFinalVisitTrigger>();
|
||||||
|
triggerOptions.AddTrigger<SubjectVisitTrigger>();
|
||||||
|
triggerOptions.AddTrigger<TrialCriterionSignTrigger>();
|
||||||
|
triggerOptions.AddTrigger<TableQuestionRowTrigger>();
|
||||||
|
//triggerOptions.AddTrigger<AddlTrialUserTrigger>();
|
||||||
|
triggerOptions.AddTrigger<VisitTaskIsFrontTaskNeedSignButNotSignTrigger>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//services.AddAssemblyTriggers(typeof(SubjectVisitImageDateTrigger).Assembly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using EasyCaching.Interceptor.Castle;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class EasyCachingSetup
|
||||||
|
{
|
||||||
|
public static void AddEasyCachingSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddEasyCaching(options =>
|
||||||
|
{
|
||||||
|
options.UseInMemory();
|
||||||
|
});
|
||||||
|
services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using AspNetCoreRateLimit;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// IPLimit限流 启动服务
|
||||||
|
/// </summary>
|
||||||
|
public static class IpPolicyRateLimitSetup
|
||||||
|
{
|
||||||
|
public static void AddIpPolicyRateLimitSetup(this IServiceCollection services, IConfiguration Configuration)
|
||||||
|
{
|
||||||
|
|
||||||
|
// needed to store rate limit counters and ip rules
|
||||||
|
services.AddMemoryCache();
|
||||||
|
|
||||||
|
//load general configuration from appsettings.json
|
||||||
|
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
|
||||||
|
|
||||||
|
//load ip rules from appsettings.json
|
||||||
|
//services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
|
||||||
|
|
||||||
|
// inject counter and rules stores
|
||||||
|
services.AddInMemoryRateLimiting();
|
||||||
|
//services.AddDistributedRateLimiting<AsyncKeyLockProcessingStrategy>();
|
||||||
|
//services.AddDistributedRateLimiting<RedisProcessingStrategy>();
|
||||||
|
//services.AddRedisRateLimiting();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// configuration (resolvers, counter key builders)
|
||||||
|
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class JsonConfigSetup
|
||||||
|
{
|
||||||
|
public static void AddJsonConfigSetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
|
||||||
|
services.Configure<ServiceVerifyConfigOption>(configuration.GetSection("BasicSystemConfig"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
using LogDashboard;
|
||||||
|
using LogDashboard.Authorization.Filters;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class LogDashboardSetup
|
||||||
|
{
|
||||||
|
public static void AddLogDashboardSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//IIS 配置虚拟路径部署,会出现IIS静态文件404
|
||||||
|
services.AddLogDashboard(opt =>
|
||||||
|
{
|
||||||
|
//opt.PathMatch = "/api/LogDashboard";
|
||||||
|
opt.PathMatch = "/LogDashboard";
|
||||||
|
|
||||||
|
//opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
|
||||||
|
|
||||||
|
//opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
//using System;
|
||||||
|
//using Microsoft.Extensions.DependencyInjection;
|
||||||
|
//using StackExchange.Profiling.Storage;
|
||||||
|
|
||||||
|
//namespace IRaCIS.Core.API
|
||||||
|
//{
|
||||||
|
// public class MiniProfilerConfigure
|
||||||
|
// {
|
||||||
|
// public static void ConfigureMiniProfiler(IServiceCollection services)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// services.AddMiniProfiler(options =>
|
||||||
|
// {
|
||||||
|
// // All of this is optional. You can simply call .AddMiniProfiler() for all defaults
|
||||||
|
|
||||||
|
// // (Optional) Path to use for profiler URLs, default is /mini-profiler-resources
|
||||||
|
// options.RouteBasePath = "/profiler";
|
||||||
|
|
||||||
|
// //// (Optional) Control storage
|
||||||
|
// //// (default is 30 minutes in MemoryCacheStorage)
|
||||||
|
// (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
|
||||||
|
|
||||||
|
// //// (Optional) Control which SQL formatter to use, InlineFormatter is the default
|
||||||
|
// //options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
|
||||||
|
|
||||||
|
// //// (Optional) To control authorization, you can use the Func<HttpRequest, bool> options:
|
||||||
|
// //// (default is everyone can access profilers)
|
||||||
|
// //options.ResultsAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
|
||||||
|
// //options.ResultsListAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler;
|
||||||
|
// //// Or, there are async versions available:
|
||||||
|
// //options.ResultsAuthorizeAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfiler;
|
||||||
|
// //options.ResultsAuthorizeListAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfilerLists;
|
||||||
|
|
||||||
|
// //// (Optional) To control which requests are profiled, use the Func<HttpRequest, bool> option:
|
||||||
|
// //// (default is everything should be profiled)
|
||||||
|
// //options.ShouldProfile = request => MyShouldThisBeProfiledFunction(request);
|
||||||
|
|
||||||
|
// //// (Optional) Profiles are stored under a user ID, function to get it:
|
||||||
|
// //// (default is null, since above methods don't use it by default)
|
||||||
|
// //options.UserIdProvider = request => MyGetUserIdFunction(request);
|
||||||
|
|
||||||
|
// //// (Optional) Swap out the entire profiler provider, if you want
|
||||||
|
// //// (default handles async and works fine for almost all applications)
|
||||||
|
// //options.ProfilerProvider = new MyProfilerProvider();
|
||||||
|
|
||||||
|
// //// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking.
|
||||||
|
// //// (defaults to true, and connection opening/closing is tracked)
|
||||||
|
// //options.TrackConnectionOpenClose = true;
|
||||||
|
|
||||||
|
// //// (Optional) Use something other than the "light" color scheme.
|
||||||
|
// //// (defaults to "light")
|
||||||
|
// //options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto;
|
||||||
|
|
||||||
|
// //// The below are newer options, available in .NET Core 3.0 and above:
|
||||||
|
|
||||||
|
// //// (Optional) You can disable MVC filter profiling
|
||||||
|
// //// (defaults to true, and filters are profiled)
|
||||||
|
// //options.EnableMvcFilterProfiling = true;
|
||||||
|
// //// ...or only save filters that take over a certain millisecond duration (including their children)
|
||||||
|
// //// (defaults to null, and all filters are profiled)
|
||||||
|
// //// options.MvcFilterMinimumSaveMs = 1.0m;
|
||||||
|
|
||||||
|
// //// (Optional) You can disable MVC view profiling
|
||||||
|
// //// (defaults to true, and views are profiled)
|
||||||
|
// //options.EnableMvcViewProfiling = true;
|
||||||
|
// //// ...or only save views that take over a certain millisecond duration (including their children)
|
||||||
|
// //// (defaults to null, and all views are profiled)
|
||||||
|
// //// options.MvcViewMinimumSaveMs = 1.0m;
|
||||||
|
|
||||||
|
// //// (Optional) listen to any errors that occur within MiniProfiler itself
|
||||||
|
// //// options.OnInternalError = e => MyExceptionLogger(e);
|
||||||
|
|
||||||
|
// //// (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage
|
||||||
|
// //// It has a lot of overhead vs. normal profiling and should only be used with that in mind
|
||||||
|
// //// (defaults to false, debug/heavy mode is off)
|
||||||
|
// ////options.EnableDebugMode = true;
|
||||||
|
// });
|
||||||
|
// //.AddEntityFramework();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class JSONCustomDateConverter : DateTimeConverterBase
|
||||||
|
{
|
||||||
|
private TimeZoneInfo _timeZoneInfo;
|
||||||
|
private string _dateFormat;
|
||||||
|
|
||||||
|
private IUserInfo _userInfo;
|
||||||
|
public JSONCustomDateConverter(string dateFormat, TimeZoneInfo timeZoneInfo, IUserInfo userInfo)
|
||||||
|
{
|
||||||
|
_dateFormat = dateFormat;
|
||||||
|
_timeZoneInfo = timeZoneInfo;
|
||||||
|
|
||||||
|
_userInfo = userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var timeZoneId = _userInfo.TimeZoneId;
|
||||||
|
|
||||||
|
var needConvertUtcDateTime = Convert.ToDateTime(value);
|
||||||
|
|
||||||
|
|
||||||
|
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
|
||||||
|
|
||||||
|
|
||||||
|
var dateTimeOffset = new DateTimeOffset(needConvertUtcDateTime);
|
||||||
|
|
||||||
|
var time = TimeZoneInfo.ConvertTimeFromUtc(needConvertUtcDateTime, tz).ToString(_dateFormat);
|
||||||
|
|
||||||
|
writer.WriteValue(time);
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class NewtonsoftJsonSetup
|
||||||
|
{
|
||||||
|
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder)
|
||||||
|
{
|
||||||
|
|
||||||
|
builder.AddNewtonsoftJson(options =>
|
||||||
|
{
|
||||||
|
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
|
||||||
|
// 忽略循环引用
|
||||||
|
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||||
|
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
|
||||||
|
|
||||||
|
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
|
||||||
|
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
|
||||||
|
// 设置时间格式
|
||||||
|
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
|
||||||
|
|
||||||
|
//IsoDateTimeConverter
|
||||||
|
//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||||
|
|
||||||
|
})
|
||||||
|
.AddControllersAsServices()//动态webApi属性注入需要
|
||||||
|
.ConfigureApiBehaviorOptions(o =>
|
||||||
|
{
|
||||||
|
o.SuppressModelStateInvalidFilter = true; //自己写验证
|
||||||
|
|
||||||
|
////这里是自定义验证结果和返回状态码 因为这里是在[ApiController]控制器层校验,动态webApi的不会校验 所以需要单独写一个Filter
|
||||||
|
//o.InvalidModelStateResponseFactory = (context) =>
|
||||||
|
//{
|
||||||
|
// var error = context.ModelState .Keys
|
||||||
|
// .SelectMany(k => context.ModelState[k].Errors)
|
||||||
|
// .Select(e => e.ErrorMessage)
|
||||||
|
// .ToArray();
|
||||||
|
|
||||||
|
//return new JsonResult(ResponseOutput.NotOk("The inputs supplied to the API are invalid. " + JsonConvert.SerializeObject( error)));
|
||||||
|
//};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
|
||||||
|
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
|
||||||
|
{
|
||||||
|
//日期类型默认格式化处理
|
||||||
|
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||||
|
|
||||||
|
return setting;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class NullToEmptyStringResolver : DefaultContractResolver
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建属性
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">类型</param>
|
||||||
|
/// <param name="memberSerialization">序列化成员</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
//protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||||
|
//{
|
||||||
|
// IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||||
|
|
||||||
|
|
||||||
|
// foreach (var jsonProperty in properties)
|
||||||
|
// {
|
||||||
|
// jsonProperty.DefaultValue = new NullToEmptyStringValueProvider(jsonProperty);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return properties;
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||||
|
{
|
||||||
|
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||||
|
|
||||||
|
var list= type.GetProperties()
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var jp = base.CreateProperty(p, memberSerialization);
|
||||||
|
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
|
||||||
|
return jp;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
var uu = list.Select(t => t.PropertyName).ToList();
|
||||||
|
|
||||||
|
//获取复杂对象属性
|
||||||
|
properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList();
|
||||||
|
|
||||||
|
list.AddRange(properties);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
|
||||||
|
public class NullToEmptyStringValueProvider : IValueProvider
|
||||||
|
{
|
||||||
|
PropertyInfo _MemberInfo;
|
||||||
|
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
||||||
|
{
|
||||||
|
_MemberInfo = memberInfo;
|
||||||
|
}
|
||||||
|
public object GetValue(object target)
|
||||||
|
{
|
||||||
|
object result = _MemberInfo.GetValue(target);
|
||||||
|
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
|
||||||
|
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
|
||||||
|
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
|
||||||
|
else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public void SetValue(object target, object value)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(_MemberInfo.PropertyType == typeof(string))
|
||||||
|
{
|
||||||
|
//去掉前后空格
|
||||||
|
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_MemberInfo.SetValue(target, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
using IRaCIS.Application.Services.BackGroundJob;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Quartz;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class QuartZSetup
|
||||||
|
{
|
||||||
|
public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddTransient<CacheTrialStatusQuartZJob>();
|
||||||
|
|
||||||
|
services.AddQuartz(q =>
|
||||||
|
{
|
||||||
|
// base quartz scheduler, job and trigger configuration
|
||||||
|
|
||||||
|
// as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
|
||||||
|
q.UseMicrosoftDependencyInjectionJobFactory();
|
||||||
|
|
||||||
|
// 基本Quartz调度器、作业和触发器配置
|
||||||
|
var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
|
||||||
|
q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
|
||||||
|
.WithDescription("Trial regular work")
|
||||||
|
);
|
||||||
|
q.AddTrigger(t => t
|
||||||
|
.WithIdentity("TrialStatusTrigger")
|
||||||
|
.ForJob(jobKey)
|
||||||
|
|
||||||
|
.WithCronSchedule("0 0 * * * ?")//每小时执行一次
|
||||||
|
.WithDescription("My regular trial work trigger")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ASP.NET Core hosting
|
||||||
|
services.AddQuartzHostedService(options =>
|
||||||
|
{
|
||||||
|
// when shutting down we want jobs to complete gracefully
|
||||||
|
options.WaitForJobsToComplete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.ResponseCompression;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class ResponseCompressionSetup
|
||||||
|
{
|
||||||
|
public static void AddResponseCompressionSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddResponseCompression(options =>
|
||||||
|
{
|
||||||
|
options.Providers.Add<BrotliCompressionProvider>();
|
||||||
|
options.Providers.Add<GzipCompressionProvider>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Configuration;
|
||||||
|
using Serilog.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class EnricherExtensions
|
||||||
|
{
|
||||||
|
public static LoggerConfiguration WithHttpContextInfo(this LoggerEnrichmentConfiguration enrich, IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
if (enrich == null)
|
||||||
|
throw new ArgumentNullException(nameof(enrich));
|
||||||
|
|
||||||
|
return enrich.With(new HttpContextEnricher(serviceProvider));
|
||||||
|
}
|
||||||
|
public static LoggerConfiguration WithHttpContextInfo(this LoggerEnrichmentConfiguration enrich, IServiceProvider serviceProvider, Action<LogEvent, ILogEventPropertyFactory, HttpContext> enrichAction)
|
||||||
|
{
|
||||||
|
if (enrich == null)
|
||||||
|
throw new ArgumentNullException(nameof(enrich));
|
||||||
|
|
||||||
|
return enrich.With(new HttpContextEnricher(serviceProvider, enrichAction));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Serilog.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class HttpContextEnricher : ILogEventEnricher
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly Action<LogEvent, ILogEventPropertyFactory, HttpContext> _enrichAction;
|
||||||
|
|
||||||
|
public HttpContextEnricher(IServiceProvider serviceProvider) : this(serviceProvider, null)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public HttpContextEnricher(IServiceProvider serviceProvider, Action<LogEvent, ILogEventPropertyFactory, HttpContext> enrichAction)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
if (enrichAction == null)
|
||||||
|
{
|
||||||
|
_enrichAction = (logEvent, propertyFactory, httpContext) =>
|
||||||
|
{
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", httpContext.Connection.RemoteIpAddress.ToString()));
|
||||||
|
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("LocalIP", httpContext.Connection.LocalIpAddress.MapToIPv4().ToString()));
|
||||||
|
|
||||||
|
|
||||||
|
//这样读取没用
|
||||||
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestBody", await ReadRequestBody(httpContext.Request)));
|
||||||
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("RequestIP", IPHelper.GetIP(httpContext.Request) ));
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserRealName", httpContext?.User?.FindFirst(ClaimAttributes.RealName)?.Value));
|
||||||
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("TokenUserType", httpContext?.User?.FindFirst(JwtIRaCISClaimType.UserTypeShortName)?.Value));
|
||||||
|
|
||||||
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Referer", httpContext.Request.Headers["Referer"].ToString()));
|
||||||
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_path", httpContext.Request.Path));
|
||||||
|
//logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("request_method", httpContext.Request.Method));
|
||||||
|
//if (httpContext.Response.HasStarted)
|
||||||
|
//{
|
||||||
|
// logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("response_status", httpContext.Response.StatusCode));
|
||||||
|
//}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_enrichAction = enrichAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
||||||
|
{
|
||||||
|
var httpContext = _serviceProvider.GetService<IHttpContextAccessor>()?.HttpContext;
|
||||||
|
if (null != httpContext)
|
||||||
|
{
|
||||||
|
_enrichAction.Invoke(logEvent, propertyFactory, httpContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> ReadRequestBody(HttpRequest request)
|
||||||
|
{
|
||||||
|
// Ensure the request's body can be read multiple times (for the next middlewares in the pipeline).
|
||||||
|
request.EnableBuffering();
|
||||||
|
|
||||||
|
using var streamReader = new StreamReader(request.Body, leaveOpen: true);
|
||||||
|
var requestBody = await streamReader.ReadToEndAsync();
|
||||||
|
|
||||||
|
// Reset the request's body stream position for next middleware in the pipeline.
|
||||||
|
request.Body.Position = 0;
|
||||||
|
return requestBody==null?String.Empty: requestBody.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> ReadResponseBody(HttpResponse response)
|
||||||
|
{
|
||||||
|
response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
string responseBody = await new StreamReader(response.Body).ReadToEndAsync();
|
||||||
|
response.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return $"{responseBody}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
using Serilog.Sinks.Email;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class SerilogExtension
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void AddSerilogSetup(string environment, IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
|
||||||
|
var config = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Information()
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
|
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
||||||
|
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||||
|
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
|
||||||
|
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
|
||||||
|
.Enrich.WithClientIp()
|
||||||
|
.Enrich.WithClientAgent()
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
|
||||||
|
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
|
||||||
|
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
|
||||||
|
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} ] {LocalIP} {ClientIp} {TokenUserRealName} {TokenUserType} {Message:lj} {Properties:j}{NewLine} {Exception}")
|
||||||
|
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
|
||||||
|
outputTemplate: "{Timestamp:HH:mm:ss} || {Level} || {SourceContext:l} || {Message} ||{Exception} ||end {NewLine}");
|
||||||
|
//.WriteTo.MSSqlServer("Data Source=DESKTOP-4TU9A6M;Initial Catalog=CoreFrame;User ID=sa;Password=123456", "logs", autoCreateSqlTable: true, restrictedToMinimumLevel: LogEventLevel.Information)//从左至右四个参数分别是数据库连接字符串、表名、如果表不存在是否创建、最低等级。Serilog会默认创建一些列。
|
||||||
|
|
||||||
|
if (environment == "Production")
|
||||||
|
{
|
||||||
|
config.WriteTo.Email(new EmailConnectionInfo()
|
||||||
|
{
|
||||||
|
EmailSubject = "系统警告,请速速查看!",//邮件标题
|
||||||
|
FromEmail = "iracis_grr@163.com",//发件人邮箱
|
||||||
|
MailServer = "smtp.163.com",//smtp服务器地址
|
||||||
|
NetworkCredentials = new NetworkCredential("iracis_grr@163.com", "XLWVQKZAEKLDWOAH"),//两个参数分别是发件人邮箱与客户端授权码
|
||||||
|
Port = 25,//端口号
|
||||||
|
ToEmail = "872297557@qq.com"//收件人
|
||||||
|
}, restrictedToMinimumLevel: LogEventLevel.Error,
|
||||||
|
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [ {Level} {ClientIp} {ClientAgent} {TokenUserRealName} {TokenUserType} ] || [path: {RequestPath} arguments: {RequestBody}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine})");
|
||||||
|
}
|
||||||
|
|
||||||
|
//扩展方法 获取上下文的ip 用户名 用户类型
|
||||||
|
Log.Logger = config.Enrich.WithHttpContextInfo(serviceProvider).CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class StaticFileAuthorizationSetup
|
||||||
|
{
|
||||||
|
public static void AddStaticFileAuthorizationSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddAuthorization(options =>
|
||||||
|
{
|
||||||
|
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
||||||
|
.RequireAuthenticatedUser()
|
||||||
|
.Build();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public class JsonPatchDocumentFilter : IDocumentFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||||
|
{
|
||||||
|
var schemas = swaggerDoc.Components.Schemas.ToList();
|
||||||
|
foreach (var item in schemas)
|
||||||
|
{
|
||||||
|
if (item.Key.StartsWith("Operation") || item.Key.StartsWith("JsonPatchDocument"))
|
||||||
|
swaggerDoc.Components.Schemas.Remove(item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
swaggerDoc.Components.Schemas.Add("Operation", new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = "object",
|
||||||
|
Properties = new Dictionary<string, OpenApiSchema>
|
||||||
|
{
|
||||||
|
{ "op", new OpenApiSchema { Type = "string" } },
|
||||||
|
{"value", new OpenApiSchema{ Type = "object", Nullable = true } },
|
||||||
|
{ "path", new OpenApiSchema { Type = "string" } }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema
|
||||||
|
{
|
||||||
|
Type = "array",
|
||||||
|
Items = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Operation" }
|
||||||
|
},
|
||||||
|
Description = "Array of operations to perform"
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var path in swaggerDoc.Paths.SelectMany(p => p.Value.Operations)
|
||||||
|
.Where(p => p.Key == Microsoft.OpenApi.Models.OperationType.Patch))
|
||||||
|
{
|
||||||
|
foreach (var item in path.Value.RequestBody.Content.Where(c => c.Key != "application/json-patch+json"))
|
||||||
|
path.Value.RequestBody.Content.Remove(item.Key);
|
||||||
|
|
||||||
|
var response = path.Value.RequestBody.Content.SingleOrDefault(c => c.Key == "application/json-patch+json");
|
||||||
|
|
||||||
|
response.Value.Schema = new OpenApiSchema
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
using IRaCIS.Core.Application.Contracts;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.Filters;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class SwaggerSetup
|
||||||
|
{
|
||||||
|
public static void AddSwaggerSetup(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSwaggerExamplesFromAssemblyOf<JsonPatchUserRequestExample>();
|
||||||
|
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
//此处的Name 是控制器上分组的名称 Title是界面的大标题
|
||||||
|
//分组
|
||||||
|
|
||||||
|
options.SwaggerDoc("Reviewer", new OpenApiInfo {Title = "医生模块",Version = "Reviewer", });
|
||||||
|
options.SwaggerDoc("Trial", new OpenApiInfo { Title = "项目模块", Version = "Trial" });
|
||||||
|
options.SwaggerDoc("Enroll", new OpenApiInfo { Title = "入组模块", Version = "Enroll" });
|
||||||
|
options.SwaggerDoc("Workload", new OpenApiInfo { Title = "工作量模块", Version = "Workload" });
|
||||||
|
options.SwaggerDoc("Common", new OpenApiInfo { Title = "通用信息获取", Version = "Common" });
|
||||||
|
options.SwaggerDoc("Institution", new OpenApiInfo { Title = "机构信息模块", Version = "Institution" });
|
||||||
|
options.SwaggerDoc("Dashboard&Statistics", new OpenApiInfo { Title = "统计模块", Version = "Dashboard&Statistics" });
|
||||||
|
|
||||||
|
options.SwaggerDoc("Financial", new OpenApiInfo { Title = "财务模块", Version = "Financial" });
|
||||||
|
options.SwaggerDoc("Management", new OpenApiInfo { Title = "管理模块", Version = "Management" });
|
||||||
|
options.SwaggerDoc("Image", new OpenApiInfo { Title = "影像模块", Version = "Image" });
|
||||||
|
options.SwaggerDoc("Reading", new OpenApiInfo { Title = "读片模块", Version = "Reading" });
|
||||||
|
|
||||||
|
|
||||||
|
// 接口排序
|
||||||
|
options.OrderActionsBy(o => o.GroupName);
|
||||||
|
|
||||||
|
options.DocInclusionPredicate((docName, apiDes) =>
|
||||||
|
{
|
||||||
|
if (!apiDes.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
|
||||||
|
var versions = methodInfo.DeclaringType.GetCustomAttributes(true)
|
||||||
|
.OfType<ApiExplorerSettingsAttribute>()
|
||||||
|
.Select(attr => attr.GroupName);
|
||||||
|
|
||||||
|
return versions.Any(v => v.ToString() == docName);
|
||||||
|
});
|
||||||
|
|
||||||
|
var xmlPath = Path.Combine(AppContext.BaseDirectory, "IRaCIS.Core.API.xml");//这个就是刚刚配置的xml文件名
|
||||||
|
options.IncludeXmlComments(xmlPath, true);
|
||||||
|
|
||||||
|
var xmlPath2 = Path.Combine(AppContext.BaseDirectory, "IRaCIS.Core.Application.xml");//这个就是刚刚配置的xml文件名
|
||||||
|
options.IncludeXmlComments(xmlPath2, true);
|
||||||
|
//默认的第二个参数是false,这个是controller的注释,记得修改
|
||||||
|
|
||||||
|
|
||||||
|
// 在header中添加token,传递到后台
|
||||||
|
options.OperationFilter<SecurityRequirementsOperationFilter>();
|
||||||
|
|
||||||
|
options.DocumentFilter<JsonPatchDocumentFilter>();
|
||||||
|
|
||||||
|
// 添加登录按钮
|
||||||
|
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||||
|
Name = "Authorization",
|
||||||
|
|
||||||
|
//In = "header",
|
||||||
|
//Type = "apiKey"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//// Bearer
|
||||||
|
//options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
|
||||||
|
//{
|
||||||
|
// Description = "JWT Authorization header using the Bearer scheme.",
|
||||||
|
// Name = "Authorization",
|
||||||
|
// In = ParameterLocation.Header,
|
||||||
|
// Scheme = "bearer",
|
||||||
|
// Type = SecuritySchemeType.Http,
|
||||||
|
// BearerFormat = "JWT"
|
||||||
|
//});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(options =>
|
||||||
|
{
|
||||||
|
//此处的Name 是页面 选择文档下拉框 显示的名称
|
||||||
|
options.SwaggerEndpoint($"swagger/Reviewer/swagger.json", "医生模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Trial/swagger.json", "项目模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Enroll/swagger.json", "入组模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Workload/swagger.json", "工作量模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Dashboard&Statistics/swagger.json", "统计模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Common/swagger.json", "通用模块");
|
||||||
|
|
||||||
|
options.SwaggerEndpoint($"swagger/Financial/swagger.json", "财务模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Institution/swagger.json", "机构信息模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Management/swagger.json", "管理模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Image/swagger.json", "影像模块");
|
||||||
|
options.SwaggerEndpoint($"swagger/Reading/swagger.json", "读片模块");
|
||||||
|
|
||||||
|
|
||||||
|
//路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,
|
||||||
|
//注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.Route = "doc";
|
||||||
|
//options.RoutePrefix = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
options.IndexStream = () => Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream("IRaCIS.Core.API.wwwroot.swagger.ui.Index.html");
|
||||||
|
|
||||||
|
options.RoutePrefix = string.Empty;
|
||||||
|
|
||||||
|
//DocExpansion设置为none可折叠所有方法
|
||||||
|
options.DocExpansion(DocExpansion.None);
|
||||||
|
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||||
|
options.DefaultModelsExpandDepth(-1);
|
||||||
|
|
||||||
|
|
||||||
|
// 引入静态文件添加登录功能
|
||||||
|
// 清除静态文件缓存
|
||||||
|
// options.IndexStream = () => null;
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using Hangfire;
|
||||||
|
using Hangfire.SqlServer;
|
||||||
|
using Hangfire.Tags.SqlServer;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.API
|
||||||
|
{
|
||||||
|
public static class hangfireSetup
|
||||||
|
{
|
||||||
|
public static void AddhangfireSetup(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var hangFireConnStr = configuration.GetSection("ConnectionStrings:Hangfire").Value;
|
||||||
|
|
||||||
|
services.AddHangfire(hangFireConfig =>
|
||||||
|
{
|
||||||
|
//指定存储介质
|
||||||
|
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
|
||||||
|
{
|
||||||
|
SchemaName = "hangfire",
|
||||||
|
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
|
||||||
|
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
|
||||||
|
QueuePollInterval = TimeSpan.Zero,
|
||||||
|
UseRecommendedIsolationLevel = true,
|
||||||
|
UsePageLocksOnDequeue = true,
|
||||||
|
DisableGlobalLocks = true
|
||||||
|
});
|
||||||
|
|
||||||
|
hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer
|
||||||
|
//.UseHangfireHttpJob();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddHangfireServer();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Test.EIImageViewer;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Hangfire_IRaCIS;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true"
|
||||||
|
|
||||||
|
},
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
|
||||||
|
"OpenSignDocumentBeforeWork": false,
|
||||||
|
|
||||||
|
"OpenTrialRelationDelete": true,
|
||||||
|
|
||||||
|
"OpenLoginLimit": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "test@extimaging.com",
|
||||||
|
"FromName": "Test_IRC",
|
||||||
|
"AuthorizationCode": "SHzyyl2021"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
"JwtSetting": {
|
||||||
|
"SecurityKey": "3e6dbfa227234a03977a2f421bdb7f4f", // 密钥
|
||||||
|
"Issuer": "IRaCIS", // 颁发者
|
||||||
|
"Audience": "ZhiZhun", // 接收者
|
||||||
|
"TokenExpireDays": "7" // 过期时间(7day)
|
||||||
|
},
|
||||||
|
"IpRateLimiting": {
|
||||||
|
"EnableEndpointRateLimiting": true, //False: globally executed, true: executed for each
|
||||||
|
"StackBlockedRequests": false, // set to false, rejected calls are not added to the throttle counter
|
||||||
|
"RealIpHeader": "X-Real-IP",
|
||||||
|
"ClientIdHeader": "X-ClientId",
|
||||||
|
"QuotaExceededResponse": {
|
||||||
|
"Content": "{{\"ErrorMessage\":\"The program performs flow limiting,Your requests are too frequent, please try again later, or contact the administrator to modify the IP flow restriction rules\",\"IsSuccess\":false}}",
|
||||||
|
"ContentType": "application/json",
|
||||||
|
"StatusCode": 429
|
||||||
|
},
|
||||||
|
"HttpStatusCode": 429,
|
||||||
|
//"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
|
||||||
|
"EndpointWhitelist": [ "post:/study/archivestudy/*" ],
|
||||||
|
//"EndpointWhitelist": [ ],
|
||||||
|
//"EndpointWhitelist": ["post:/trial/getTrialList"], //demo
|
||||||
|
"IpWhitelist": [],
|
||||||
|
//"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
|
||||||
|
"GeneralRules": [
|
||||||
|
{
|
||||||
|
"Endpoint": "*",
|
||||||
|
"Period": "1s",
|
||||||
|
"Limit": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Endpoint": "*",
|
||||||
|
"Period": "15m",
|
||||||
|
"Limit": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Endpoint": "*",
|
||||||
|
"Period": "12h",
|
||||||
|
"Limit": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Endpoint": "*",
|
||||||
|
"Period": "7d",
|
||||||
|
"Limit": 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"easycaching": {
|
||||||
|
"inmemory": {
|
||||||
|
"MaxRdSecond": 120,
|
||||||
|
"EnableLogging": false,
|
||||||
|
"LockMs": 5000,
|
||||||
|
"SleepMs": 300,
|
||||||
|
"DBConfig": {
|
||||||
|
"SizeLimit": 10000,
|
||||||
|
"ExpirationScanFrequency": 60,
|
||||||
|
"EnableReadDeepClone": true,
|
||||||
|
"EnableWriteDeepClone": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"IRaCISBasicConfig": {
|
||||||
|
|
||||||
|
"DoctorCodePrefix": "RE",
|
||||||
|
|
||||||
|
"UserCodePrefix": "U",
|
||||||
|
|
||||||
|
"QCChallengeCodePrefix": "Q",
|
||||||
|
|
||||||
|
"NoneDicomStudyCodePrefix": "NST",
|
||||||
|
|
||||||
|
|
||||||
|
"DicomStudyCodePrefix": "ST",
|
||||||
|
|
||||||
|
"SystemSiteCodePrefix": "S",
|
||||||
|
|
||||||
|
"DefaultPassword": "EIImage@2023",
|
||||||
|
|
||||||
|
"DefaultInternalOrganizationName": "ExtImaging",
|
||||||
|
|
||||||
|
"ImageShareExpireDays": 10
|
||||||
|
}
|
||||||
|
|
||||||
|
//网站根地址,为了访问文件 dicom 和上传的文档... 实测发现不用将域名拼接返回,浏览器会自动加上当前ip,避免了多环境读取环境配置文件
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<security>
|
||||||
|
<requestFiltering>
|
||||||
|
<!--单位:字节。 -->
|
||||||
|
<requestLimits maxAllowedContentLength="1073741824" />
|
||||||
|
<!-- 1 GB -->
|
||||||
|
</requestFiltering>
|
||||||
|
</security>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
行藏医学影像处理软件系统为您添加了账户,账户信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
用户名: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{3}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">武汉行藏科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
行藏医学影像处理软件系统将您的账户密码已重置,账户信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
用户名: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
密码: {3}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">武汉行藏科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
感谢您使用行藏医学影像处理软件。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{0}。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">武汉行藏科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
感谢您使用展影云平台。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{0}。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
展影医疗作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
系统登录地址:{6}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
展影医疗作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
您好, 您填写的中心调研表被驳回,详细信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
中心编号: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
中心名称: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
驳回原因: {6}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a href='{7}' style='margin-left:60px;font-size:14px;padding: 10px;text-decoration: none;display:{8} ;height: 40px;width: 140px;background: #00D1B2;color:#fff;border-radius: 5px;line-height: 40px;text-align: center;margin-bottom: 100px;'>
|
||||||
|
登陆并查看
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
展影医疗作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
系统登录地址:{6}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
尊敬的 {0} ,您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
展影医疗作为 [{1} (试验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC相关工作,欢迎您提供指导和建议,非常感谢!
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
该项目采用电子化工作流,系统及您的账号信息如下:
|
||||||
|
</div>
|
||||||
|
<span style="color: #00D1B2"></span>
|
||||||
|
<div style='border: 1px solid #eee;box-sizing:border-box;width: 50%;background: #fff;padding: 20px;line-height: 40px;font-size: 14px;border-radius: 5px;margin-left: 60px;margin-bottom: 30px;'>
|
||||||
|
<div>
|
||||||
|
项目编号: {3}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验方案号: {2}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
试验名称: {1}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
用户名: {4}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
角色: {5}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
首次登陆前,请通过该链接修改您的账户信息:
|
||||||
|
<a href='{6}' style='margin-left:30px;font-size:14px;text-decoration: none;display: inline-block;color:#00D1B2;border-radius: 5px;line-height: 40px;text-align: center;'>
|
||||||
|
初始化账号信息
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">上海展影医疗科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang='en'>
|
||||||
|
<head>
|
||||||
|
<meta charset='UTF-8'>
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body style='font-family: 微软雅黑;padding: 0;margin: 0;'>
|
||||||
|
<div style='padding-left: 40px;background: #f6f6f6'>
|
||||||
|
<div style='padding-top: 20px;'>
|
||||||
|
<div style='line-height: 40px;font-size: 18px'>
|
||||||
|
{0}您好:
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
感谢您使用行藏医学影像处理软件。
|
||||||
|
</div>
|
||||||
|
<div style='line-height: 40px;padding-left: 40px;margin-bottom: 10px;'>
|
||||||
|
{1},验证码是: {2},请在3分钟内输入该验证码,进行后续操作。如非本人操作,请忽略该邮件。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
|
||||||
|
<div>祝您顺利!/Best Regards</div>
|
||||||
|
<div style="font-size: 14px;">武汉行藏科技有限公司</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,128 @@
|
||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>%(DocumentTitle)</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
|
||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
%(HeadContent)
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
|
||||||
|
<defs>
|
||||||
|
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||||
|
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="locked">
|
||||||
|
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="close">
|
||||||
|
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||||
|
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||||
|
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z" />
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||||
|
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol viewBox="0 0 24 24" id="expand">
|
||||||
|
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
|
||||||
|
</symbol>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="./swagger-ui-bundle.js"></script>
|
||||||
|
<script src="./swagger-ui-standalone-preset.js"></script>
|
||||||
|
<script src="/swagger/ui/abp.js"></script>
|
||||||
|
<script src="/swagger/ui/abp.swagger.js?v=1"></script>
|
||||||
|
<!--<script src="/lib/jquery/jquery.min.js"></script>-->
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
var configObject = JSON.parse('%(ConfigObject)');
|
||||||
|
|
||||||
|
// Apply mandatory parameters
|
||||||
|
configObject.dom_id = "#swagger-ui";
|
||||||
|
configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset];
|
||||||
|
configObject.layout = "StandaloneLayout";
|
||||||
|
configObject.requestInterceptor = function (request) {
|
||||||
|
request.headers.Authorization = "Bearer " + abp.auth.getToken();
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
if (!configObject.hasOwnProperty("oauth2RedirectUrl")) {
|
||||||
|
configObject.oauth2RedirectUrl = window.location + "oauth2-redirect.html"; // use the built-in default
|
||||||
|
}
|
||||||
|
function getAuthorizeButtonText() {
|
||||||
|
return abp.auth.getToken() ? 'Logout' : 'Authorize';
|
||||||
|
}
|
||||||
|
function getAuthorizeButtonCssClass() {
|
||||||
|
return abp.auth.getToken() ? 'cancel' : 'authorize';
|
||||||
|
}
|
||||||
|
configObject.plugins = [
|
||||||
|
function (system) {
|
||||||
|
return {
|
||||||
|
components: {
|
||||||
|
authorizeBtn: function () {
|
||||||
|
return system.React.createElement("button",
|
||||||
|
{
|
||||||
|
id: "authorize",
|
||||||
|
className: "btn " + getAuthorizeButtonCssClass(),
|
||||||
|
style: {
|
||||||
|
lineHeight: "normal"
|
||||||
|
},
|
||||||
|
onClick: function () {
|
||||||
|
var authorizeButton = document.getElementById('authorize');
|
||||||
|
if (abp.auth.getToken()) {
|
||||||
|
abp.swagger.logout();
|
||||||
|
authorizeButton.innerText = getAuthorizeButtonText();
|
||||||
|
authorizeButton.className = 'btn ' + getAuthorizeButtonCssClass();
|
||||||
|
} else {
|
||||||
|
abp.swagger.openAuthDialog(function () {
|
||||||
|
authorizeButton.innerText = getAuthorizeButtonText();
|
||||||
|
authorizeButton.className = 'btn ' + getAuthorizeButtonCssClass();
|
||||||
|
abp.swagger.closeAuthDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, getAuthorizeButtonText());
|
||||||
|
}, info: function () {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Build a system
|
||||||
|
SwaggerUIBundle(configObject);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,117 @@
|
||||||
|
var abp = abp || {};
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
/* Application paths *****************************************/
|
||||||
|
|
||||||
|
// Current application root path (including virtual directory if exists).
|
||||||
|
abp.appPath = abp.appPath || '/';
|
||||||
|
|
||||||
|
/* AUTHORIZATION **********************************************/
|
||||||
|
// Implements Authorization API that simplifies usage of authorization scripts generated by Abp.
|
||||||
|
|
||||||
|
abp.auth = abp.auth || {};
|
||||||
|
|
||||||
|
abp.auth.tokenCookieName = 'Abp.AuthToken';
|
||||||
|
abp.auth.tokenHeaderName = 'Authorization';
|
||||||
|
|
||||||
|
abp.auth.setToken = function (authToken, expireDate) {
|
||||||
|
abp.utils.setCookieValue(abp.auth.tokenCookieName, authToken, expireDate, abp.appPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
abp.auth.getToken = function () {
|
||||||
|
return abp.utils.getCookieValue(abp.auth.tokenCookieName);
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.auth.clearToken = function () {
|
||||||
|
abp.auth.setToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UTILS ***************************************************/
|
||||||
|
|
||||||
|
abp.utils = abp.utils || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cookie value for given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} value
|
||||||
|
* @param {Date} expireDate (optional). If not specified the cookie will expire at the end of session.
|
||||||
|
* @param {string} path (optional)
|
||||||
|
*/
|
||||||
|
abp.utils.setCookieValue = function (key, value, expireDate, path) {
|
||||||
|
var cookieValue = encodeURIComponent(key) + '=';
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
cookieValue = cookieValue + encodeURIComponent(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expireDate) {
|
||||||
|
cookieValue = cookieValue + "; expires=" + expireDate.toUTCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
cookieValue = cookieValue + "; path=" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cookie with given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {string} Cookie value or null
|
||||||
|
*/
|
||||||
|
abp.utils.getCookieValue = function (key) {
|
||||||
|
var equalities = document.cookie.split('; ');
|
||||||
|
for (var i = 0; i < equalities.length; i++) {
|
||||||
|
if (!equalities[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitted = equalities[i].split('=');
|
||||||
|
if (splitted.length != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeURIComponent(splitted[0]) === key) {
|
||||||
|
return decodeURIComponent(splitted[1] || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes cookie for given key.
|
||||||
|
* This is a simple implementation created to be used by ABP.
|
||||||
|
* Please use a complete cookie library if you need.
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} path (optional)
|
||||||
|
*/
|
||||||
|
abp.utils.deleteCookie = function (key, path) {
|
||||||
|
var cookieValue = encodeURIComponent(key) + '=';
|
||||||
|
|
||||||
|
cookieValue = cookieValue + "; expires=" + (new Date(new Date().getTime() - 86400000)).toUTCString();
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
cookieValue = cookieValue + "; path=" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.cookie = cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SECURITY ***************************************/
|
||||||
|
abp.security = abp.security || {};
|
||||||
|
abp.security.antiForgery = abp.security.antiForgery || {};
|
||||||
|
|
||||||
|
abp.security.antiForgery.tokenCookieName = 'XSRF-TOKEN';
|
||||||
|
abp.security.antiForgery.tokenHeaderName = 'X-XSRF-TOKEN';
|
||||||
|
|
||||||
|
abp.security.antiForgery.getToken = function () {
|
||||||
|
return abp.utils.getCookieValue(abp.security.antiForgery.tokenCookieName);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,470 @@
|
||||||
|
var abp = abp || {};
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
/* md5*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||||
|
* Digest Algorithm, as defined in RFC 1321.
|
||||||
|
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||||
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||||
|
* Distributed under the BSD License
|
||||||
|
* See http://pajhome.org.uk/crypt/md5 for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configurable variables. You may need to tweak these to be compatible with
|
||||||
|
* the server-side, but the defaults work in most cases.
|
||||||
|
*/
|
||||||
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
||||||
|
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
|
||||||
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are the functions you'll usually want to call
|
||||||
|
* They take string arguments and return either hex or base-64 encoded strings
|
||||||
|
*/
|
||||||
|
function hex_md5(s) { return binl2hex(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function b64_md5(s) { return binl2b64(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function str_md5(s) { return binl2str(core_md5(str2binl(s), s.length * chrsz)); }
|
||||||
|
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
|
||||||
|
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
|
||||||
|
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a simple self-test to see if the VM is working
|
||||||
|
*/
|
||||||
|
function md5_vm_test() {
|
||||||
|
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the MD5 of an array of little-endian words, and a bit length
|
||||||
|
*/
|
||||||
|
function core_md5(x, len) {
|
||||||
|
/* append padding */
|
||||||
|
x[len >> 5] |= 0x80 << ((len) % 32);
|
||||||
|
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||||
|
|
||||||
|
var a = 1732584193;
|
||||||
|
var b = -271733879;
|
||||||
|
var c = -1732584194;
|
||||||
|
var d = 271733878;
|
||||||
|
|
||||||
|
for (var i = 0; i < x.length; i += 16) {
|
||||||
|
var olda = a;
|
||||||
|
var oldb = b;
|
||||||
|
var oldc = c;
|
||||||
|
var oldd = d;
|
||||||
|
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
|
||||||
|
a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
|
||||||
|
d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
|
||||||
|
c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
|
||||||
|
b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
|
||||||
|
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
|
||||||
|
a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
|
||||||
|
d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
|
||||||
|
c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
|
||||||
|
b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
|
||||||
|
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
|
||||||
|
a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
|
||||||
|
d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
|
||||||
|
c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
|
||||||
|
b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
|
||||||
|
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
|
||||||
|
a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
|
||||||
|
d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
|
||||||
|
c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
|
||||||
|
b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
|
||||||
|
|
||||||
|
a = safe_add(a, olda);
|
||||||
|
b = safe_add(b, oldb);
|
||||||
|
c = safe_add(c, oldc);
|
||||||
|
d = safe_add(d, oldd);
|
||||||
|
}
|
||||||
|
return Array(a, b, c, d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These functions implement the four basic operations the algorithm uses.
|
||||||
|
*/
|
||||||
|
function md5_cmn(q, a, b, x, s, t) {
|
||||||
|
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
|
||||||
|
}
|
||||||
|
function md5_ff(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_gg(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_hh(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
|
||||||
|
}
|
||||||
|
function md5_ii(a, b, c, d, x, s, t) {
|
||||||
|
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the HMAC-MD5, of a key and some data
|
||||||
|
*/
|
||||||
|
function core_hmac_md5(key, data) {
|
||||||
|
var bkey = str2binl(key);
|
||||||
|
if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
|
||||||
|
|
||||||
|
var ipad = Array(16), opad = Array(16);
|
||||||
|
for (var i = 0; i < 16; i++) {
|
||||||
|
ipad[i] = bkey[i] ^ 0x36363636;
|
||||||
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
|
||||||
|
return core_md5(opad.concat(hash), 512 + 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||||
|
* to work around bugs in some JS interpreters.
|
||||||
|
*/
|
||||||
|
function safe_add(x, y) {
|
||||||
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||||
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||||
|
return (msw << 16) | (lsw & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitwise rotate a 32-bit number to the left.
|
||||||
|
*/
|
||||||
|
function bit_rol(num, cnt) {
|
||||||
|
return (num << cnt) | (num >>> (32 - cnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a string to an array of little-endian words
|
||||||
|
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
|
||||||
|
*/
|
||||||
|
function str2binl(str) {
|
||||||
|
var bin = Array();
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for (var i = 0; i < str.length * chrsz; i += chrsz)
|
||||||
|
bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a string
|
||||||
|
*/
|
||||||
|
function binl2str(bin) {
|
||||||
|
var str = "";
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for (var i = 0; i < bin.length * 32; i += chrsz)
|
||||||
|
str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a hex string.
|
||||||
|
*/
|
||||||
|
function binl2hex(binarray) {
|
||||||
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||||
|
var str = "";
|
||||||
|
for (var i = 0; i < binarray.length * 4; i++) {
|
||||||
|
str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
|
||||||
|
hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of little-endian words to a base-64 string
|
||||||
|
*/
|
||||||
|
function binl2b64(binarray) {
|
||||||
|
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
var str = "";
|
||||||
|
for (var i = 0; i < binarray.length * 4; i += 3) {
|
||||||
|
var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
|
||||||
|
| (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
|
||||||
|
| ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
|
||||||
|
for (var j = 0; j < 4; j++) {
|
||||||
|
if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
||||||
|
else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Swagger */
|
||||||
|
|
||||||
|
abp.swagger = abp.swagger || {};
|
||||||
|
|
||||||
|
abp.swagger.addAuthToken = function () {
|
||||||
|
var authToken = abp.auth.getToken();
|
||||||
|
if (!authToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.auth.tokenHeaderName, 'Bearer ' + authToken, 'header');
|
||||||
|
swaggerUi.api.clientAuthorizations.add('bearerAuth', cookieAuth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.addCsrfToken = function () {
|
||||||
|
var csrfToken = abp.security.antiForgery.getToken();
|
||||||
|
if (!csrfToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var csrfCookieAuth = new SwaggerClient.ApiKeyAuthorization(abp.security.antiForgery.tokenHeaderName, csrfToken, 'header');
|
||||||
|
swaggerUi.api.clientAuthorizations.add(abp.security.antiForgery.tokenHeaderName, csrfCookieAuth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loginUserInternal(tenantId, callback) {
|
||||||
|
|
||||||
|
var usernameOrEmailAddress = document.getElementById('userName').value;
|
||||||
|
if (!usernameOrEmailAddress) {
|
||||||
|
alert('UserName Can Not Be Null');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var password = document.getElementById('password').value;
|
||||||
|
if (!password) {
|
||||||
|
alert('PassWord Can Not Be Null');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
debugger;
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
debugger;
|
||||||
|
|
||||||
|
var resultdata = JSON.parse(xhr.responseText);
|
||||||
|
if (resultdata.ErrorMessage != '') {
|
||||||
|
alert(resultdata.ErrorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (resultdata.code == 300) {
|
||||||
|
alert(resultdata.message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var responseJSON = JSON.parse(xhr.responseText);
|
||||||
|
var result = responseJSON;
|
||||||
|
var expireDate = new Date(Date.now() + (60*60*24 * 1000));
|
||||||
|
abp.auth.setToken(result.Result.JWTStr, expireDate);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
alert('Login failed !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('POST', '/user/login', true);
|
||||||
|
xhr.setRequestHeader('Abp.TenantId', tenantId);
|
||||||
|
xhr.setRequestHeader('Content-type', 'application/json');
|
||||||
|
var parm = {
|
||||||
|
|
||||||
|
|
||||||
|
UserName: usernameOrEmailAddress,
|
||||||
|
Password: hex_md5(password),
|
||||||
|
}
|
||||||
|
xhr.send(JSON.stringify(parm));
|
||||||
|
//xhr.send("{" + "userName:'" + usernameOrEmailAddress + "'," + "passWord:'" + password + "'}");
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
abp.swagger.login = function (callback) {
|
||||||
|
//Get TenantId first
|
||||||
|
var tenancyName = document.getElementById('tenancyName').value;
|
||||||
|
|
||||||
|
if (tenancyName) {
|
||||||
|
var xhrTenancyName = new XMLHttpRequest();
|
||||||
|
xhrTenancyName.onreadystatechange = function () {
|
||||||
|
if (xhrTenancyName.readyState === XMLHttpRequest.DONE && xhrTenancyName.status === 200) {
|
||||||
|
var responseJSON = JSON.parse(xhrTenancyName.responseText);
|
||||||
|
var result = responseJSON.result;
|
||||||
|
if (result.state === 1) { // Tenant exists and active.
|
||||||
|
loginUserInternal(result.tenantId, callback); // Login for tenant
|
||||||
|
} else {
|
||||||
|
alert('There is no such tenant or tenant is not active !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhrTenancyName.open('POST', '/api/services/app/Account/IsTenantAvailable', true);
|
||||||
|
xhrTenancyName.setRequestHeader('Content-type', 'application/json');
|
||||||
|
xhrTenancyName.send("{" + "tenancyName:'" + tenancyName + "'}");
|
||||||
|
} else {
|
||||||
|
loginUserInternal(null, callback); // Login for host
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abp.swagger.logout = function () {
|
||||||
|
abp.auth.clearToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.closeAuthDialog = function () {
|
||||||
|
if (document.getElementById('abp-auth-dialog')) {
|
||||||
|
document.getElementsByClassName("swagger-ui")[1].removeChild(document.getElementById('abp-auth-dialog'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abp.swagger.openAuthDialog = function (loginCallback) {
|
||||||
|
abp.swagger.closeAuthDialog();
|
||||||
|
|
||||||
|
var abpAuthDialog = document.createElement('div');
|
||||||
|
abpAuthDialog.className = 'dialog-ux';
|
||||||
|
abpAuthDialog.id = 'abp-auth-dialog';
|
||||||
|
|
||||||
|
document.getElementsByClassName("swagger-ui")[1].appendChild(abpAuthDialog);
|
||||||
|
|
||||||
|
// -- backdrop-ux
|
||||||
|
var backdropUx = document.createElement('div');
|
||||||
|
backdropUx.className = 'backdrop-ux';
|
||||||
|
abpAuthDialog.appendChild(backdropUx);
|
||||||
|
|
||||||
|
// -- modal-ux
|
||||||
|
var modalUx = document.createElement('div');
|
||||||
|
modalUx.className = 'modal-ux';
|
||||||
|
abpAuthDialog.appendChild(modalUx);
|
||||||
|
|
||||||
|
// -- -- modal-dialog-ux
|
||||||
|
var modalDialogUx = document.createElement('div');
|
||||||
|
modalDialogUx.className = 'modal-dialog-ux';
|
||||||
|
modalUx.appendChild(modalDialogUx);
|
||||||
|
|
||||||
|
// -- -- -- modal-ux-inner
|
||||||
|
var modalUxInner = document.createElement('div');
|
||||||
|
modalUxInner.className = 'modal-ux-inner';
|
||||||
|
modalDialogUx.appendChild(modalUxInner);
|
||||||
|
|
||||||
|
// -- -- -- -- modal-ux-header
|
||||||
|
var modalUxHeader = document.createElement('div');
|
||||||
|
modalUxHeader.className = 'modal-ux-header';
|
||||||
|
modalUxInner.appendChild(modalUxHeader);
|
||||||
|
|
||||||
|
var modalHeader = document.createElement('h3');
|
||||||
|
modalHeader.innerText = 'Authorize';
|
||||||
|
modalUxHeader.appendChild(modalHeader);
|
||||||
|
|
||||||
|
// -- -- -- -- modal-ux-content
|
||||||
|
var modalUxContent = document.createElement('div');
|
||||||
|
modalUxContent.className = 'modal-ux-content';
|
||||||
|
modalUxInner.appendChild(modalUxContent);
|
||||||
|
|
||||||
|
modalUxContent.onkeydown = function (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
//try to login when user presses enter on authorize modal
|
||||||
|
abp.swagger.login(loginCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Inputs
|
||||||
|
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
|
||||||
|
createInput(modalUxContent, 'userName', 'Username or email address','text','admin');
|
||||||
|
createInput(modalUxContent, 'password', 'Password','password');
|
||||||
|
|
||||||
|
//Buttons
|
||||||
|
var authBtnWrapper = document.createElement('div');
|
||||||
|
authBtnWrapper.className = 'auth-btn-wrapper';
|
||||||
|
modalUxContent.appendChild(authBtnWrapper);
|
||||||
|
|
||||||
|
//Close button
|
||||||
|
var closeButton = document.createElement('button');
|
||||||
|
closeButton.className = 'btn modal-btn auth btn-done button';
|
||||||
|
closeButton.innerText = 'Close';
|
||||||
|
closeButton.style.marginRight = '5px';
|
||||||
|
closeButton.onclick = abp.swagger.closeAuthDialog;
|
||||||
|
authBtnWrapper.appendChild(closeButton);
|
||||||
|
|
||||||
|
//Authorize button
|
||||||
|
var authorizeButton = document.createElement('button');
|
||||||
|
authorizeButton.className = 'btn modal-btn auth authorize button';
|
||||||
|
authorizeButton.innerText = 'Login';
|
||||||
|
authorizeButton.onclick = function () {
|
||||||
|
abp.swagger.login(loginCallback);
|
||||||
|
};
|
||||||
|
authBtnWrapper.appendChild(authorizeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInput(container, id, title, type, value="") {
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'wrapper';
|
||||||
|
if (id == "tenancyName") {
|
||||||
|
wrapper.style.display = 'none';
|
||||||
|
}
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.innerText = title;
|
||||||
|
wrapper.appendChild(label);
|
||||||
|
|
||||||
|
var section = document.createElement('section');
|
||||||
|
section.className = 'block-tablet col-10-tablet block-desktop col-10-desktop';
|
||||||
|
wrapper.appendChild(section);
|
||||||
|
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.id = id;
|
||||||
|
input.type = type ? type : 'text';
|
||||||
|
input.style.width = '100%';
|
||||||
|
input.value = value;
|
||||||
|
input.autocomplete = "off";
|
||||||
|
|
||||||
|
|
||||||
|
section.appendChild(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,97 @@
|
||||||
|
using Castle.DynamicProxy;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.AOP
|
||||||
|
{
|
||||||
|
public abstract class AsyncInterceptorBase : IInterceptor
|
||||||
|
{
|
||||||
|
public AsyncInterceptorBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Intercept(IInvocation invocation)
|
||||||
|
{
|
||||||
|
BeforeProceed(invocation);
|
||||||
|
invocation.Proceed();
|
||||||
|
if (IsAsyncMethod(invocation.MethodInvocationTarget))
|
||||||
|
{
|
||||||
|
invocation.ReturnValue = InterceptAsync((dynamic)invocation.ReturnValue, invocation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AfterProceedSync(invocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckMethodReturnTypeIsTaskType(MethodInfo method)
|
||||||
|
{
|
||||||
|
var methodReturnType = method.ReturnType;
|
||||||
|
if (methodReturnType.IsGenericType)
|
||||||
|
{
|
||||||
|
if (methodReturnType.GetGenericTypeDefinition() == typeof(Task<>) ||
|
||||||
|
methodReturnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (methodReturnType == typeof(Task) ||
|
||||||
|
methodReturnType == typeof(ValueTask))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAsyncMethod(MethodInfo method)
|
||||||
|
{
|
||||||
|
bool isDefAsync = Attribute.IsDefined(method, typeof(AsyncStateMachineAttribute), false);
|
||||||
|
bool isTaskType = CheckMethodReturnTypeIsTaskType(method);
|
||||||
|
bool isAsync = isDefAsync && isTaskType;
|
||||||
|
|
||||||
|
return isAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected object ProceedAsyncResult { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private async Task InterceptAsync(Task task, IInvocation invocation)
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
await AfterProceedAsync(invocation, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TResult> InterceptAsync<TResult>(Task<TResult> task, IInvocation invocation)
|
||||||
|
{
|
||||||
|
ProceedAsyncResult = await task.ConfigureAwait(false);
|
||||||
|
await AfterProceedAsync(invocation, true);
|
||||||
|
return (TResult)ProceedAsyncResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask InterceptAsync(ValueTask task, IInvocation invocation)
|
||||||
|
{
|
||||||
|
await task.ConfigureAwait(false);
|
||||||
|
await AfterProceedAsync(invocation, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<TResult> InterceptAsync<TResult>(ValueTask<TResult> task, IInvocation invocation)
|
||||||
|
{
|
||||||
|
ProceedAsyncResult = await task.ConfigureAwait(false);
|
||||||
|
await AfterProceedAsync(invocation, true);
|
||||||
|
return (TResult)ProceedAsyncResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void BeforeProceed(IInvocation invocation) { }
|
||||||
|
|
||||||
|
protected virtual void AfterProceedSync(IInvocation invocation) { }
|
||||||
|
|
||||||
|
protected virtual Task AfterProceedAsync(IInvocation invocation, bool hasAsynResult)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,499 @@
|
||||||
|
//using System;
|
||||||
|
//using Castle.DynamicProxy;
|
||||||
|
//using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||||
|
//using IRaCIS.Core.Infra.EFCore;
|
||||||
|
|
||||||
|
//using System.Linq;
|
||||||
|
//using IRaCIS.Core.Domain.Models;
|
||||||
|
//using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
//namespace IRaCIS.Core.API.Utility.AOP
|
||||||
|
//{
|
||||||
|
//#pragma warning disable
|
||||||
|
// public class QANoticeAOP : IInterceptor
|
||||||
|
// {
|
||||||
|
// private readonly IRepository<QANotice> _qaNoticeRepository;
|
||||||
|
|
||||||
|
// private readonly IRepository<DicomStudy> _studyRepository;
|
||||||
|
// private readonly IRepository<TrialUser> _userTrialRepository;
|
||||||
|
// private readonly IRepository<TrialSiteUser> _userTrialSiteRepository;
|
||||||
|
// private readonly IUserInfo _userInfo;
|
||||||
|
|
||||||
|
// public QANoticeAOP(IRepository<QANotice> qaNoticeRepository,
|
||||||
|
// IUserInfo userInfo, IRepository<DicomStudy> studyRepository, IRepository<TrialUser> userTrialRepository, IRepository<TrialSiteUser> userTrialSiteRepository)
|
||||||
|
// {
|
||||||
|
// _qaNoticeRepository = qaNoticeRepository;
|
||||||
|
|
||||||
|
// _studyRepository = studyRepository;
|
||||||
|
// _userTrialRepository = userTrialRepository;
|
||||||
|
// _userTrialSiteRepository = userTrialSiteRepository;
|
||||||
|
// _userInfo = userInfo;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public void Intercept(IInvocation invocation)
|
||||||
|
// {
|
||||||
|
// //处理拦截的方法
|
||||||
|
// invocation.Proceed();
|
||||||
|
|
||||||
|
// if (invocation.Method.Name == "UpdateStudyStatus")
|
||||||
|
// {
|
||||||
|
// var studyStatus = invocation.Arguments[0] as StudyStatusDetailCommand;
|
||||||
|
|
||||||
|
// var study = _studyRepository.FirstOrDefault(t=>t.Id==studyStatus.StudyId);
|
||||||
|
|
||||||
|
|
||||||
|
// if (study.Status == (int)StudyStatus.Uploaded)
|
||||||
|
// {
|
||||||
|
// _qaNoticeRepository.Add(new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
|
||||||
|
// NoticeTypeEnum = NoticeType.NotNeedNotice,
|
||||||
|
// NeedDeal = false,
|
||||||
|
// StudyStatusStr = "Uploaded",
|
||||||
|
// Message = $"IC : {_userInfo.RealName} has uploaded {study.StudyCode} ",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #region 处理QA通知模块
|
||||||
|
|
||||||
|
// //查询项目的参与者 和 负责site下IC用户
|
||||||
|
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// // 找到该study 关联Site 下的IC
|
||||||
|
|
||||||
|
// var crcList = _userTrialSiteRepository.Where(t =>
|
||||||
|
// t.SiteId == study.SiteId && t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
// var qaList = trialUserList.Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
||||||
|
|
||||||
|
// var pm = trialUserList.FirstOrDefault(t => t.User.UserTypeEnum == UserTypeEnum.ProjectManager);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // IC =>QA
|
||||||
|
// if (studyStatus.Status == (int)StudyStatus.QARequested)
|
||||||
|
// {
|
||||||
|
// //找出当前操作的IC
|
||||||
|
// //PM 或者admin可以代替IC角色 不能从IC列表中查询用户
|
||||||
|
// //var currentCRC = trialUserList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
|
||||||
|
// var notice = new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
|
||||||
|
// //FromUser = currentCRC.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentCRC.UserType,
|
||||||
|
// NoticeTypeEnum = NoticeType.CRC_RequestToQA_NoticeQA,
|
||||||
|
// NeedDeal = true,
|
||||||
|
// StudyStatusStr = "QA Requested",
|
||||||
|
// Message =
|
||||||
|
// $"IC -> QA : {_userInfo.RealName} request QA {study.StudyCode} , Inquiry can be performed! ",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// qaList.ForEach(t => notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// {
|
||||||
|
// QANoticeId = notice.Id,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// ToUser = t.User.LastName + " / " + t.User.FirstName,
|
||||||
|
// ToUserId = t.UserId,
|
||||||
|
// ToUserType = t.User.UserTypeRole.UserTypeShortName
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// _qaNoticeRepository.Add(notice);
|
||||||
|
|
||||||
|
// //DealRequestToQA(study.Id);
|
||||||
|
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.AsQueryable()
|
||||||
|
// .Where(t => t.SubjectVisitId == study.Id && t.NeedDeal && t.NoticeTypeEnum == NoticeType.CRC_RequestToQA_NoticeQA).ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // QA =>IC 向IC推送消息影像有问题 同时作为 requestToQA 的边界
|
||||||
|
// else if (studyStatus.Status == (int)StudyStatus.QAing)
|
||||||
|
// {
|
||||||
|
// //找出当前操作的QA 如果是pm 或者admin 代替操作 此时会有问题 所以 谁代替,就以谁的名义执行
|
||||||
|
// //var currentQA = qaList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
// //var currentQA = trialUserList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
|
||||||
|
// //在项目IC列表中筛选出 负责该study关联 site的IC
|
||||||
|
// var siteCRCList = _userTrialSiteRepository.Where(t =>
|
||||||
|
// t.SiteId == study.SiteId && t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// //查询项目的参与者 和 负责site下IC用户
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var notice = new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// //FromUser = currentQA.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentQA.UserType,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.QA_InQA_NoticeCRC,
|
||||||
|
// NeedDeal = true,
|
||||||
|
// StudyStatusStr = "In QA",
|
||||||
|
// Message = $"QA -> IC : {_userInfo.RealName} inquiry {study.StudyCode} ",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// siteCRCList.ForEach(t => notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// {
|
||||||
|
// QANoticeId = notice.Id,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// ToUser = t.User.LastName + " / " + t.User.FirstName,
|
||||||
|
// ToUserId = t.UserId,
|
||||||
|
// ToUserType = t.UserTypeRole.UserTypeShortName
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// //添加 发送给IC的消息 消息和IC是 一对多
|
||||||
|
// _qaNoticeRepository.Add(notice);
|
||||||
|
|
||||||
|
|
||||||
|
// //处理 消息 标记已处理
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.AsQueryable()
|
||||||
|
// .Where(t => t.SubjectVisitId == study.Id && t.NeedDeal &&
|
||||||
|
// (t.NoticeTypeEnum == NoticeType.CRC_RequestToQA_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_ReUpload_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_QARecordDialogPost_NoticeQA)).ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
// // QA =>QA 给自己的消息 通知需要匿名化 同时作为 requestToQA 的边界
|
||||||
|
// else if (studyStatus.Status == (int)StudyStatus.QAFinish)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// //找出当前操作的QA 如果是pm 或者admin 代替操作 此时会有问题 所以 谁代替,就以谁的名义执行
|
||||||
|
// //var currentQA = qaList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
// //var currentQA = trialUserList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
|
||||||
|
// //发送给当前项目QA列表
|
||||||
|
|
||||||
|
// var notice = new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// //FromUser = currentQA.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentQA.UserType,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.QA_QAPass_NoticeQA,
|
||||||
|
// NeedDeal = true,
|
||||||
|
// StudyStatusStr = "QA-Passed",
|
||||||
|
// Message =
|
||||||
|
// $"QA -> QA : {_userInfo.RealName} inquiry {study.StudyCode} finished,Anonymization can be performed!",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// qaList.ForEach(t => notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// {
|
||||||
|
// QANoticeId = notice.Id,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// ToUser = t.User.LastName+" / "+t.User.FirstName,
|
||||||
|
// ToUserId = t.UserId,
|
||||||
|
// ToUserType = t.User.UserTypeRole.UserTypeShortName
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// _qaNoticeRepository.Add(notice);
|
||||||
|
|
||||||
|
// //处理 消息 标记已处理 存在意外情况 qa发给IC的 但是qa里面设置了 通过或者不通过 此时qa发送的消息也设置为已处理
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.AsQueryable()
|
||||||
|
// .Where(t => t.SubjectVisitId == study.Id && t.NeedDeal &&
|
||||||
|
// (t.NoticeTypeEnum == NoticeType.CRC_RequestToQA_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_ReUpload_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_QARecordDialogPost_NoticeQA ||
|
||||||
|
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_QARecordDialogPost_NoticeCRC ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_InQA_NoticeCRC ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_AddQARecord_NoticeCRC)).ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
// // QA =>IC 暂时不用发送消息给IC 因为IC 暂时没有入口回复 同时作为 requestToQA 的边界
|
||||||
|
// else if (studyStatus.Status == (int)StudyStatus.QAFInishNotPass)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// _qaNoticeRepository.Add(new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.NotNeedNotice,
|
||||||
|
// NeedDeal = false,
|
||||||
|
// StudyStatusStr = "QA-Failed",
|
||||||
|
// Message = $"QA : {_userInfo.RealName} set {study.StudyCode} QA-Failed !",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// //处理 消息 标记已处理
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.AsQueryable()
|
||||||
|
// .Where(t => t.SubjectVisitId == study.Id && t.NeedDeal &&
|
||||||
|
// (t.NoticeTypeEnum == NoticeType.CRC_RequestToQA_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_ReUpload_NoticeQA ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.CRC_QARecordDialogPost_NoticeQA ||
|
||||||
|
|
||||||
|
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_QARecordDialogPost_NoticeCRC ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_InQA_NoticeCRC ||
|
||||||
|
// t.NoticeTypeEnum == NoticeType.QA_AddQARecord_NoticeCRC)).ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// else if (invocation.Method.Name == "ReUploadSameStudy")
|
||||||
|
// {
|
||||||
|
// var studyId = Guid.Parse(invocation.Arguments[0].ToString());
|
||||||
|
|
||||||
|
// var study = _studyRepository.FirstOrDefault(t => t.Id == studyId);
|
||||||
|
// var status = study.Status;
|
||||||
|
|
||||||
|
// //处理IC 重传时 QA消息
|
||||||
|
|
||||||
|
// if (status == (int)StudyStatus.QAing)
|
||||||
|
// {
|
||||||
|
// //查询项目的参与者 和 负责site下IC用户
|
||||||
|
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// // 找到该study 关联Site 下的IC
|
||||||
|
|
||||||
|
// var crcList = _userTrialSiteRepository.Where(t =>
|
||||||
|
// t.SiteId == study.SiteId && t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// var qaList = trialUserList.Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
||||||
|
|
||||||
|
// //IC =>QA IC的职能被PM 或者admin代替
|
||||||
|
// //if (_userInfo.UserTypeEnumInt == (int)UserType.ClinicalResearchCoordinator)
|
||||||
|
// {
|
||||||
|
// //PM 或者admin可以代替IC角色 不能从IC列表中查询用户
|
||||||
|
// //var currentCRC = trialUserList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
|
||||||
|
// var notice = new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// //FromUser = currentCRC.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentCRC.UserType,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.CRC_ReUpload_NoticeQA,
|
||||||
|
// NeedDeal = true,
|
||||||
|
// Message = $"IC -> QA :{_userInfo.RealName} has reuploaded {study.StudyCode} , Need to be inquiry again",
|
||||||
|
// SendTime = DateTime.Now
|
||||||
|
// };
|
||||||
|
|
||||||
|
// qaList.ForEach(t => notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// {
|
||||||
|
// QANoticeId = notice.Id,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// ToUser = t.User.LastName+" / "+t.User.FirstName,
|
||||||
|
// ToUserId = t.UserId,
|
||||||
|
// ToUserType = t.User.UserTypeRole.UserTypeShortName
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// _qaNoticeRepository.Add(notice);
|
||||||
|
|
||||||
|
// //这里作为 QA 设置 Inqa 状态的回复 或者QA和IC对话的
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.Where(t => t.SubjectVisitId == study.Id && t.NeedDeal
|
||||||
|
// && (t.NoticeTypeEnum == NoticeType.QA_InQA_NoticeCRC || t.NoticeTypeEnum == NoticeType.QA_QARecordDialogPost_NoticeCRC))
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// //不是QAing 的重传 不发送qa消息
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// else if (invocation.Method.Name == "DicomAnonymize")
|
||||||
|
// {
|
||||||
|
// var studyId = Guid.Parse(invocation.Arguments[0].ToString());
|
||||||
|
|
||||||
|
// var study = _studyRepository.FirstOrDefault(t => t.Id == studyId);
|
||||||
|
|
||||||
|
// #region 处理QA通知 匿名化完毕 通知PM
|
||||||
|
|
||||||
|
// //查询项目的参与者 和 负责site下IC用户
|
||||||
|
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// // 找到该study 关联Site 下的IC
|
||||||
|
|
||||||
|
// var crcList = _userTrialSiteRepository.Where(t =>
|
||||||
|
// t.SiteId == study.SiteId && t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && t.TrialId == study.TrialId).ToList();
|
||||||
|
|
||||||
|
// var qaList = trialUserList.Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
||||||
|
|
||||||
|
// //
|
||||||
|
// var pm = trialUserList.FirstOrDefault(t => t.User.UserTypeEnum == UserTypeEnum.ProjectManager);
|
||||||
|
|
||||||
|
|
||||||
|
// //找出当前操作的QA 如果是pm 或者admin 代替操作 此时会有问题 所以 谁代替,就以谁的名义执行
|
||||||
|
// //var currentQA = trialUserList.First(t =>
|
||||||
|
// // t.UserTypeEnum == UserType.IQC && t.UserId == _userInfo.Id);
|
||||||
|
// //var currentQA = trialUserList.First(t => t.UserId == _userInfo.Id);
|
||||||
|
|
||||||
|
// var notice = new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// //FromUser = currentQA.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentQA.UserType,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.QA_Anonymized_NoticeQA,
|
||||||
|
// NeedDeal = true,
|
||||||
|
// StudyStatusStr = "Anonymized",
|
||||||
|
// //Message = $"QA -> PM :{_userInfo.RealName} has anonymized {study.StudyCode} ,Forward can be performed!!",
|
||||||
|
// Message = $"QA -> QA :{_userInfo.RealName} has anonymized {study.StudyCode} ,Forward can be performed!!",
|
||||||
|
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
// //notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// //{
|
||||||
|
// // QANoticeId = notice.Id,
|
||||||
|
// // StudyId = study.Id,
|
||||||
|
// // ToUser = pm.UserRealName,
|
||||||
|
// // ToUserId = pm.UserId,
|
||||||
|
// // ToUserType = pm.UserType
|
||||||
|
// //});
|
||||||
|
|
||||||
|
// qaList.ForEach(t => notice.QANoticeUserList.Add(new QANoticeUser()
|
||||||
|
// {
|
||||||
|
// QANoticeId = notice.Id,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// ToUser = t.User.LastName+" / "+t.User.FirstName,
|
||||||
|
// ToUserId = t.UserId,
|
||||||
|
// ToUserType = t.User.UserTypeRole.UserTypeShortName
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// _qaNoticeRepository.Add(notice);
|
||||||
|
|
||||||
|
// var needDealNoticeList = _qaNoticeRepository.AsQueryable()
|
||||||
|
// .Where(t => t.SubjectVisitId == study.Id && t.NeedDeal && (t.NoticeTypeEnum == NoticeType.QA_QAPass_NoticeQA)).ToList();
|
||||||
|
|
||||||
|
// needDealNoticeList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// }
|
||||||
|
|
||||||
|
// else if (invocation.Method.Name == "ForwardStudy")
|
||||||
|
// {
|
||||||
|
// var studyId = Guid.Parse(invocation.Arguments[0].ToString());
|
||||||
|
|
||||||
|
// var study = _studyRepository.FirstOrDefault(t => t.Id == studyId);
|
||||||
|
|
||||||
|
// //匿名化操作产生的消息 设置为已经处理
|
||||||
|
// _qaNoticeRepository.Add(new QANotice()
|
||||||
|
// {
|
||||||
|
// TrialId = study.TrialId,
|
||||||
|
// SubjectVisitId = study.Id,
|
||||||
|
// //FromUser = currentQA.UserRealName,
|
||||||
|
// //FromUserId = _userInfo.Id,
|
||||||
|
// //FromUserType = currentQA.UserType,
|
||||||
|
// FromUser = _userInfo.RealName,
|
||||||
|
// FromUserId = _userInfo.Id,
|
||||||
|
// FromUserType = _userInfo.UserTypeShortName,
|
||||||
|
// NoticeTypeEnum = NoticeType.NotNeedNotice,
|
||||||
|
// NeedDeal = false,
|
||||||
|
// StudyStatusStr = "Forwarded",
|
||||||
|
// //Message = $"PM :{_userInfo.RealName} has forwarded {study.StudyCode} !",
|
||||||
|
// Message = $"QA :{_userInfo.RealName} has forwarded {study.StudyCode} !",
|
||||||
|
// SendTime = DateTime.Now,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// var needDealList = _qaNoticeRepository.Where(t =>
|
||||||
|
// t.SubjectVisitId == study.Id && t.NeedDeal && t.NoticeTypeEnum == NoticeType.QA_Anonymized_NoticeQA).ToList();
|
||||||
|
|
||||||
|
// needDealList.ForEach(t =>
|
||||||
|
// {
|
||||||
|
// t.NeedDeal = false;
|
||||||
|
// t.DealTime = DateTime.Now;
|
||||||
|
// _qaNoticeRepository.Update(t);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// var success = _qaNoticeRepository.SaveChanges();
|
||||||
|
|
||||||
|
// if (!success)
|
||||||
|
// {
|
||||||
|
// throw new Exception("Send QA message failed");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using Castle.DynamicProxy;
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.AOP
|
||||||
|
{
|
||||||
|
public class TrialStatusAutofacAOP : IAsyncInterceptor
|
||||||
|
{
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
|
||||||
|
public TrialStatusAutofacAOP(IEasyCachingProvider provider)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void InterceptAsynchronous(IInvocation invocation)
|
||||||
|
{
|
||||||
|
invocation.Proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
//这里AOP 处理两个方法 分别是 项目的添加和更新、项目状态的变更
|
||||||
|
|
||||||
|
public void InterceptAsynchronous<TResult>(IInvocation invocation)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//处理拦截的方法
|
||||||
|
invocation.Proceed();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dynamic result = invocation.ReturnValue;
|
||||||
|
|
||||||
|
//接口成功了,才修改缓存
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 处理项目列表的查询 在前端界面已经在某个界面,但是服务器重置了,此时没有缓存项目信息,接口不能正确返回,因故采用,启动时查询,每天查询一次,缓存一天,然后项目添加、更改状态时,及时更新
|
||||||
|
|
||||||
|
//if (invocation.Method.Name == "GetTrialList")
|
||||||
|
//{
|
||||||
|
// //在此 将当前查询的项目Id 和对应的项目状态进行缓存
|
||||||
|
// dynamic result = invocation.ReturnValue;
|
||||||
|
// foreach (var item in result.CurrentPageData)
|
||||||
|
// {
|
||||||
|
// _provider.Remove(item.Id.ToString());
|
||||||
|
// _provider.Set(item.Id.ToString(), item.TrialStatusStr.ToString(), TimeSpan.FromDays(1));
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
if (invocation.Method.Name == "AddOrUpdateTrial")
|
||||||
|
{
|
||||||
|
//如果是添加 那么将对应的初始状态加进去 更新状态是单独操作的
|
||||||
|
|
||||||
|
var trialModel = (invocation.Arguments[0] as TrialCommand).IfNullThrowConvertException();
|
||||||
|
if (trialModel.Id == null || trialModel.Id == Guid.Empty)
|
||||||
|
{
|
||||||
|
_provider.Set(result.Data.Id.ToString(), StaticData.TrialState.TrialOngoing, TimeSpan.FromDays(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// 更新缓存
|
||||||
|
else if (invocation.Method.Name == "UpdateTrialStatus")
|
||||||
|
{
|
||||||
|
//项目状态更新,也需要及时更新
|
||||||
|
_provider.Set(invocation.Arguments[0].ToString(), invocation.Arguments[1].ToString(), TimeSpan.FromDays(1));
|
||||||
|
|
||||||
|
////Test参数是否符合要求
|
||||||
|
//var tt = invocation.Arguments[0].ToString();
|
||||||
|
//var cc = _provider.Get<string>(invocation.Arguments[0].ToString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InterceptSynchronous(IInvocation invocation)
|
||||||
|
{
|
||||||
|
invocation.Proceed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using IRaCIS.Application.Contracts;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Auth
|
||||||
|
{
|
||||||
|
public class IRaCISClaims
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string FullName { get; set; } = String.Empty;
|
||||||
|
public string Code { get; set; } = String.Empty;
|
||||||
|
public string RealName { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string UserTypeShortName { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public UserTypeEnum UserTypeEnum { get; set; }
|
||||||
|
|
||||||
|
public string PermissionStr { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public Guid UserTypeId { get; set; }
|
||||||
|
|
||||||
|
public int IsAdmin { get; }
|
||||||
|
|
||||||
|
public bool IsTestUser { get; set; }
|
||||||
|
|
||||||
|
public string Phone { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public static IRaCISClaims Create(UserBasicInfo user)
|
||||||
|
{
|
||||||
|
return new IRaCISClaims
|
||||||
|
{
|
||||||
|
Id = user.Id,
|
||||||
|
FullName = user.UserName,
|
||||||
|
RealName = user.RealName,
|
||||||
|
UserTypeEnum=user.UserTypeEnum,
|
||||||
|
UserTypeId=user.UserTypeId,
|
||||||
|
IsTestUser=user.IsTestUser,
|
||||||
|
Code = user.Code,
|
||||||
|
PermissionStr = user.PermissionStr,
|
||||||
|
|
||||||
|
UserTypeShortName = user.UserTypeShortName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static IRaCISClaims Create(DoctorAccountDTO doctor)
|
||||||
|
{
|
||||||
|
return new IRaCISClaims
|
||||||
|
{
|
||||||
|
Id = doctor.Id,
|
||||||
|
FullName = doctor.FirstName + doctor.LastName,
|
||||||
|
Phone = doctor.Phone,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Auth
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public static class IRaCISPolicy
|
||||||
|
{
|
||||||
|
public const string IC = "IC";
|
||||||
|
|
||||||
|
public const string PM = "PM";
|
||||||
|
|
||||||
|
public const string IQC = "IQC";
|
||||||
|
|
||||||
|
public const string PM_IQC = "PM_IQC";
|
||||||
|
|
||||||
|
public const string CRC_IQC = "CRC_IQC";
|
||||||
|
|
||||||
|
|
||||||
|
public const string SPM_CPM = "SPM_CPM";
|
||||||
|
public const string PM_APM = "PM_APM";
|
||||||
|
public const string PM_APM_CRC = "PM_APM_CRC";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public const string PM_APM_SPM_CPM = "PM_APM_SPM_CPM";
|
||||||
|
|
||||||
|
public const string PM_APM_SPM_CPM_SMM_CMM = "PM_APM_SPM_CPM_SMM_CMM";
|
||||||
|
|
||||||
|
public const string PM_APM_CRC_QC = "PM_APM_CRC_QC";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Auth
|
||||||
|
{
|
||||||
|
public class JwtSetting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 颁发者
|
||||||
|
/// </summary>
|
||||||
|
public string Issuer { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 接收者
|
||||||
|
/// </summary>
|
||||||
|
public string Audience { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 令牌密码
|
||||||
|
/// </summary>
|
||||||
|
public string SecurityKey { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 过期时间
|
||||||
|
/// </summary>
|
||||||
|
public int TokenExpireDays { get; set; }
|
||||||
|
|
||||||
|
//public Dictionary<string, object> Claims { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 签名
|
||||||
|
/// </summary>
|
||||||
|
public SigningCredentials Credentials
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey));
|
||||||
|
return new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Auth
|
||||||
|
{
|
||||||
|
|
||||||
|
public interface ITokenService
|
||||||
|
{
|
||||||
|
string GetToken(IRaCISClaims user);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class TokenService : ITokenService
|
||||||
|
{
|
||||||
|
private readonly JwtSetting _jwtSetting;
|
||||||
|
|
||||||
|
public TokenService(IOptions<JwtSetting> option)
|
||||||
|
{
|
||||||
|
_jwtSetting = option.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetToken(IRaCISClaims user)
|
||||||
|
{
|
||||||
|
//创建用户身份标识,可按需要添加更多信息
|
||||||
|
var claims = new Claim[]
|
||||||
|
{
|
||||||
|
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.Id, user.Id.ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.Name, user.FullName),
|
||||||
|
new Claim(JwtIRaCISClaimType.RealName, user.RealName),
|
||||||
|
new Claim(JwtIRaCISClaimType.Code,user.Code),
|
||||||
|
new Claim(JwtIRaCISClaimType.UserTypeId,user.UserTypeId.ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.UserTypeEnum,user.UserTypeEnum.ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.UserTypeEnumInt,((int)user.UserTypeEnum).ToString()),
|
||||||
|
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
||||||
|
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
||||||
|
|
||||||
|
new Claim(JwtIRaCISClaimType.IsTestUser,user.IsTestUser.ToString())
|
||||||
|
};
|
||||||
|
|
||||||
|
////创建令牌
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: _jwtSetting.Issuer,
|
||||||
|
audience: _jwtSetting.Audience,
|
||||||
|
signingCredentials: _jwtSetting.Credentials,
|
||||||
|
claims: claims,
|
||||||
|
notBefore: DateTime.Now,
|
||||||
|
expires: DateTime.Now.AddDays(_jwtSetting.TokenExpireDays)
|
||||||
|
);
|
||||||
|
|
||||||
|
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
return jwtToken;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Quartz;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Application.Services.BackGroundJob
|
||||||
|
{
|
||||||
|
|
||||||
|
public class CacheTrialStatusQuartZJob: IJob
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IRepository<Trial> _trialRepository;
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly ILogger<CacheTrialStatusQuartZJob> _logger;
|
||||||
|
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
|
||||||
|
|
||||||
|
public CacheTrialStatusQuartZJob(IRepository<Trial> trialRepository, IEasyCachingProvider provider,ILogger<CacheTrialStatusQuartZJob> logger, IRepository<SystemAnonymization> systemAnonymizationRepository)
|
||||||
|
{
|
||||||
|
_trialRepository = trialRepository;
|
||||||
|
_provider = provider;
|
||||||
|
_logger = logger;
|
||||||
|
_systemAnonymizationRepository = systemAnonymizationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Execute(IJobExecutionContext context)
|
||||||
|
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"开始执行QuartZ定时任务作业");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await MemoryCacheTrialStatus();
|
||||||
|
|
||||||
|
await MemoryCacheAnonymizeData();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError($" 查询和缓存过程出现异常"+e.Message);
|
||||||
|
}
|
||||||
|
_logger.LogInformation("QuartZ定时任务作业结束");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task MemoryCacheTrialStatus()
|
||||||
|
{
|
||||||
|
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MemoryCacheAnonymizeData()
|
||||||
|
{
|
||||||
|
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
||||||
|
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace IRaCIS.Application.Services.BackGroundJob
|
||||||
|
{
|
||||||
|
|
||||||
|
public interface IIRaCISCacheHangfireJob
|
||||||
|
{
|
||||||
|
|
||||||
|
Task ProjectStartCache();
|
||||||
|
Task MemoryCacheTrialStatus();
|
||||||
|
|
||||||
|
Task MemoryCacheAnonymizeData();
|
||||||
|
|
||||||
|
Task CacheUserTypePermission(Guid? cacheUserTypeId);
|
||||||
|
}
|
||||||
|
public class IRaCISCacheHangfireJob: IIRaCISCacheHangfireJob
|
||||||
|
{
|
||||||
|
private readonly IRepository<Trial> _trialRepository;
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly ILogger<IRaCISCacheHangfireJob> _logger;
|
||||||
|
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
|
||||||
|
|
||||||
|
private readonly IRepository<UserTypeMenu> _userTypeMenuRepository;
|
||||||
|
|
||||||
|
public IRaCISCacheHangfireJob(IRepository<Trial> trialRepository,
|
||||||
|
IRepository<SystemAnonymization> systemAnonymizationRepository, IRepository<UserTypeMenu> userTypeMenuRepository,
|
||||||
|
IEasyCachingProvider provider,ILogger<IRaCISCacheHangfireJob> logger)
|
||||||
|
{
|
||||||
|
_trialRepository = trialRepository;
|
||||||
|
_provider = provider;
|
||||||
|
_logger = logger;
|
||||||
|
_systemAnonymizationRepository = systemAnonymizationRepository;
|
||||||
|
_userTypeMenuRepository = userTypeMenuRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task ProjectStartCache()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("hangfire 定时缓存项目状态任务开始~");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await MemoryCacheTrialStatus();
|
||||||
|
|
||||||
|
await MemoryCacheAnonymizeData();
|
||||||
|
|
||||||
|
await CacheUserTypePermission();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError("hangfire 定时任务执行失败" + e.Message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("hangfire 定时任务执行结束");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task MemoryCacheTrialStatus()
|
||||||
|
{
|
||||||
|
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task MemoryCacheAnonymizeData()
|
||||||
|
{
|
||||||
|
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
||||||
|
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
|
||||||
|
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CacheUserTypePermission(Guid? cacheUserTypeId=null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var permissionList = await _userTypeMenuRepository.Where(t => t.Menu.MenuType == "F")
|
||||||
|
.WhereIf(cacheUserTypeId != null, t => t.UserTypeId == cacheUserTypeId.Value).Select(t => new { t.UserTypeId, t.Menu.PermissionStr }).ToListAsync();
|
||||||
|
|
||||||
|
foreach (var userTypeGroup in permissionList.GroupBy(t => t.UserTypeId))
|
||||||
|
{
|
||||||
|
_provider.Set($"{StaticData.CacheKey.UserTypeId}_{userTypeGroup.Key}", userTypeGroup.Select(t => t.PermissionStr).ToList(), TimeSpan.FromDays(7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.BackGroundJob
|
||||||
|
{
|
||||||
|
public interface IObtainTaskAutoCancelJob
|
||||||
|
{
|
||||||
|
Task CancelQCObtaion(Guid subjectVisitId,DateTime startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObtainTaskAutoCancelJob : IObtainTaskAutoCancelJob
|
||||||
|
{
|
||||||
|
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
|
||||||
|
private readonly ILogger<ObtainTaskAutoCancelJob> _logger;
|
||||||
|
|
||||||
|
public ObtainTaskAutoCancelJob(IRepository<SubjectVisit> subjectVisitRepository, ILogger<ObtainTaskAutoCancelJob> logger)
|
||||||
|
{
|
||||||
|
_subjectVisitRepository = subjectVisitRepository;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public async Task CancelQCObtaion(Guid subjectVisitId, DateTime startTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId).IfNullThrowException();
|
||||||
|
|
||||||
|
dbSubjectVisit.IsTake = false;
|
||||||
|
dbSubjectVisit.CurrentActionUserId = null;
|
||||||
|
dbSubjectVisit.CurrentActionUserExpireTime = null;
|
||||||
|
|
||||||
|
var success = await _subjectVisitRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
_logger.LogWarning($"任务建立时间:{startTime} 取消时间:{DateTime.Now} 取消 患者检查批次:{ subjectVisitId }success:{success}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError("hangfire 定时任务执行失败" + e.Message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using IRaCIS.Application.Services.BusinessFilter;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Panda.DynamicWebApi;
|
||||||
|
using Panda.DynamicWebApi.Attributes;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application
|
||||||
|
{
|
||||||
|
|
||||||
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
|
|
||||||
|
#region 非泛型版本
|
||||||
|
|
||||||
|
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
|
||||||
|
public class BaseService : IBaseService, IDynamicWebApi
|
||||||
|
{
|
||||||
|
public IMapper _mapper { get; set; }
|
||||||
|
|
||||||
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||||
|
{
|
||||||
|
return new ResponseOutput<string>()
|
||||||
|
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IBaseService
|
||||||
|
{
|
||||||
|
[MemberNotNull(nameof(_mapper))]
|
||||||
|
public IMapper _mapper { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_localizer))]
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_hostEnvironment))]
|
||||||
|
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region 泛型版本测试
|
||||||
|
|
||||||
|
|
||||||
|
public interface IBaseServiceTest<T> where T : Entity
|
||||||
|
{
|
||||||
|
[MemberNotNull(nameof(_mapper))]
|
||||||
|
public IMapper _mapper { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_userInfo))]
|
||||||
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_repository))]
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(_localizer))]
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
|
||||||
|
public class BaseServiceTest<T> : IBaseServiceTest<T>, IDynamicWebApi where T : Entity
|
||||||
|
{
|
||||||
|
public IMapper _mapper { get; set; }
|
||||||
|
|
||||||
|
public IUserInfo _userInfo { get; set; }
|
||||||
|
|
||||||
|
public IRepository _repository { get; set; }
|
||||||
|
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||||
|
{
|
||||||
|
return new ResponseOutput<string>()
|
||||||
|
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Filter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class LimitUserRequestAuthorization : IAsyncAuthorizationFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
|
||||||
|
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
|
||||||
|
|
||||||
|
public LimitUserRequestAuthorization(IEasyCachingProvider provider, IUserInfo userInfo, IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
_userInfo = userInfo;
|
||||||
|
_verifyConfig = verifyConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||||
|
{
|
||||||
|
if (_verifyConfig.CurrentValue.OpenLoginLimit)
|
||||||
|
{
|
||||||
|
if (context.ActionDescriptor.EndpointMetadata.Any(item => item is IAllowAnonymous))
|
||||||
|
{
|
||||||
|
|
||||||
|
return;
|
||||||
|
//匿名访问的不处理
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//1、用户登陆的时候,设置缓存
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//没有从请求中取到token
|
||||||
|
if (string.IsNullOrWhiteSpace(_userInfo.UserToken))
|
||||||
|
{
|
||||||
|
context.HttpContext.Response.ContentType = "application/json";
|
||||||
|
context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("当前请求未从Header/Url取到用户Token"));
|
||||||
|
|
||||||
|
//await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("当前请求未从Header/Url取到用户Token,请联系开发者")));
|
||||||
|
}
|
||||||
|
|
||||||
|
//2、在这里取缓存 进行比较 看是否有其他人进行了登陆,如果其他人登陆了,就把之前用户挤掉
|
||||||
|
var cacheUserToken = (await _provider.GetAsync<string>(_userInfo.Id.ToString())).Value;
|
||||||
|
|
||||||
|
//缓存中没有取到Token
|
||||||
|
if (string.IsNullOrWhiteSpace(cacheUserToken))
|
||||||
|
{
|
||||||
|
//设置当前用户最新Token
|
||||||
|
await _provider.SetAsync(_userInfo.Id.ToString(), _userInfo.UserToken, TimeSpan.FromDays(7));
|
||||||
|
|
||||||
|
cacheUserToken = _userInfo.UserToken;
|
||||||
|
|
||||||
|
}
|
||||||
|
//是同一个人
|
||||||
|
else if (cacheUserToken == _userInfo.UserToken)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
context.HttpContext.Response.ContentType = "application/json";
|
||||||
|
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("您的账户在其他地方已登陆,您被迫下线。", ApiResponseCodeEnum.LoginInOtherPlace));
|
||||||
|
//await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk("您的账户在其他地方已登陆,您被迫下线。", ApiResponseCodeEnum.LoginInOtherPlace)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//public class UserTypeRequirement : IAuthorizationRequirement
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public class UserTypeHandler : AuthorizationHandler<UserTypeRequirement>
|
||||||
|
//{
|
||||||
|
|
||||||
|
// private IUserInfo _userInfo;
|
||||||
|
|
||||||
|
// public UserTypeHandler(IUserInfo userInfo)
|
||||||
|
// {
|
||||||
|
// _userInfo = userInfo;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserTypeRequirement requirement)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// //if (context.User.Claims.Count() == 0)
|
||||||
|
// //{
|
||||||
|
// // return Task.CompletedTask;
|
||||||
|
// //}
|
||||||
|
|
||||||
|
// //string userId = context.User.Claims.First(c => c.Type == "Userid").Value;
|
||||||
|
// //string qq = context.User.Claims.First(c => c.Type == "QQ").Value;
|
||||||
|
|
||||||
|
// //if (_UserService.Validata(userId, qq))
|
||||||
|
// //{
|
||||||
|
// // context.Succeed(requirement); //验证通过了
|
||||||
|
// //}
|
||||||
|
// ////在这里就可以做验证
|
||||||
|
|
||||||
|
// return Task.CompletedTask;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
//using System.Diagnostics;
|
||||||
|
//using IRaCIS.Application.Interfaces;
|
||||||
|
//using IRaCIS.Application.Contracts;
|
||||||
|
//using IRaCIS.Core.Infra.EFCore;
|
||||||
|
//using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
//using Microsoft.AspNetCore.Mvc;
|
||||||
|
//using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
//using Microsoft.Extensions.Logging;
|
||||||
|
//using Newtonsoft.Json;
|
||||||
|
|
||||||
|
//namespace IRaCIS.Core.Application.Filter
|
||||||
|
//{
|
||||||
|
|
||||||
|
// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
// public class LogFilter : Attribute
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// public class LogActionFilter : IAsyncActionFilter
|
||||||
|
// {
|
||||||
|
// private readonly ILogService _logService;
|
||||||
|
// private readonly IUserInfo _userInfo;
|
||||||
|
// private readonly ILogger<LogActionFilter> _logger;
|
||||||
|
|
||||||
|
// public LogActionFilter(ILogService logService, IUserInfo userInfo , ILogger<LogActionFilter> logger)
|
||||||
|
// {
|
||||||
|
// _logService = logService;
|
||||||
|
// _userInfo = userInfo;
|
||||||
|
// _logger = logger;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// if (context.ActionDescriptor.EndpointMetadata!=null&& context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(LogFilter)))
|
||||||
|
// {
|
||||||
|
// return LogAsync(context, next);
|
||||||
|
// }
|
||||||
|
// return next();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public async Task LogAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
|
// {
|
||||||
|
// var sw = new Stopwatch();
|
||||||
|
// sw.Start();
|
||||||
|
|
||||||
|
// dynamic actionResult = (await next()).Result;
|
||||||
|
// sw.Stop();
|
||||||
|
// var args = JsonConvert.SerializeObject(context.ActionArguments);
|
||||||
|
// var result = JsonConvert.SerializeObject(actionResult?.Value);
|
||||||
|
|
||||||
|
// var attr = (ApiExplorerSettingsAttribute)context.ActionDescriptor.EndpointMetadata.FirstOrDefault(m => m.GetType() == typeof(ApiExplorerSettingsAttribute));
|
||||||
|
// var groupName = attr?.GroupName;
|
||||||
|
// var res = actionResult?.Value as IResponseOutput;
|
||||||
|
// var input = new SystemLogDTO
|
||||||
|
// {
|
||||||
|
// ClientIP = string.Empty,
|
||||||
|
// OptUserId = _userInfo.Id,
|
||||||
|
// OptUserName = _userInfo.UserName,
|
||||||
|
// ApiPath = context.ActionDescriptor.AttributeRouteInfo.Template.ToLower(),
|
||||||
|
// Params = args,
|
||||||
|
// Result = result,
|
||||||
|
// RequestTime = DateTime.Now,
|
||||||
|
// ElapsedMilliseconds = sw.ElapsedMilliseconds,
|
||||||
|
// Status =res?.IsSuccess?? false,
|
||||||
|
// Message = res?.ErrorMessage,
|
||||||
|
// LogCategory = groupName
|
||||||
|
// };
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// _logService.SaveLog2Db(input);
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// _logger.LogError(ex.Message);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
{
|
||||||
|
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
|
||||||
|
{
|
||||||
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
if (!context.ModelState.IsValid)
|
||||||
|
{
|
||||||
|
|
||||||
|
var validationErrors = context.ModelState
|
||||||
|
.Keys
|
||||||
|
.SelectMany(k => context.ModelState[k]!.Errors)
|
||||||
|
.Select(e => e.ErrorMessage)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("提供给接口的参数无效。" +JsonConvert.SerializeObject( validationErrors)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
{
|
||||||
|
#region snippet_DisableFormValueModelBindingAttribute
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
|
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||||
|
{
|
||||||
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var factories = context.ValueProviderFactories;
|
||||||
|
//factories.RemoveType<FormValueProviderFactory>();
|
||||||
|
factories.RemoveType<FormFileValueProviderFactory>();
|
||||||
|
factories.RemoveType<JQueryFormValueProviderFactory>();
|
||||||
|
context.HttpContext.Request.EnableBuffering();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
{
|
||||||
|
public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly ILogger<ProjectExceptionFilter> _logger;
|
||||||
|
|
||||||
|
public ProjectExceptionFilter(ILogger<ProjectExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
|
||||||
|
|
||||||
|
if (!context.ExceptionHandled)
|
||||||
|
{
|
||||||
|
if (context.Exception.GetType().Name == "DbUpdateConcurrencyException")
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("并发更新,当前不允许该操作" + context.Exception.Message));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.Exception.GetType() == typeof(BusinessValidationFailedException) || context.Exception.GetType() == typeof(DBSaveFailedException))
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message,ApiResponseCodeEnum.BusinessValidationFailed));
|
||||||
|
}
|
||||||
|
else if(context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk( context.Exception.Message, ApiResponseCodeEnum.DataNotExist));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("当前操作失败,请联系开发人员查看系统日志排查 ", ApiResponseCodeEnum.ProgramException));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//继续
|
||||||
|
}
|
||||||
|
context.ExceptionHandled = true;//标记当前异常已经被处理过了
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,208 @@
|
||||||
|
using EasyCaching.Core;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Filter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 主要为了 处理项目结束 锁库,不允许操作
|
||||||
|
/// </summary>
|
||||||
|
public class TrialResourceFilter : Attribute, IAsyncResourceFilter
|
||||||
|
{
|
||||||
|
private readonly IEasyCachingProvider _provider;
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
|
||||||
|
|
||||||
|
private readonly List<string> _trialOptList=new List<string>();
|
||||||
|
|
||||||
|
|
||||||
|
public TrialResourceFilter(IEasyCachingProvider provider, IUserInfo userInfo, string trialOpt = null, string trialOpt2 = null, string trialOpt3 = null)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
_userInfo = userInfo;
|
||||||
|
//_trialOpt = trialOpt;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(trialOpt)) _trialOptList.Add(trialOpt.Trim());
|
||||||
|
if (!string.IsNullOrWhiteSpace(trialOpt2)) _trialOptList.Add(trialOpt2.Trim());
|
||||||
|
if (!string.IsNullOrWhiteSpace(trialOpt3)) _trialOptList.Add(trialOpt3.Trim());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//public TrialResourceFilter(IEasyCachingProvider provider, IUserInfo userInfo)
|
||||||
|
//{
|
||||||
|
// _provider = provider;
|
||||||
|
// _userInfo = userInfo;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//优先选择异步的方法
|
||||||
|
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
|
||||||
|
{
|
||||||
|
// var typeFilter = context.ActionDescriptor.EndpointMetadata.Where(t => t.GetType() == typeof(TypeFilterAttribute)).Select(t => (TypeFilterAttribute)t).ToList().FirstOrDefault();
|
||||||
|
//var _trialOptList= typeFilter.Arguments.Select(t => t.ToString()).ToList();
|
||||||
|
|
||||||
|
#region 处理新的用户类型,不能操作项目相关接口
|
||||||
|
|
||||||
|
// 后期列举出具体的类型,其他任何用户类型,都不允许操作
|
||||||
|
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA)
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("对不起,您的账户没有操作权限。"));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//TrialId 传递的途径多种,可能在path 可能在body 可能在数组中,也可能在对象中,可能就在url
|
||||||
|
var trialIdStr = string.Empty;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(context.HttpContext.Request.Query["trialId"]))
|
||||||
|
{
|
||||||
|
trialIdStr = context.HttpContext.Request.Query["trialId"];
|
||||||
|
}
|
||||||
|
|
||||||
|
//先尝试从path中取TrialId
|
||||||
|
else if (context.RouteData.Values.Keys.Any(t => t.Contains("trialId")))
|
||||||
|
{
|
||||||
|
var index = context.RouteData.Values.Keys.ToList().IndexOf("trialId");
|
||||||
|
trialIdStr = context.RouteData.Values.Values.ToList()[index] as string;
|
||||||
|
}
|
||||||
|
else if (context.HttpContext.Request.Headers["RefererUrl"].ToString().Contains("trialId"))
|
||||||
|
{
|
||||||
|
var headerStr = context.HttpContext.Request.Headers["RefererUrl"].ToString();
|
||||||
|
|
||||||
|
var trialIdIndex = headerStr.IndexOf("trialId");
|
||||||
|
|
||||||
|
|
||||||
|
var matchResult = Regex.Match(headerStr.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
|
||||||
|
|
||||||
|
if (matchResult.Success)
|
||||||
|
{
|
||||||
|
trialIdStr = matchResult.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("正则取请求Refer 中trialId 失败,请联系开发人员核查"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#region body 中取数据
|
||||||
|
|
||||||
|
//设置可以多次读
|
||||||
|
context.HttpContext.Request.EnableBuffering();
|
||||||
|
var reader = new StreamReader(context.HttpContext.Request.Body);
|
||||||
|
var contentFromBody = await reader.ReadToEndAsync();
|
||||||
|
//读取后,流的位置还原
|
||||||
|
context.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);
|
||||||
|
//context.HttpContext.Request.Body.Position = 0;
|
||||||
|
|
||||||
|
//找到参数位置在字符串中的索引
|
||||||
|
var trialIdIndex = contentFromBody.IndexOf("\"TrialId\"", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (trialIdIndex > -1)
|
||||||
|
{
|
||||||
|
// (?<="trialId" *: *").*?(?=",)
|
||||||
|
|
||||||
|
//使用正则 [0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}
|
||||||
|
|
||||||
|
var matchResult = Regex.Match(contentFromBody.Substring(trialIdIndex), @"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
|
||||||
|
|
||||||
|
if (matchResult.Success)
|
||||||
|
{
|
||||||
|
//有可能匹配错误 "trialId":"","documentId":"b8180000-3e2c-0016-9fe0-08da33f96236" 从缓存里面验证下
|
||||||
|
var cacheResultDic = _provider.GetAll<string>(new[] { matchResult.Value });
|
||||||
|
|
||||||
|
var trialStatusStr = cacheResultDic[matchResult.Value].Value;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(trialStatusStr))
|
||||||
|
{
|
||||||
|
trialIdStr = matchResult.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("正则取请求Refer 中trialId 失败,请联系开发人员核查"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//使用字符串取 如果是swagger 可能有时取的不对 因为空格的原因
|
||||||
|
//trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 3
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过path 或者body 找到trialId 了
|
||||||
|
if ( !string.IsNullOrWhiteSpace(trialIdStr))
|
||||||
|
{
|
||||||
|
|
||||||
|
//如果没缓存数据,可能定时任务没执行或者缓存丢失 在此重新缓存
|
||||||
|
if (_provider.GetCount() == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
var _trialRepository = context.HttpContext.RequestServices.GetService(typeof(IRepository<Trial>)) as IRepository<Trial>;
|
||||||
|
|
||||||
|
var list = _trialRepository.IfNullThrowException().Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var cacheResultDic = _provider.GetAll<string>(new[] { trialIdStr });
|
||||||
|
|
||||||
|
var trialStatusStr = cacheResultDic[trialIdStr].Value;
|
||||||
|
|
||||||
|
//意外 导致缓存过期,调整服务器时间,测试不想重启程序
|
||||||
|
if (string.IsNullOrWhiteSpace(trialStatusStr))
|
||||||
|
{
|
||||||
|
var trialRepository = context.HttpContext.RequestServices.GetService(typeof(IRepository<Trial>)) as IRepository<Trial>;
|
||||||
|
trialStatusStr = trialRepository?.Where(t => t.Id == Guid.Parse(trialIdStr)).Select(t => t.TrialStatusStr).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这里是统一拦截 项目有关的操作允许情况(特殊的地方,比如项目配置(有的在多种状态(初始化,ongoing)都可以操作,有的仅仅在Initializing)还有 项目添加和更新,不走这里,特殊处理,不然在这里显得很乱,判断是哪个接口)
|
||||||
|
if (trialStatusStr == StaticData.TrialState.TrialOngoing || _trialOptList.Any(t=>t== TrialOpt.BeforeOngoingCantOpt) )
|
||||||
|
{
|
||||||
|
|
||||||
|
await next.Invoke();
|
||||||
|
|
||||||
|
}
|
||||||
|
// 项目停止、或者完成 不允许操作
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("本次请求被配置规则拦截:项目状态处于进行中状态时,才允许操作。"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//添加项目 签名系统文档的时候 不做拦截 但是更新项目 签名项目文档的时候需要拦截
|
||||||
|
else if (_trialOptList.Any(t => t == TrialOpt.AddOrUpdateTrial ||t ==TrialOpt.SignSystemDocNoTrialId))
|
||||||
|
{
|
||||||
|
await next.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//如果项目相关接口没有传递trialId 会来到这里,提醒,以便修改
|
||||||
|
|
||||||
|
context.Result = new JsonResult(ResponseOutput.NotOk("该接口参数中,没有传递项目编号,请核对。"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue