添加项目文件。

This commit is contained in:
DK
2022-03-28 15:27:40 +08:00
parent b620fcb0cf
commit dc78fd1a09
898 changed files with 173053 additions and 0 deletions
@@ -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;
}
}
}
+499
View File
@@ -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 = $"CRC : {_userInfo.RealName} has uploaded {study.StudyCode} ",
// SendTime = DateTime.Now,
// });
// }
// #region 处理QA通知模块
// //查询项目的参与者 和 负责site下CRC用户
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
// // 找到该study 关联Site 下的CRC
// 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);
// // CRC =>QA
// if (studyStatus.Status == (int)StudyStatus.QARequested)
// {
// //找出当前操作的CRC
// //PM 或者admin可以代替CRC角色 不能从CRC列表中查询用户
// //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 =
// $"CRC -> 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 =>CRC 向CRC推送消息影像有问题 同时作为 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);
// //在项目CRC列表中筛选出 负责该study关联 site的CRC
// var siteCRCList = _userTrialSiteRepository.Where(t =>
// t.SiteId == study.SiteId && t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && t.TrialId == study.TrialId).ToList();
// //查询项目的参与者 和 负责site下CRC用户
// 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 -> CRC : {_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
// }));
// //添加 发送给CRC的消息 消息和CRC是 一对多
// _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} finishedAnonymization 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发给CRC的 但是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 =>CRC 暂时不用发送消息给CRC 因为CRC 暂时没有入口回复 同时作为 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;
// //处理CRC 重传时 QA消息
// if (status == (int)StudyStatus.QAing)
// {
// //查询项目的参与者 和 负责site下CRC用户
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
// // 找到该study 关联Site 下的CRC
// 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();
// //CRC =>QA CRC的职能被PM 或者admin代替
// //if (_userInfo.UserTypeEnumInt == (int)UserType.ClinicalResearchCoordinator)
// {
// //PM 或者admin可以代替CRC角色 不能从CRC列表中查询用户
// //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 = $"CRC -> 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和CRC对话的
// 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下CRC用户
// var trialUserList = _userTrialRepository.Where(t => t.TrialId == study.TrialId).ToList();
// // 找到该study 关联Site 下的CRC
// 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.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();
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using Castle.DynamicProxy;
using IRaCIS.Application.Services;
using IRaCIS.Application.Contracts;
using Microsoft.Extensions.Logging;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.API.Utility.AOP
{
/// <summary>
///服务动态生成api AOP 此时会失效
/// </summary>
public class UserAddAOP : IInterceptor
{
private readonly IMailVerificationService _mailVerificationService;
private readonly ILogger<UserAddAOP> _logger;
public UserAddAOP(IMailVerificationService mailVerificationService, ILogger<UserAddAOP> logger)
{
_mailVerificationService = mailVerificationService;
_logger = logger;
}
public void Intercept(IInvocation invocation)
{
var userInfo = (invocation.Arguments[0] as UserCommand).IfNullThrowConvertException();
//处理拦截的方法
invocation.Proceed();
//在此 发送邮件
dynamic result = invocation.ReturnValue;
if (result.IsSuccess)
{
var userId = result.Data.Id;
var verificationCode = result.Data.VerificationCode;
_logger.LogInformation($"Sent to {userInfo.UserName} email {userInfo.EMail} init password {verificationCode}");
_mailVerificationService.SendMail(userId, userInfo.UserName, userInfo.EMail, verificationCode).GetAwaiter().GetResult();
}
}
}
}
@@ -0,0 +1,50 @@
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 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,
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,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,59 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.AuthUser;
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)
};
////创建令牌
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,46 @@
using EasyCaching.Core;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Application.Services.BackGroundJob
{
public interface ICacheTrialStatusJob
{
Task MemoryCacheTrialStatus();
}
public class CacheTrialStatusHangfireJob: ICacheTrialStatusJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<CacheTrialStatusHangfireJob> _logger;
public CacheTrialStatusHangfireJob(IRepository<Trial> trialRepository, IEasyCachingProvider provider,ILogger<CacheTrialStatusHangfireJob> logger)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
}
public Task MemoryCacheTrialStatus()
{
_logger.LogInformation("hangfire 定时任务开始~");
try
{
var list = _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToList();
//_provider.GetCount("");
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
catch (Exception e)
{
_logger.LogError("hangfire 定时任务执行失败"+e.Message);
}
_logger.LogInformation("hangfire 定时任务执行结束");
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,53 @@
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;
namespace IRaCIS.Application.Services.BackGroundJob
{
public class CacheTrialStatusQuartZJob: IJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<CacheTrialStatusQuartZJob> _logger;
public CacheTrialStatusQuartZJob(IRepository<Trial> trialRepository, IEasyCachingProvider provider,ILogger<CacheTrialStatusQuartZJob> logger)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation($"开始执行QuartZ定时任务作业");
try
{
var list = _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToList();
//_provider.GetCount("");
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(1)));
}
catch (Exception e)
{
_logger.LogError($" 查询和缓存过程出现异常"+e.Message);
}
_logger.LogInformation("QuartZ定时任务作业结束");
return Task.CompletedTask;
}
}
}
@@ -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);
}
}
}
}
+109
View File
@@ -0,0 +1,109 @@
using AutoMapper;
using IRaCIS.Application.Services.BusinessFilter;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Panda.DynamicWebApi;
using Panda.DynamicWebApi.Attributes;
using System.Diagnostics.CodeAnalysis;
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 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; }
}
#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,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("The inputs supplied to the API are invalid. " +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 @@
namespace System.ComponentModel.DataAnnotations
{
[AttributeUsage(
AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
AllowMultiple = false)]
public class GuidNotEmptyAttribute : ValidationAttribute
{
public const string DefaultErrorMessage = "The {0} field must not be empty";
public GuidNotEmptyAttribute() : base(DefaultErrorMessage) { }
public override bool IsValid(object? value)
{
//NotEmpty doesn't necessarily mean required
if (value is null)
{
return true;
}
switch (value)
{
case Guid guid:
return guid != Guid.Empty;
default:
return true;
}
}
}
public class NotDefaultAttribute : ValidationAttribute
{
public const string DefaultErrorMessage = "The {0} field is is not passed or not set a valid value";
public NotDefaultAttribute() : base(DefaultErrorMessage) { }
public override bool IsValid(object? value)
{
//NotDefault doesn't necessarily mean required
if (value is null)
{
return true;
}
var type = value.GetType();
if (type.IsValueType)
{
var defaultValue = Activator.CreateInstance(type);
return !value.Equals(defaultValue);
}
// non-null ref type
return true;
}
}
}
@@ -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.Result = new JsonResult(ResponseOutput.NotOk("Verify error: " + context.Exception.Message));
}
else if(context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
{
context.Result = new JsonResult(ResponseOutput.NotOk( context.Exception.Message));
}
else
{
context.Result = new JsonResult(ResponseOutput.NotOk(" Program exception, please contact the developer! " + (context.Exception.InnerException is null? context.Exception.Message:context.Exception.InnerException?.Message) ));
}
_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,152 @@
using EasyCaching.Core;
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;
using Microsoft.AspNetCore.Mvc.Filters;
namespace IRaCIS.Core.Application.Filter
{
/// <summary>
/// 主要为了 处理项目结束 锁库,不允许操作
/// </summary>
public class TrialResourceFilter : Attribute, IAsyncResourceFilter /* , IResourceFilter*/
{
private readonly IEasyCachingProvider _provider;
private readonly IUserInfo _userInfo;
public TrialResourceFilter(IEasyCachingProvider provider, IUserInfo userInfo)
{
_provider = provider;
_userInfo = userInfo;
}
//优先选择异步的方法
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
#region
if( _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA)
{
context.Result = new JsonResult(ResponseOutput.NotOk("Sorry,Your UserType does not allow this operation"));
return ;
}
#endregion
//bool isEditTrialStatus = context.ActionDescriptor.DisplayName==null? false:context.ActionDescriptor.DisplayName.Contains("UpdateTrialStatus");
//bool isTrialAdd = context.ActionDescriptor.DisplayName == null ? false: context.ActionDescriptor.DisplayName.Contains("AddOrUpdateTrial");
//TrialId 传递的途径多种,可能在path 可能在body 可能在数组中,也可能在对象中,可能就在url
var trialIdStr = string.Empty;
//先尝试从path中取TrialId
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
{
#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)
{
trialIdStr = contentFromBody.Substring(trialIdIndex + "TrialId".Length + 4, 36);
}
//else if(isTrialAdd)
//{
// //项目的添加和编辑时例外 trailId 在Id字段中 同时,添加和更新时有区别的
// trialIdIndex = contentFromBody.IndexOf("\"Id\"");
// //添加时为-1 不进行操作
// if (trialIdIndex != -1)
// {
// trialIdStr = contentFromBody.Substring(trialIdIndex + "Id".Length + 4, 36);
// trialIdStr = Guid.TryParse(trialIdStr, out var trialId) ? trialId.ToString() : String.Empty ;
// }
//}
#endregion
}
//通过path 或者body 找到trialId 了
if (trialIdStr != string.Empty)
{
//如果没缓存数据,是不允许的 意外情况,IIS回收了,导致定时任务没执行或者缓存丢失
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];
//项目完成和停止,都不能操作
if (trialStatusStr.Value == StaticData.TrialCompleted || trialStatusStr.Value == StaticData.TrialStopped)
{
context.Result = new JsonResult(ResponseOutput.NotOk("Only trial in ongoing state can the operation be performed"));
}
//仅仅管理员 在项目暂停 并且是编辑项目接口时 才放开操作 遗漏了正常情况 TrialOngoing
if (/*(trialStatusStr.Value == StaticData.TrialPaused && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SuperAdmin && isEditTrialStatus)||*/ trialStatusStr.Value == StaticData.TrialOngoing)
{
await next.Invoke();
}
//项目暂停的基础上,是其他人,或者不是编辑项目状态,那么要禁止操作
else
{
context.Result = new JsonResult(ResponseOutput.NotOk("Only trial in ongoing state can the operation be performed"));
}
}
////没有找到trialId 判断是否是项目添加
//else if (isTrialAdd)
//{
// await next.Invoke();
//}
else
{
//如果项目相关接口没有传递trialId 会来到这里,提醒,以便修改
context.Result = new JsonResult(ResponseOutput.NotOk("该接口参数中,没有传递trialId,请核查"));
}
}
}
}
@@ -0,0 +1,120 @@
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Application.Services.BusinessFilter
{
/// <summary>
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
/// by zhouhang 2021.09.12 周末
/// </summary>
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
{
/// <summary>
/// 异步版本
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is ObjectResult objectResult)
{
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
//是200 并且没有包装 那么包装结果
if (statusCode == 200 && !(objectResult.Value is IResponseOutput))
{
//if (objectResult.Value == null)
//{
// var apiResponse = ResponseOutput.DBNotExist();
// objectResult.Value = apiResponse;
// objectResult.DeclaredType = apiResponse.GetType();
//}
//else
//{
var type = objectResult.Value?.GetType();
if ( type!=null&& type.IsGenericType&&(type.GetGenericTypeDefinition()==typeof(ValueTuple<,>)|| type.GetGenericTypeDefinition()==typeof(Tuple<,>)))
{
//报错
//var tuple = (object, object))objectResult.Value;
//var (val1, val2) = ((dynamic, dynamic))objectResult.Value;
//var apiResponse = ResponseOutput.Ok(val1, val2);
//OK
var tuple = (dynamic)objectResult.Value;
var apiResponse = ResponseOutput.Ok(tuple.Item1, tuple.Item2);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
else
{
var apiResponse = ResponseOutput.Ok(objectResult.Value);
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
//}
}
//如果不是200 是IResponseOutput 不处理
else if (statusCode != 200 && (objectResult.Value is IResponseOutput))
{
}
else if(statusCode != 200&&!(objectResult.Value is IResponseOutput))
{
var apiResponse = ResponseOutput.NotOk("Program error, contact the developer!");
objectResult.Value = apiResponse;
objectResult.DeclaredType = apiResponse.GetType();
}
}
await next.Invoke();
}
public static bool IsTupleType(Type type, bool checkBaseTypes = false)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type == typeof(Tuple))
return true;
while (type != null)
{
if (type.IsGenericType)
{
var genType = type.GetGenericTypeDefinition();
if (genType == typeof(Tuple<>)
|| genType == typeof(Tuple<,>)
|| genType == typeof(Tuple<,>))
return true;
}
if (!checkBaseTypes)
break;
type = type.BaseType;
}
return false;
}
}
}
@@ -0,0 +1,46 @@
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.Application.BusinessFilter
{
//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,98 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>default</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\bin\</OutputPath>
<DocumentationFile>.\IRaCIS.Core.Application.xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1591;1587</NoWarn>
</PropertyGroup>
<ItemGroup>
<Using Include="IRaCIS.Core.Application;" />
<Using Include="AutoMapper.QueryableExtensions;" />
<Using Include="Microsoft.EntityFrameworkCore;" />
<Using Include="IRaCIS.Core.Domain.Models;" />
<Using Include="IRaCIS.Core.Infrastructure.Extention;" />
<!-- Global using -->
</ItemGroup>
<ItemGroup>
<Compile Remove="WebAppConfig.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="IRaCIS.Core.Application.xml" />
<None Remove="Resources\en-US.json" />
<None Remove="Resources\zh-CN.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\zh-CN.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="Resources\en-US.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.0.0" />
<PackageReference Include="EasyCaching.Interceptor.AspectCore" Version="1.4.1" />
<PackageReference Include="Efferent.Native" Version="4.1.0" />
<PackageReference Include="ExcelDataReader" Version="3.6.0" />
<PackageReference Include="ExcelDataReader.DataSet" Version="3.6.0" />
<PackageReference Include="fo-dicom.Codecs" Version="5.0.3" />
<PackageReference Include="fo-dicom.Drawing" Version="4.0.8" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.0.2" />
<PackageReference Include="Hangfire" Version="1.7.28" />
<PackageReference Include="Magicodes.IE.Core" Version="2.6.1" />
<PackageReference Include="Magicodes.IE.Excel" Version="2.6.1" />
<PackageReference Include="Magicodes.IE.Excel.AspNetCore" Version="2.6.1" />
<PackageReference Include="MailKit" Version="3.1.0" />
<PackageReference Include="MediatR" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.1" />
<PackageReference Include="MimeKit" Version="3.1.0" />
<PackageReference Include="MiniExcel" Version="0.19.1" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.1.2" />
<PackageReference Include="Quartz" Version="3.3.3" />
<PackageReference Include="SharpCompress" Version="0.30.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.15.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.15" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="WinSCP" Version="5.19.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
</ItemGroup>
</Project>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
{
"test{0}": "英文本地化{0}",
"RequiredAttribute": "{0} is required",
// SiteSurvey 服务--------------------------------------------------------------------------------------------------------------------------
// TrialSiteEquipmentSurveyService
"CPMNotOperation": "CPM/APM Disallow operation", //CPM/APM 不允许操作
"IsLockNotOperation": "The operation cannot be performed if it is locked", //已锁定 不允许操作
// TrialSiteSurveyService
"ValidationEmail": "Please input a legal email", // 验证邮箱
"ValidationPhone": "Please input a legal phone", // 验证手机号
"SiteNotExistUpdateDisable": "The project Site does not have the survey record of the handover person, so it is not allowed to choose to update", // site不存在禁止更新
"RecordLockUpdateDisable": "Your record is not locked, you are not allowed to choose to update, if submitted, can be rejected after operation", //记录锁定禁止更新
"SiteLockUpdateDisableOther": "At the current Site, your survey record has been locked, and it is not allowed to update other people's email survey record", //Site锁定禁止更新其他人
"SiteLockUpdateDisableSelf": "At the current Site, your survey record has been locked, and there are other unlocked records, so you are not allowed to update your own survey record", //Site锁定禁止更新自己
"SiteLockUpdateDisableEmail": "当前Site 存在未锁定的调研记录,不允许更新已锁定邮箱的调研记录", //Site锁定禁止更新邮箱调研记录
"EmailNotLatestDisableEmail{0}": "该邮箱{0}对应的调查表不是最新锁定的记录,不允许更新!", //邮箱调研表不是最新 不允许更新
"SiteExistOtherUpdateDisable": "该Site下已经有其他用户已填写的调研表,您不被允许继续填写", //存在其他用户调研表不允许填写
"IsLockUpdateDisable": "已锁定,不允许操作", //已锁定,不允许操作
"OnlyAbolishNotFiled": "只允许废除未提交的记录", //只允许废除未提交的记录
"AdminOperateDisable": "不允许Admin操作", // 不允许Admin操作
"UserWrongNotSubmit": "人员信息有不正确项,不允许提交", // 人员信息有不正确项,不允许提交
"FillInTheType": "请填写生成账号的类型。人员姓名{0}", // 请填写生成账号的类型。人员姓名
// TrialSiteUserSurveyService
"InfoInconformity": "该用户在系统中账户名为:{0} ,与填写信息存在不一致项, 现将界面信息修改为与系统一致,可进行保存", // 信息不一致 修改一致进行保存
// TrialSiteUser 服务------------------------------------------------------------------------------------------------------------
// TrialConfigService
"NoDataDound": "未在系统中找到该签名场景的数据", //未在系统中找到该签名场景的数据
"PasswordError": "password error", //密码错误
"UserBeDisabled": "The user has been disabled!",
"ProjSetDisable": "项目不在Initializing/Ongoing,不允许确认配置", //不允许确认配置
"QCRepate": "QC问题显示序号不允许重复", // QC问题显示序号不允许重复
"ParentNumToLow": "父问题的序号要比子问题序号小,请确认", // 父问题的序号要比子问题序号小,请确认
"ExistUnconfirmedItems": "项目、基础配置、流程配置、加急配置、访视计划,有未确认项", // 存在未确认项
"NotAllCanOperate": "only in Initializing or Ongoing State can operate" //只有“初始化中”和“正在进行中”才能进行操作
}
@@ -0,0 +1,45 @@
{
"test{0}": "中文本地化{0}",
"RequiredAttribute": "{0} 字段是必须的",
// SiteSurvey 服务--------------------------------------------------------------------------------------------------------------------------
// TrialSiteEquipmentSurveyService
"CPMNotOperation": "CPM/APM 不允许操作", //CPM/APM 不允许操作
"IsLockNotOperation": "已锁定 不允许操作", //已锁定 不允许操作
// TrialSiteSurveyService
"ValidationEmail": "请输入正确的邮箱", // 验证邮箱
"ValidationPhone": "请输入正确的手机号", // 验证手机号
"SiteNotExistUpdateDisable": "该项目Site不存在该交接人的调研记录,不允许选择更新", // site不存在禁止更新
"RecordLockUpdateDisable": "您的记录未锁定,不允许选择更新,若已经提交,可被驳回后进行操作", //记录锁定禁止更新
"SiteLockUpdateDisableOther": "当前Site 您的调研记录已锁定,不允许更新其他人邮箱调研记录", //Site锁定禁止更新其他人
"SiteLockUpdateDisableSelf": "当前Site 您的调研记录已锁定,也存在其他未锁定的记录,不允许更新自己的调研记录", //Site锁定禁止更新自己
"SiteLockUpdateDisableEmail": "当前Site 存在未锁定的调研记录,不允许更新已锁定邮箱的调研记录", //Site锁定禁止更新邮箱调研记录
"EmailNotLatestDisableEmail{0}": "该邮箱{0}对应的调查表不是最新锁定的记录,不允许更新!", //邮箱调研表不是最新 不允许更新
"SiteExistOtherUpdateDisable": "该Site下已经有其他用户已填写的调研表,您不被允许继续填写", //存在其他用户调研表不允许填写
"IsLockUpdateDisable": "已锁定,不允许操作", //已锁定,不允许操作
"OnlyAbolishNotFiled": "只允许废除未提交的记录", //只允许废除未提交的记录
"AdminOperateDisable": "不允许Admin操作", // 不允许Admin操作
"UserWrongNotSubmit": "人员信息有不正确项,不允许提交", // 人员信息有不正确项,不允许提交
"FillInTheType{0}": "请填写生成账号的类型。人员姓名{0}", // 请填写生成账号的类型。人员姓名
// TrialSiteUserSurveyService
"InfoInconformity{0}": "该用户在系统中账户名为:{0} ,与填写信息存在不一致项, 现将界面信息修改为与系统一致,可进行保存", // 信息不一致 修改一致进行保存
// TrialSiteUser 服务------------------------------------------------------------------------------------------------------------
// TrialConfigService
"NoDataDound": "未在系统中找到该签名场景的数据", //未在系统中找到该签名场景的数据
"PasswordError": "密码错误", //密码错误
"UserBeDisabled": "用户被禁用", // 用户被禁用
"ProjSetDisable": "项目不在Initializing/Ongoing,不允许确认配置", //不允许确认配置
"QCRepate": "QC问题显示序号不允许重复", // QC问题显示序号不允许重复
"ParentNumToLow": "父问题的序号要比子问题序号小,请确认", // 父问题的序号要比子问题序号小,请确认
"ExistUnconfirmedItems": "项目、基础配置、流程配置、加急配置、访视计划,有未确认项", // 存在未确认项
"NotAllCanOperate": "只有“初始化中”和“正在进行中”才能进行操作", //只有“初始化中”和“正在进行中”才能进行操作
// TrialExternalUserService
"InfoDoNotAgree{0}{1}": "该用户在系统中账户名为:{0} 电话:{1},与填写信息存在不一致项, 现将界面信息修改为与系统一致,可进行保存" // 用户信息不一致
"UserExist"
}
@@ -0,0 +1,155 @@
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts
{
public class BasicDicView: AddOrEditBasicDic
{
public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
public string ConfigType { get; set; }
public string ConfigTypeDes { get; set; }
}
public class AddOrEditBasicDic
{
public Guid? Id { get; set; }
public string Code { get; set; } = String.Empty;
public string KeyName { get; set; } = String.Empty;
public string Description { get; set; } = String.Empty;
public string Value { get; set; } = String.Empty;
public string ValueCN { get; set; } = String.Empty;
public int ShowOrder { get; set; }
//有父亲 就有值
public Guid? ParentId { get; set; }
public bool IsEnable { get; set; }
//默认不是字典项 类型配置
public bool IsConfig { get; set; }
//是配置的话,就有值
public Guid? ConfigTypeId { get; set; }
}
public class BasicDicSelect
{
public Guid Id { get; set; }
public string KeyName { get; set; } = string.Empty;
public string ValueCN { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty;
public int ShowOrder { get; set; }
public Guid? ParentId { get; set; }
public string ParentCode { get; set; } = string.Empty;
}
public class BasicDicQuery:PageInput
{
public string? Code { get; set; }
public string? KeyName { get; set; }
public bool? IsConfig { get; set; }
public Guid? ConfigTypeId { get; set; }
}
public class DicViewModelDTO : AddOrUpdateDicDTO
{
}
public class AddOrUpdateDicDTO
{
public Guid? Id { get; set; }
public string KeyName { get; set; } = String.Empty;
public string Value { get; set; } = String.Empty;
public string Description { get; set; } = String.Empty;
public string ValueCN { get; set; } = String.Empty;
public int ShowOrder { get; set; }
public string Type { get; set; } = String.Empty;
}
public class DicQueryDTO : PageInput
{
public string KeyName { get; set; } = String.Empty;
}
public class KeyNameType
{
public Guid KeyId { get; set; }
public string KeyName { get; set; } = String.Empty;
public string Type { get; set; } = String.Empty;
}
public class DicResultDTO
{
public Dictionary<string, Dictionary<Guid, string>> DicList = new Dictionary<string, Dictionary<Guid, string>>();
}
public class TrialDictionaryView
{
public Guid? Id { get; set; }
public string KeyName { get; set; } = String.Empty;
public string Value { get; set; } = String.Empty;
public int ShowOrder { get; set; }
}
public class TrialDicSelect
{
public TrialDictionaryView[] Phase { get; set; } = new TrialDictionaryView[0];
public TrialDictionaryView[] IndicationType { get; set; } = new TrialDictionaryView[0];
public TrialDictionaryView[] DeclarationType { get; set; } = new TrialDictionaryView[0];
}
}
@@ -0,0 +1,64 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 11:55:57
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using Newtonsoft.Json;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> EmailNoticeConfigView 列表视图模型 </summary>
public class EmailNoticeConfigView : EmailNoticeConfigAddOrEdit
{
public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; }
public Guid UpdateUserId { get; set; }
public DateTime UpdateTime { get; set; }
[JsonIgnore]
public SystemBasicDataSelect Scenario { get; set; }
//public Guid? ScenarioParentId => Scenario.ParentId;
public string ScenarioName => Scenario.Value;
public string ScenarioNameCN => Scenario.ValueCN;
}
///<summary>EmailNoticeConfigQuery 列表查询参数模型</summary>
public class EmailNoticeConfigQuery:PageInput
{
public Guid? ScenarioId { get; set; }
public bool? IsReturnRequired { get; set; }
public bool? IsUrgent { get; set; }
public bool? IsEnable { get; set; }
}
///<summary> EmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
public class EmailNoticeConfigAddOrEdit
{
public Guid Id { get; set; }
public string Code { get; set; } = String.Empty;
public string AuthorizationCode { get; set; } = String.Empty;
public Guid ScenarioId { get; set; }
public string Title { get; set; } = String.Empty;
public string Body { get; set; } = String.Empty;
public string FromEmail { get; set; } = String.Empty;
public string ReceiveEmail { get; set; } = String.Empty;
public string CopyEmail { get; set; } = String.Empty;
public bool IsReturnRequired { get; set; }
public bool IsUrgent { get; set; }
public bool IsEnable { get; set; }
public bool IsAutoSend { get; set; }
}
}
@@ -0,0 +1,18 @@
namespace IRaCIS.Application.Contracts
{
public class UploadFileInfoDTO
{
public Guid Id { get; set; }
public string FilePath { get; set; } = string.Empty;
//[JsonIgnore]
//public string FullFilePathNoToken => FilePath;
public string FullFilePath { get; set; } = string.Empty;
}
}
@@ -0,0 +1,16 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class SysMessageDTO
{
public int Id { get; set; }
public int ToDoctorId { get; set; }
public int FromUserId { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string MessageTime { get; set; } = string.Empty;
public bool HasRead { get; set; }
public string Memo { get; set; } = string.Empty;
}
}
@@ -0,0 +1,67 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 15:46:00
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> SystemBasicDataView 列表视图模型 </summary>
public class SystemBasicDataView: SystemBasicDataAddOrEdit
{
public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
}
public class SystemBasicDataSelect
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string ValueCN { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Code { get; set; } = string.Empty;
public Guid? ParentId { get; set; }
public string ParentCode { get; set; } = string.Empty;
}
///<summary>SystemBasicDataQuery 列表查询参数模型</summary>
public class SystemBasicDataQuery:PageInput
{
///<summary> Name</summary>
public string? Name { get; set; }
///<summary> Code</summary>
public string? Code { get; set; }
}
///<summary> SystemBasicDataAddOrEdit 列表查询参数模型</summary>
public class SystemBasicDataAddOrEdit
{
public Guid? Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public int ShowOrder { get; set; }
public string Code { get; set; } = string.Empty;
public Guid? ParentId { get; set; }
public string ValueCN { get; set; } = string.Empty;
public bool IsEnable { get; set; }=true;
}
}
@@ -0,0 +1,99 @@
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts
{
public class SystemLogDTO
{
public Guid Id { get; set; }
public string ApiPath { get; set; } = string.Empty;
public string Params { get; set; } = string.Empty;
public string Result { get; set; } = string.Empty;
public DateTime RequestTime { get; set; } = DateTime.Now;
public long ElapsedMilliseconds { get; set; } = 0;
public Guid OptUserId { get; set; } = Guid.Empty;
public string OptUserName { get; set; } = string.Empty;
public string ClientIP { get; set; } = string.Empty;
public bool Status { get; set; } = true;
public string Message { get; set; } = string.Empty;
public string LogCategory { get; set; } = string.Empty;
}
public class QueryLogQueryDTO : PageInput
{
public string Keyword { get; set; } = string.Empty;
public string LogCategory { get; set; } = string.Empty;
public DateTime? BeginTime { get; set; }
public DateTime? EndTime { get; set; }
}
public class AuditQueryDTO : PageInput
{
public Guid TrialId { get; set; }
public Guid? StudyId { get; set; }
public Guid? SubjectId { get; set; }
public int? AuditType { get; set; }
public string SubjectInfo { get; set; } = string.Empty;
public Guid? OptUserId { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
public class AuditDTO
{
public Guid Id { get; set; }
public int AuditType { get; set; }
public Guid TrialId { get; set; }
public Guid StudyId { get; set; }
public Guid? SubjectId { get; set; }
public string SubjectName { get; set; } = string.Empty;
public string SubjectCode { get; set; } = string.Empty;
public Guid OptUserId { get; set; }
public string OptUser { get; set; } = string.Empty;
public DateTime OptTime { get; set; } = DateTime.Now;
public string Note { get; set; } = string.Empty;
public string Detail { get; set; } = string.Empty;
public string TrialCode { get; set; } = string.Empty;
public string TrialIndication { get; set; } = string.Empty;
}
public class OptUserDto
{
public Guid OptUserId { get; set; }
public string OptUser { get; set; } = string.Empty;
}
public class AuditSubjectSelectDto
{
public Guid? SubjectId { get; set; }
public string SubjectCode { get; set; } = string.Empty;
public string SubjectName { get; set; } = string.Empty;
}
}
@@ -0,0 +1,311 @@
using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
/// <summary>
/// 数据字典-基础数据维护
/// </summary>
[ApiExplorerSettings(GroupName = "Common")]
public class DictionaryService : BaseService, IDictionaryService
{
private readonly IRepository<Dictionary> _dicRepository;
private readonly IRepository<DoctorDictionary> _doctorDictionaryRepository;
private readonly IRepository<TrialDictionary> _trialDictionaryRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<Trial> _trialRepository;
public DictionaryService(IRepository<Dictionary> sysDicRepository, IRepository<DoctorDictionary> doctorDictionaryRepository, IRepository<TrialDictionary> trialDictionaryRepository,
IRepository<Doctor> doctorRepository, IRepository<Trial> trialRepository)
{
_dicRepository = sysDicRepository;
_doctorDictionaryRepository = doctorDictionaryRepository;
_trialDictionaryRepository = trialDictionaryRepository;
_doctorRepository = doctorRepository;
_trialRepository = trialRepository;
}
/// <summary>
/// New 查询条件 IsConfig 代表是字典类型配置项 否就是我们普通的项 和普通项的子项
/// </summary>
/// <param name="basicDicQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<BasicDicView>> GetBasicDicList(BasicDicQuery basicDicQuery)
{
var systemBasicDataQueryable = _repository.GetQueryable<Dictionary>().Where(t => t.ParentId == null)
.WhereIf(!string.IsNullOrEmpty(basicDicQuery.Code), t => t.Code.Contains(basicDicQuery.Code!))
.WhereIf(!string.IsNullOrEmpty(basicDicQuery.KeyName), t => t.KeyName.Contains(basicDicQuery.KeyName!))
.WhereIf(basicDicQuery.ConfigTypeId != null, t => t.ConfigTypeId == basicDicQuery.ConfigTypeId!)
.WhereIf(basicDicQuery.IsConfig != null, t => t.IsConfig == basicDicQuery.IsConfig)
.ProjectTo<BasicDicView>(_mapper.ConfigurationProvider);
return await systemBasicDataQueryable.ToPagedListAsync(basicDicQuery.PageIndex, basicDicQuery.PageSize, String.IsNullOrEmpty(basicDicQuery.SortField) ? "Code" : basicDicQuery.SortField, basicDicQuery.Asc);
}
/// <summary>
/// New
/// </summary>
/// <param name="addOrEditBasic"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateBasicDic(AddOrEditBasicDic addOrEditBasic)
{
var entity = await _repository.InsertOrUpdateAsync<Dictionary, AddOrEditBasicDic>(addOrEditBasic, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
/// <summary>
/// New
/// </summary>
/// <param name="parentId"></param>
/// <returns></returns>
[HttpGet("{parentId:guid}")]
public async Task<List<BasicDicView>> GetChildList(Guid parentId)
{
return await _repository.GetQueryable<Dictionary>().Where(t => t.ParentId == parentId)
.OrderBy(t => t.ShowOrder).ProjectTo<BasicDicView>(_mapper.ConfigurationProvider).ToListAsync();
}
/// <summary>
/// 传递父亲 code 字符串 数组 返回多个下拉框数据
/// </summary>
/// <param name="searchArray"></param>
/// <returns></returns>
[HttpPost]
public async Task<Dictionary<string, List<BasicDicSelect>>> GetBasicDataSelect(string[] searchArray)
{
var searchList = await _repository.GetQueryable<Dictionary>().Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelect>(_mapper.ConfigurationProvider).ToListAsync();
return searchList.GroupBy(t => t.ParentCode).ToDictionary(g => g.Key, g => g.ToList());
}
public async Task<List<BasicDicSelect>> GetBasicDataSelect(string searchKey)
{
var searchList = await _repository.GetQueryable<Dictionary>().Where(t => t.Parent.Code== searchKey && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelect>(_mapper.ConfigurationProvider).ToListAsync();
return searchList;
}
#region old
/// <summary>
/// 获取项目多选字典
/// </summary>
/// <param name="searchArray">Title、Department、Rank、Position、ReadingType、Subspeciality Sponsor CROCompany ReadingStandard ReviewMode ReviewType ProjectState</param>
/// <returns></returns>
[HttpPost]
public DicResultDTO GetDictionary(string[] searchArray)
{
var doctorViewList = _dicRepository.ProjectTo<DicViewModelDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName)
.ThenBy(t => t.ShowOrder).ToList();
var projectDicResult = new DicResultDTO();
foreach (var searchItem in searchArray)
{
var item = searchItem.Trim();
var tempDic = new Dictionary<Guid, string>();
doctorViewList.Where(o => o.KeyName == item).ToList().ForEach(o => tempDic.Add(o.Id!.Value, o.Value));
projectDicResult.DicList.Add(item, tempDic);
}
return projectDicResult;
}
public DicResultDTO GetAllDictionary()
{
var list = _dicRepository.ProjectTo<DicViewModelDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.KeyName)
.ThenBy(t => t.ShowOrder).ToList();
var types = list.Select(u => u.KeyName).Distinct();
var projectDicResult = new DicResultDTO();
foreach (var type in types)
{
var tempDic = new Dictionary<Guid, string>();
//list.Where(o => o.KeyName == type).ToList().ForEach(o => tempDic.Add(o.Id, string.IsNullOrEmpty(o.ValueCN)?o.Value: o.Value + " / " + o.ValueCN));
list.Where(o => o.KeyName == type).ToList().ForEach(o => tempDic.Add(o.Id!.Value, o.Value));
projectDicResult.DicList.Add(type, tempDic);
}
// //用户类型从字典表 移到另外的表了,现在为了前端不变,在这里获取,给出数据
//var userTypes= _userTypeRoleRepository.GetAll().OrderBy(t => t.Order).Select(t => new {t.Id, t.UserType}).ToList();
//var userTypeDic = new Dictionary<Guid, string>();
//userTypes.ForEach(o => userTypeDic.Add(o.Id, o.UserType));
// projectDicResult.DicList.Add("UserType", userTypeDic);
return projectDicResult;
}
/// <summary> 根据Key,获取单个字典数组 </summary>
[HttpPost]
public PageOutput<DicViewModelDTO> getDictionarySelectList(DicQueryDTO dicSearchModel)
{
var dicQueryable = _dicRepository
.WhereIf(!string.IsNullOrEmpty(dicSearchModel.KeyName), t => t.KeyName == dicSearchModel.KeyName && t.Value != "")
.ProjectTo<DicViewModelDTO>(_mapper.ConfigurationProvider);
var pageList = dicQueryable.ToPagedList(dicSearchModel.PageIndex, dicSearchModel.PageSize, dicSearchModel.SortField, dicSearchModel.Asc);
return pageList;
}
/// <summary> 根据Type、Key 获取字典 树结构 </summary>
public List<DictionaryTreeNode> GetDicTree()
{
var keyNameTypeDistinctList = _dicRepository.Where(t => t.ParentId != null)
.ProjectTo<KeyNameType>(_mapper.ConfigurationProvider).Distinct().ToList();
var treeNodeList = new List<DictionaryTreeNode>();
var group = keyNameTypeDistinctList.GroupBy(t => t.Type);
foreach (var groupItem in group)
{
var node = new DictionaryTreeNode()
{
Id = Guid.NewGuid(),
KeyName = groupItem.Key,
Type = groupItem.Key,
Children = keyNameTypeDistinctList.Where(t => t.Type == groupItem.Key).Select(t =>
new DictionaryTreeNode()
{
Id = Guid.NewGuid(),
KeyName = t.KeyName,
Type = t.Type,
Children = new List<DictionaryTreeNode>()
}).ToList()
};
treeNodeList.Add(node);
}
return treeNodeList;
}
/// <summary> 添加或更新字典数据 </summary>
//[HttpPost]
//public IResponseOutput AddOrUpdateDictionary(AddOrUpdateDicDTO viewModel)
//{
// #region 封装前
// //if (viewModel.Id == null)
// //{
// // var existItem = _dicRepository.FirstOrDefault(dic => dic.KeyName.Equals(viewModel.KeyName) && dic.Value.Equals(viewModel.Value));
// // if (existItem != null)
// // {
// // return ResponseOutput.NotOk("The added item has the same name as a sub-item of current categpry. Please modify the name.");
// // }
// // var result = _dicRepository.Add(_mapper.Map<Dictionary>(viewModel));
// // var success = _dicRepository.SaveChanges();
// // return ResponseOutput.Result(success);
// //}
// //else
// //{
// // var existItem = _dicRepository.FirstOrDefault(dic => dic.KeyName.Equals(viewModel.KeyName) && dic.Value.Equals(viewModel.Value));
// // if (existItem != null && existItem.Id != viewModel.Id)
// // {
// // return ResponseOutput.NotOk("The updated item has the same name as a sub-item of current categpry. Please modify the name.");
// // }
// // var updateItem = _dicRepository.FirstOrDefault(t => t.Id == viewModel.Id);
// // _mapper.Map(viewModel, updateItem);
// // var success = _dicRepository.SaveChanges();
// // return ResponseOutput.Result(success);
// //}
// #endregion
// var exp = new EntityVerifyExp<Dictionary>()
// {
// VerifyExp = dic => dic.KeyName.Equals(viewModel.KeyName) && dic.Value.Equals(viewModel.Value),
// VerifyMsg = "The item has the same name as a sub-item of current categpry"
// };
// //var entity = _dicRepository.UseMapper(_mapper).InsertOrUpdate(viewModel, true, exp);
// return ResponseOutput.Ok(entity.Id);
//}
/// <summary> 删除字典数据 </summary>
[HttpDelete("{id:guid}")]
public async Task<IResponseOutput> DeleteDictionary(Guid id)
{
if ((await _doctorDictionaryRepository.AnyAsync(t => t.DictionaryId == id)) ||
(await _doctorRepository.AnyAsync(t => t.SpecialityId == id|| t.PositionId == id|| t.DepartmentId == id|| t.RankId == id))
)
{
return ResponseOutput.NotOk("This item is referenced by content of the reviewer's resume.");
}
if (await _trialDictionaryRepository.AnyAsync(t => t.DictionaryId == id) ||
await _trialRepository.AnyAsync(t => t.ReviewModeId == id))
{
return ResponseOutput.NotOk("This item is referenced by content of the trial infomation.");
}
var success = await _dicRepository.DeleteFromQueryAsync(t => t.Id == id);
return ResponseOutput.Result(success);
}
/// <summary> 获取所有字典数据 </summary>
public async Task<IEnumerable<string>> getDictionarySelect()
{
return await _dicRepository.Select(t => t.KeyName).Distinct().ToListAsync();
}
//[Obsolete]
[NonDynamicMethod]
public DicViewModelDTO GetDetailById(Guid id)
{
var result = _dicRepository.ProjectTo<DicViewModelDTO>(_mapper.ConfigurationProvider).FirstOrDefault(u => u.Id == id).IfNullThrowException();
return result;
}
public TrialDicSelect GetGenerateTrialCodeDic()
{
var list = _dicRepository.Where(t => t.KeyName == "Phase" || t.KeyName == "IndicationType" || t.KeyName == "DeclarationType").ProjectTo<TrialDictionaryView>(_mapper.ConfigurationProvider).ToList();
return new TrialDicSelect()
{
Phase = list.Where(t => t.KeyName == "Phase").OrderBy(t => t.ShowOrder).ToArray(),
IndicationType = list.Where(t => t.KeyName == "IndicationType").OrderBy(t => t.ShowOrder).ToArray(),
DeclarationType = list.Where(t => t.KeyName == "DeclarationType").OrderBy(t => t.ShowOrder).ToArray()
};
}
#endregion
}
}
@@ -0,0 +1,65 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 13:11:20
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary>
/// EmailNoticeConfigService
/// </summary>
[ApiExplorerSettings(GroupName = "Common")]
public class EmailNoticeConfigService : BaseService, IEmailNoticeConfigService
{
private readonly IRepository<EmailNoticeConfig> repository;
public EmailNoticeConfigService(IRepository<EmailNoticeConfig> repository)
{
this.repository = repository;
}
[HttpPost]
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig)
{
var emailNoticeConfigQueryable = _repository
.WhereIf<EmailNoticeConfig>(queryEmailNoticeConfig.ScenarioId != null, t => t.ScenarioId == queryEmailNoticeConfig.ScenarioId)
.WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired)
.WhereIf(queryEmailNoticeConfig.IsUrgent != null, t => t.IsUrgent == queryEmailNoticeConfig.IsUrgent)
.WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable)
.ProjectTo<EmailNoticeConfigView>(_mapper.ConfigurationProvider);
return await emailNoticeConfigQueryable.ToPagedListAsync(queryEmailNoticeConfig.PageIndex, queryEmailNoticeConfig.PageSize, queryEmailNoticeConfig.SortField, queryEmailNoticeConfig.Asc);
}
public async Task<IResponseOutput> AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig)
{
var entity = await _repository.InsertOrUpdateAsync<EmailNoticeConfig, EmailNoticeConfigAddOrEdit>(addOrEditEmailNoticeConfig, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
[HttpDelete("{emailNoticeConfigId:guid}")]
public async Task<IResponseOutput> DeleteEmailNoticeConfig(Guid emailNoticeConfigId)
{
var success = await repository.DeleteFromQueryAsync(t => t.Id == emailNoticeConfigId);
return ResponseOutput.Result(success);
}
public async Task<Dictionary<object, string>> GetEmailScenarioEnumSelect()
{
return await Task.FromResult(EnumToSelectExtension.ToSelect<EmailScenarioEnum>());
}
}
}
@@ -0,0 +1,209 @@
using IRaCIS.Application.Interfaces;
using System.Text;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Application.Services
{
public class FileService : IFileService
{
private readonly IDoctorService _doctorService;
private readonly IAttachmentService _attachmentService;
private readonly IHostEnvironment _hostEnvironment;
private string defaultUploadFilePath = string.Empty;
private readonly ILogger<FileService> _logger;
public FileService(IDoctorService doctorService, IAttachmentService attachmentService,
IHostEnvironment hostEnvironment, ILogger<FileService> logger)
{
_doctorService = doctorService;
_attachmentService = attachmentService;
_hostEnvironment = hostEnvironment;
defaultUploadFilePath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
_logger = logger;
}
/// <summary>
/// 打包医生官方简历
/// </summary>
/// <param name="language"></param>
/// <param name="doctorIds"></param>
/// <returns></returns>
public async Task<string> CreateOfficialResumeZip(int language, Guid[] doctorIds)
{
//准备下载文件的临时路径
var guidStr = Guid.NewGuid().ToString();
//string uploadFolderPath = HostingEnvironment.MapPath("/UploadFile/");
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile");
var tempSavePath = Path.Combine(uploadFolderPath, "temp", guidStr); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹
if (!Directory.Exists(tempSavePath))
{
Directory.CreateDirectory(tempSavePath);
}
//找到服务器简历路径 循环拷贝简历到临时路径
foreach (var doctorId in doctorIds)
{
var doctor = await _doctorService.GetBasicInfo(doctorId);
var doctorName = doctor.FirstName + "_" + doctor.LastName;
//找官方简历存在服务器的相对路径
var sourceCvPath = await _attachmentService.GetDoctorOfficialCV(language, doctorId);
if (!string.IsNullOrWhiteSpace(sourceCvPath))
{
//服务器简历文件实际路径
//var sourceCvFullPath = HostingEnvironment.MapPath(sourceCvPath);
var sourceCvPathTemp = sourceCvPath.Substring(1, sourceCvPath.Length - 1);//.Replace('/','\\');
string sourceCvFullPath = Path.Combine(defaultUploadFilePath, sourceCvPathTemp);
var arr = sourceCvPath.Split('.');
string extensionName = arr[arr.Length - 1]; //得到扩展名
//需要拷贝到的路径
var doctorPath = Path.Combine(tempSavePath, doctor.ReviewerCode.ToString() + "_" + doctorName + "." + extensionName);
if (File.Exists(sourceCvFullPath))
{
File.Copy(sourceCvFullPath, doctorPath, true);
}
}
}
//创建ZIP
DateTime now = DateTime.Now;
StringBuilder sb = new StringBuilder();
sb.Append(now.Year).Append(now.Month.ToString().PadLeft(2, '0')).Append(now.Day.ToString().PadLeft(2, '0'))
.Append(now.Hour.ToString().PadLeft(2, '0')).Append(now.Minute.ToString().PadLeft(2, '0'))
.Append(now.Second.ToString().PadLeft(2, '0')).Append(now.Millisecond.ToString().PadLeft(3, '0'));
string targetZipPath = Path.Combine(uploadFolderPath, "CV_" + sb.ToString() + ".zip");
ZipHelper.CreateZip(tempSavePath, targetZipPath);
//返回Zip路径
return Path.Combine("/UploadFile/", "CV_" + sb.ToString() + ".zip");
}
/// <summary>
/// 打包医生的所有附件
/// </summary>
/// <param name="doctorIds"></param>
/// <returns></returns>
public async Task<string> CreateDoctorsAllAttachmentZip(Guid[] doctorIds)
{
//准备下载文件的临时路径
var guidStr = Guid.NewGuid().ToString();
//string uploadFolderPath = HostingEnvironment.MapPath("/UploadFile/");
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile");
var tempSavePath = Path.Combine(uploadFolderPath, "temp", guidStr); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹
if (!Directory.Exists(tempSavePath))
{
Directory.CreateDirectory(tempSavePath);
}
foreach (var doctorId in doctorIds)
{
//获取医生基本信息
var doctor = await _doctorService.GetBasicInfo(doctorId);
var doctorName = doctor.FirstName + "_" + doctor.LastName;
var doctorCode = doctor.ReviewerCode;
var doctorDestPath = Path.Combine(tempSavePath, doctorCode + "_" + doctorName);
if (!Directory.Exists(doctorDestPath))
{
Directory.CreateDirectory(doctorDestPath);
}
//服务器上传后的源路径
string doctorFileSourcePath = Path.Combine(uploadFolderPath, doctorId.ToString());
if (Directory.Exists(doctorFileSourcePath))
{
CopyDirectory(doctorFileSourcePath, doctorDestPath);
}
}
string target = Guid.NewGuid().ToString();
string targetPath = Path.Combine(uploadFolderPath, target + ".zip");
ZipHelper.CreateZip(tempSavePath, targetPath);
return Path.Combine("/UploadFile/", target + ".zip");
}
public async Task<string> CreateZipPackageByAttachment(Guid doctorId, Guid[] attachmentIds)
{
var doctor = await _doctorService.GetBasicInfo(doctorId);
var doctorName = doctor.FirstName + "_" + doctor.LastName;
Guid temp = Guid.NewGuid();
//string root = HostingEnvironment.MapPath("/UploadFile/"); //文件根目录
string root = Path.Combine(defaultUploadFilePath, "UploadFile");
var tempPath = Path.Combine(root, "temp", temp.ToString(), doctor.ReviewerCode + doctorName); //待压缩的文件夹,将需要下载的文件拷贝到此文件夹
var packagePath = Path.Combine(root, "temp", temp.ToString()); //打包目录
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
var attachemnts = (await _attachmentService.GetAttachments(doctorId)).Where(a => attachmentIds.Contains(a.Id));
foreach (var item in attachemnts)
{
var arr = item.Path.Trim().Split('/');
var myPath = string.Empty;
var myFile = string.Empty;
//需要改进
if (arr.Length > 0)
{
myFile = arr[arr.Length - 1];
foreach (var arrItem in arr)
{
if (arrItem != string.Empty && !"UploadFile".Equals(arrItem))
{
myPath += (arrItem + "/");
}
}
myPath = myPath.TrimEnd('/');
}
var sourcePath = Path.Combine(root, myPath);
if (!string.IsNullOrWhiteSpace(sourcePath) && File.Exists(sourcePath))
{
File.Copy(sourcePath, Path.Combine(tempPath, myFile), true);
}
}
string target = Guid.NewGuid().ToString();
string targetPath = Path.Combine(root, target + ".zip");
ZipHelper.CreateZip(packagePath, targetPath);
return Path.Combine("/UploadFile/", target + ".zip");
}
private static void CopyDirectory(string srcPath, string destPath)
{
DirectoryInfo dir = new DirectoryInfo(srcPath);
FileSystemInfo[] fileInfoArray = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录
foreach (FileSystemInfo fileInfo in fileInfoArray)
{
if (fileInfo is DirectoryInfo) //判断是否文件夹
{
if (!Directory.Exists(destPath + "\\" + fileInfo.Name))
{
Directory.CreateDirectory(destPath + "\\" + fileInfo.Name); //目标目录下不存在此文件夹即创建子文件夹
}
CopyDirectory(fileInfo.FullName, destPath + "\\" + fileInfo.Name); //递归调用复制子文件夹
}
else
{
File.Copy(fileInfo.FullName, destPath + "\\" + fileInfo.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件
}
}
}
}
}
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using EasyCaching.Core.Interceptor;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IDictionaryService
{
Task<IEnumerable<string>> getDictionarySelect();
PageOutput<DicViewModelDTO> getDictionarySelectList(DicQueryDTO dicSearchModel);
Task<IResponseOutput> DeleteDictionary(Guid id);
DicResultDTO GetDictionary(string[] searchArray);
DicResultDTO GetAllDictionary();
//IResponseOutput AddOrUpdateDictionary(AddOrUpdateDicDTO viewModel);
[EasyCachingAble(Expiration = 10)]
List<DictionaryTreeNode> GetDicTree();
DicViewModelDTO GetDetailById(Guid Id);
TrialDicSelect GetGenerateTrialCodeDic();
}
}
@@ -0,0 +1,15 @@
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 13:11:20
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
namespace IRaCIS.Core.Application.Contracts
{
public interface IEmailNoticeConfigService
{
Task<IResponseOutput> AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig);
Task<IResponseOutput> DeleteEmailNoticeConfig(Guid emailNoticeConfigId);
Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig);
}
}
@@ -0,0 +1,17 @@
using System;
namespace IRaCIS.Application.Interfaces
{
public interface IFileService
{
//IResponseOutput<UploadFileInfo> DownloadOfficialResume(Guid[] doctorIds);
Task<string> CreateOfficialResumeZip(int language, Guid[] doctorIds);
Task<string> CreateDoctorsAllAttachmentZip(Guid[] doctorIds);
Task<string> CreateZipPackageByAttachment(Guid doctorId, Guid[] attachmentIds);
}
}
@@ -0,0 +1,21 @@
using System;
using IRaCIS.Application.Contracts;
using System.Collections.Generic;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface ILogService
{
IResponseOutput SaveLog2Db(SystemLogDTO viewModel);
PageOutput<SystemLogDTO> GetLogList(QueryLogQueryDTO param);
PageOutput<AuditDTO> GetAuditList(AuditQueryDTO param);
List<OptUserDto> GetOptUserList(Guid trialId);
List<AuditSubjectSelectDto> GetSubjectList(Guid trialId);
}
}
@@ -0,0 +1,15 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IMessageService
{
int GetUnReadMessageCount(Guid doctorId);
IResponseOutput DeleteSysMessage(Guid messageId);
IResponseOutput MarkedAsRead(Guid messageId);
PageOutput<SysMessageDTO> GetMessageList(Guid doctorId, int pageSize, int pageIndex);
}
}
@@ -0,0 +1,25 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 15:47:41
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
namespace IRaCIS.Core.Application.Contracts
{
/// <summary>
/// ISystemBasicDataService
/// </summary>
public interface ISystemBasicDataService
{
Task<PageOutput<SystemBasicDataView>> GetSystemBasicDataList(SystemBasicDataQuery querySystemBasicData);
Task<IResponseOutput> AddOrUpdateSystemBasicData(SystemBasicDataAddOrEdit addOrEditSystemBasicData);
Task<IResponseOutput> DeleteSystemBasicData(Guid systemBasicDataId);
}
}
@@ -0,0 +1,114 @@
//using IRaCIS.Application.Interfaces;
//using IRaCIS.Application.Contracts;
//using IRaCIS.Core.Infra.EFCore;
//using IRaCIS.Core.Infrastructure;
//using Microsoft.AspNetCore.Http;
//using Microsoft.AspNetCore.Mvc;
//using Panda.DynamicWebApi.Attributes;
//namespace IRaCIS.Application.Services
//{
// /// <summary>
// /// 日志、项目审计日志
// /// </summary>
// [ApiExplorerSettings(GroupName = "Common")]
// public class LogService : BaseService, ILogService
// {
// private readonly IRepository<SystemLog> _systemLogRepository;
// private readonly IHttpContextAccessor _context;
// private readonly IRepository<TrialAudit> _trialAuditRepository;
// private readonly IRepository<Subject> _subjectRepository;
// private readonly IRepository<Trial> _trialRepository;
// public LogService(IRepository<SystemLog> systemLogRepository, IHttpContextAccessor context, IRepository<TrialAudit> trialAuditRepository,
// IRepository<Subject> subjectRepository, IRepository<Trial> trialRepository)
// {
// _systemLogRepository = systemLogRepository;
// _context = context;
// _trialAuditRepository = trialAuditRepository;
// _subjectRepository = subjectRepository;
// _trialRepository = trialRepository;
// }
// [HttpPost]
// public PageOutput<AuditDTO> GetAuditList(AuditQueryDTO param)
// {
// var subjectInfo = param.SubjectInfo == null ? string.Empty : param.SubjectInfo.Trim();
// var query = _trialAuditRepository.Where(x => x.TrialId == param.TrialId)
// .WhereIf(param.AuditType != null, t => t.AuditType == param.AuditType)
// .WhereIf(param.OptUserId != null, t => t.OptUserId == param.OptUserId)
// .WhereIf(param.SubjectId != null, t => t.SubjectId == param.SubjectId)
// .WhereIf(!string.IsNullOrEmpty(subjectInfo), t => t.Subject.Code.Contains(subjectInfo) || (t.Subject.LastName + " / " + t.Subject.FirstName).Contains(subjectInfo))
// .WhereIf(param.StudyId != null, t => t.StudyId == param.StudyId)
// .WhereIf(param.StartDate != null, t => t.OptTime >= param.StartDate)
// .WhereIf(param.EndDate != null, t => t.OptTime <= param.EndDate)
// .ProjectTo<AuditDTO>(_mapper.ConfigurationProvider);
// return query.ToPagedList(param.PageIndex, param.PageSize, string.IsNullOrWhiteSpace(param.SortField) ? "OptTime" : param.SortField, param.Asc);
// }
// /// <summary> 查询系统日志信息 </summary>
// [HttpPost]
// public PageOutput<SystemLogDTO> GetLogList(QueryLogQueryDTO param)
// {
// var LogCategory = param.LogCategory == null ? string.Empty : param.LogCategory.Trim();
// var keyword = param.Keyword == null ? string.Empty : param.Keyword.Trim();
// var logQueryable = _systemLogRepository
// .WhereIf(param.BeginTime!=null,t=>t.RequestTime>= param.BeginTime)
// .WhereIf(param.EndTime != null, t => t.RequestTime <= param.EndTime)
// .WhereIf(!string.IsNullOrEmpty(LogCategory), t => t.LogCategory == param.LogCategory)
// .WhereIf(!string.IsNullOrEmpty(keyword), t => t.Params.Contains(keyword) || t.Result.Contains(keyword))
// .ProjectTo<SystemLogDTO>(_mapper.ConfigurationProvider);
// return logQueryable.ToPagedList(param.PageIndex, param.PageSize, string.IsNullOrWhiteSpace(param.SortField) ? "RequestTime" : param.SortField, param.Asc);
// }
// [HttpGet("{trialId:guid}")]
// public List<OptUserDto> GetOptUserList(Guid trialId)
// {
// var list = _trialAuditRepository.Where(t => t.TrialId == trialId).Select(u => new OptUserDto()
// {
// OptUserId = u.OptUserId,
// OptUser = u.OptUser
// }).Distinct().ToList();
// return list;
// }
// /// <summary>
// /// 审计列表 受试者下拉框 从受试者那里进去看的时候,这里需要固定,如果不采用下拉框,请传递指定格式的受试者信息查询才行
// /// </summary>
// /// <param name="trialId"></param>
// /// <returns></returns>
// [HttpGet("{trialId:guid}")]
// public List<AuditSubjectSelectDto> GetSubjectList(Guid trialId)
// {
// var query = from trialAudit in _trialAuditRepository.Where(t => t.TrialId == trialId)
// join subject in _subjectRepository.AsQueryable() on trialAudit.SubjectId equals subject.Id
// select new AuditSubjectSelectDto()
// {
// SubjectCode = subject.Code,
// SubjectId = trialAudit.SubjectId,
// SubjectName = subject.LastName + " / " + subject.FirstName
// };
// return query.Distinct().ToList();
// }
// [NonDynamicMethod]
// public IResponseOutput SaveLog2Db(SystemLogDTO input)
// {
// input.ClientIP = IPHelper.GetIP(_context?.HttpContext?.Request);
// _systemLogRepository.Add(_mapper.Map<SystemLog>(input));
// var success = _systemLogRepository.SaveChanges();
// return ResponseOutput.Result(success);
// }
// }
//}
@@ -0,0 +1,231 @@
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using MailKit.Security;
using MimeKit;
namespace IRaCIS.Application.Services
{
public interface IMailVerificationService
{
Task SendMail(Guid userId, string userName, string emailAddress, int verificationCode);
Task AnolymousSendEmail(string emailAddress, int verificationCode);
Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode);
}
public class MailVerificationService : IMailVerificationService
{
private readonly IRepository<VerificationCode> _verificationCodeRepository;
private readonly IRepository<SystemBasicData> _systemBasicDatarepository;
public MailVerificationService(IRepository<VerificationCode> verificationCodeRepository, IRepository<SystemBasicData> systemBasicDatarepository)
{
_verificationCodeRepository = verificationCodeRepository;
_systemBasicDatarepository = systemBasicDatarepository;
}
public async Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com"));
//收件地址
messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
//主题
messageToSend.Subject = "Reset PassWord (Verification Code)";
messageToSend.Body = new TextPart("plain")
{
Text = $@"Hey {userName},you are modify your email . The verification code is: {verificationCode}, which is valid within 3 minutes. If it is not your own operation, please ignore it!
-- GRR"
};
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.MessageSent += (sender, args) =>
{
// args.Response
var code = verificationCode.ToString();
_ = _verificationCodeRepository.AddAsync(new VerificationCode()
{
CodeType = 0,
HasSend = true,
Code = code,
UserId = userId,
ExpirationTime = DateTime.Now.AddMinutes(3)
}).Result;
_ = _verificationCodeRepository.SaveChangesAsync().Result;
};
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
await smtp.ConnectAsync("smtp.163.com", 25, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH");
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
public async Task SendMail(Guid userId, string userName, string emailAddress, int verificationCode)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com"));
//收件地址
messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
//主题
messageToSend.Subject = "Reset PassWord (Verification Code)";
messageToSend.Body = new TextPart("plain")
{
Text = $@"Hey {userName},you are resetting your password via email. The verification code is: {verificationCode}, which is valid within 3 minutes. If it is not your own operation, please ignore it!
-- GRR"
};
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.MessageSent += (sender, args) =>
{
// args.Response
var code = verificationCode.ToString();
_= _verificationCodeRepository.AddAsync(new VerificationCode()
{
CodeType = 0,
HasSend = true,
Code = code,
UserId = userId,
ExpirationTime = DateTime.Now.AddMinutes(3)
}).Result;
_= _verificationCodeRepository.SaveChangesAsync().Result;
};
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
await smtp.ConnectAsync("smtp.163.com", 25, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH");
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
public async Task AnolymousSendEmail(string emailAddress, int verificationCode)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com"));
//收件地址
messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
//主题
messageToSend.Subject = "GRR Site survey (Verification Code)";
messageToSend.Body = new TextPart("plain")
{
Text = $@"Hey ,you are login for site survey via email. The verification code is: {verificationCode}, which is valid within 3 minutes. If it is not your own operation, please ignore it!
-- GRR"
};
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.MessageSent += (sender, args) =>
{
// args.Response
var code = verificationCode.ToString();
_ = _verificationCodeRepository.AddAsync(new VerificationCode()
{
CodeType = 0,
HasSend = true,
Code = code,
UserId = Guid.Empty,//此时不知道用户
EmailOrPhone = emailAddress,
ExpirationTime = DateTime.Now.AddMinutes(3)
}).Result;
_ = _verificationCodeRepository.SaveChangesAsync().Result;
};
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
await smtp.ConnectAsync("smtp.163.com", 25, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH");
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
public async Task SendEmailForExternalUser(string emailAddress, string verificationCode)
{
var messageToSend = new MimeMessage();
//发件地址
messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com"));
//收件地址
messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
//主题
messageToSend.Subject = "GRR External User survey (Verification Code)";
messageToSend.Body = new TextPart("plain")
{
Text = $@"Hey ,you are login for site survey via email. The verification code is: {verificationCode}, If it is not your own operation, please ignore it!
-- GRR"
};
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
smtp.MessageSent += (sender, args) =>
{
// args.Response
var code = verificationCode.ToString();
_ = _verificationCodeRepository.AddAsync(new VerificationCode()
{
CodeType = 0,
HasSend = true,
Code = code,
UserId = Guid.Empty,//此时不知道用户
EmailOrPhone = emailAddress,
ExpirationTime = DateTime.Now.AddMinutes(3)
}).Result;
_ = _verificationCodeRepository.SaveChangesAsync().Result;
};
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
await smtp.ConnectAsync("smtp.163.com", 25, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH");
await smtp.SendAsync(messageToSend);
await smtp.DisconnectAsync(true);
}
}
}
}
@@ -0,0 +1,87 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-02-15 15:57:21
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Application.Contracts;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Core.Application.Services
{
/// <summary>
/// SystemBasicDataService
/// </summary>
[ApiExplorerSettings(GroupName = "Common")]
public class SystemBasicDataService : BaseService, ISystemBasicDataService
{
/// <summary>
/// 模板列表
/// </summary>
/// <param name="querySystemBasicData"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<SystemBasicDataView>> GetSystemBasicDataList(SystemBasicDataQuery querySystemBasicData)
{
var systemBasicDataQueryable = _repository.GetQueryable<SystemBasicData>().Where(t => t.ParentId == null)
.ProjectTo<SystemBasicDataView>(_mapper.ConfigurationProvider);
return await systemBasicDataQueryable.ToPagedListAsync(querySystemBasicData.PageIndex, querySystemBasicData.PageSize, String.IsNullOrEmpty(querySystemBasicData.SortField) ? "Code" : querySystemBasicData.SortField, querySystemBasicData.Asc);
}
[HttpGet("{code}")]
public async Task<SystemBasicDataView> GetSystemBasicData(string code)
{
return await _repository.Where<SystemBasicData>(t => t.Code == code).ProjectTo<SystemBasicDataView>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
}
/// <summary>
/// 模板关联的场景
/// </summary>
/// <param name="parentId"></param>
/// <returns></returns>
[HttpGet("{parentId:guid}")]
public async Task<List<SystemBasicDataView>> GetChildList(Guid parentId)
{
return await _repository.GetQueryable<SystemBasicData>().Where(t => t.ParentId == parentId&&t.IsEnable).OrderBy(t => t.Code).ProjectTo<SystemBasicDataView>(_mapper.ConfigurationProvider).ToListAsync();
}
public async Task<IResponseOutput> AddOrUpdateSystemBasicData(SystemBasicDataAddOrEdit addOrEditSystemBasicData)
{
var entity = await _repository.InsertOrUpdateAsync<SystemBasicData, SystemBasicDataAddOrEdit>(addOrEditSystemBasicData, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
[HttpDelete("{systemBasicDataId:guid}")]
public async Task<IResponseOutput> DeleteSystemBasicData(Guid systemBasicDataId)
{
var success = await _repository.DeleteFromQueryAsync<SystemBasicData>(t => t.Id == systemBasicDataId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 传递父亲Code 数组 返回多个下拉框数据
/// </summary>
/// <param name="searchArray"></param>
/// <returns></returns>
[HttpPost]
public async Task<Dictionary<string, List<SystemBasicDataSelect>>> GetBasicDataSelect(string[] searchArray)
{
var searchList = await _repository.GetQueryable<SystemBasicData>().Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null).ProjectTo<SystemBasicDataSelect>(_mapper.ConfigurationProvider).ToListAsync();
return searchList.GroupBy(t => t.ParentCode).ToDictionary(g => g.Key, g => g.ToList());
}
}
}
@@ -0,0 +1,47 @@
using AutoMapper;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.Application.Service
{
public class CommonConfig : Profile
{
public CommonConfig()
{
CreateMap<Message, SysMessageDTO>()
.ForMember(o => o.MessageTime, t => t.MapFrom(u => u.MessageTime.ToString()));
CreateMap<SystemLog, SystemLogDTO>();
CreateMap<SystemLogDTO, SystemLog>();
CreateMap<EmailNoticeConfigAddOrEdit, EmailNoticeConfig>().ReverseMap();
CreateMap<EmailNoticeConfig, EmailNoticeConfigView>();
CreateMap<SystemBasicData, SystemBasicDataView>();
CreateMap<SystemBasicData, SystemBasicDataSelect>()
.ForMember(o => o.ParentCode, t => t.MapFrom(u => u.Parent.Code));
CreateMap<SystemBasicDataAddOrEdit, SystemBasicData>().ReverseMap();
CreateMap<Dictionary, BasicDicView>()
.ForMember(o => o.ConfigType, t => t.MapFrom(u => u.ConfigDictionary.Code))
.ForMember(o => o.ConfigTypeDes, t => t.MapFrom(u => u.ConfigDictionary.Description));
CreateMap<AddOrEditBasicDic, Dictionary>().ReverseMap();
CreateMap<Dictionary, BasicDicSelect>()
.ForMember(o => o.ParentCode, t => t.MapFrom(u => u.Parent.Code));
}
}
}
@@ -0,0 +1,254 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
/// <summary>
/// 医生文档关联关系维护
/// </summary>
[ApiExplorerSettings(GroupName = "Reviewer")]
public class AttachmentService : BaseService, IAttachmentService
{
private readonly IRepository<Attachment> attachmentrepository;
public AttachmentService(IRepository<Attachment> attachmentrepository)
{
this.attachmentrepository = attachmentrepository;
}
/// <summary>
/// 删除附件
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public async Task<IResponseOutput> DeleteAttachment([FromBody]AttachementCommand param)
{
//var attachment = _doctorAttachmentApp.GetDetailById(id);
//string file = HostingEnvironment.MapPath(attachment.Path);
//if (File.Exists(file))
//{
// File.Delete(file);
//}
//var temp = HostingEnvironment.MapPath(param.Path);
//if (File.Exists(temp))
//{
// File.Delete(temp);
//}
var success =await attachmentrepository.DeleteFromQueryAsync(a => a.Id == param.Id);
return ResponseOutput.Result(success);
}
/// <summary>
/// 根据医生Id 和 附件类型,获取记录
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <param name="type">附件类型</param>
/// <returns></returns>
[HttpGet("{doctorId:guid}/{type}")]
public async Task<IEnumerable<AttachmentDTO>> GetAttachmentByType(Guid doctorId, string type)
{
var attachmentList = await attachmentrepository.Where(a => a.DoctorId == doctorId && a.Type.Equals(type)).ProjectTo<AttachmentDTO>(_mapper.ConfigurationProvider).ToListAsync();
attachmentList.ForEach(t => t.FullPath = t.Path + "?access_token=" + _userInfo.UserToken);
return attachmentList;
}
/// <summary>
/// 获取单个医生的多种证书附件
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <param name="types">类型数组</param>
/// <returns></returns>
[HttpPost("{doctorId:guid}")]
public async Task<IEnumerable<AttachmentDTO>> GetAttachmentByTypes(Guid doctorId, string[] types)
{
var attachmentList =await attachmentrepository.Where(a => a.DoctorId == doctorId && types.Contains(a.Type)).OrderBy(s => s.Type).ThenBy(m => m.CreateTime).ProjectTo<AttachmentDTO>(_mapper.ConfigurationProvider).ToListAsync();
attachmentList.ForEach(t => t.FullPath = t.Path + "?access_token=" + _userInfo.UserToken);
return attachmentList;
}
/// <summary>
/// 根据医生Id获取医生附件
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <returns></returns>
[HttpGet("{doctorId:guid}")]
public async Task<IEnumerable<AttachmentDTO>> GetAttachments(Guid doctorId)
{
var attachmentList =await attachmentrepository.Where(a => a.DoctorId == doctorId).OrderBy(s => s.Type).ThenBy(m => m.CreateTime).ProjectTo<AttachmentDTO>(_mapper.ConfigurationProvider).ToListAsync();
attachmentList.ForEach(t => t.FullPath = t.Path + "?access_token=" + _userInfo.UserToken);
return attachmentList;
}
[NonDynamicMethod]
public async Task<AttachmentDTO> GetDetailById(Guid attachmentId)
{
var attachment = await attachmentrepository.FirstOrDefaultAsync(a => a.Id == attachmentId).IfNullThrowException();
var temp= _mapper.Map<AttachmentDTO>(attachment);
temp.FullPath = temp.Path + "?access_token=" + _userInfo.UserToken;
return temp;
}
/// <summary>
/// 保存多个附件
/// </summary>
/// <param name="attachmentList"></param>
/// <returns></returns>
public async Task<IEnumerable<AttachmentDTO>> SaveAttachments(IEnumerable<AttachmentDTO> attachmentList)
{
var attachments = _mapper.Map<IEnumerable<Attachment>>(attachmentList).ToList();
//1 是中文 2是英文 中英文第一份简历默认设置为官方
var zhCount = attachments.Count(t => t.Language == 1);
var usCount = attachments.Count(t => t.Language == 2);
if (zhCount == 1)
{
var k = attachments.First(t => t.Language == 1);
k.IsOfficial = true;
}
if (usCount == 1)
{
var k = attachments.First(t => t.Language == 2);
k.IsOfficial = true;
}
//处理重传
var reUpload = attachmentList.FirstOrDefault(t => t.ReUpload == true);
if (reUpload != null)
{
//因为界面现实的列表用了 接口返回的列表,所以要把返回的模型对应的字段也要更改
var attach = attachments.First(t => t.Id == reUpload.Id);
attach.CreateTime = DateTime.Now;
//重传的时候,发现 相同语言的官方简历数量为2 那么将重传的简历设置为非官方
if (attachments.Count(t => t.Language == reUpload.Language && t.IsOfficial) == 2)
{
await attachmentrepository.UpdateFromQueryAsync(t => t.Id == reUpload.Id, u => new Attachment()
{
Path = reUpload.Path,
CreateTime = DateTime.Now,
Language = reUpload.Language,
IsOfficial = false
});
attach.IsOfficial = false;
}
else //相同语言的重传
{
await attachmentrepository.UpdateFromQueryAsync(t => t.Id == reUpload.Id, u => new Attachment()
{
Path = reUpload.Path,
CreateTime = DateTime.Now,
Language = reUpload.Language
});
}
}
var newAttachment = attachments.Where(t => t.Id == Guid.Empty);
await _repository.AddRangeAsync(newAttachment);
await _repository.SaveChangesAsync();
//_doctorAttachmentRepository.AddRange(newAttachment);
//_doctorAttachmentRepository.SaveChanges();
var list = _mapper.Map<IEnumerable<AttachmentDTO>>(attachments).ToList();
list.ForEach(t => t.FullPath = t.Path + "?access_token=" + _userInfo.UserToken);
return list;
}
public async Task<IResponseOutput<AttachmentDTO>> AddAttachment(AttachmentDTO attachment)
{
var newAttachment = _mapper.Map<Attachment>(attachment);
//如果这个医生不存在 这个语言的官方简历 就设置为官方简历
if (! await attachmentrepository.AnyAsync(t => t.Type == "Resume" && t.DoctorId == attachment.DoctorId && t.Language == attachment.Language && t.IsOfficial))
{
newAttachment.IsOfficial = true;
attachment.IsOfficial = true;
}
await _repository.AddAsync(newAttachment);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, attachment);
}
[NonDynamicMethod]
public async Task<string> GetDoctorOfficialCV(int language, Guid doctorId)
{
var result = await attachmentrepository.FirstOrDefaultAsync(a => a.DoctorId == doctorId &&
a.IsOfficial && a.Type.Equals("Resume") && a.Language == language);
if (result != null)
{
return result.Path;
}
return string.Empty;
}
/// <summary>
/// 将简历设置为官方简历
/// </summary>
/// <param name="doctorId"></param>
/// <param name="attachmentId"></param>
/// <param name="language"></param>
/// <returns></returns>
[HttpPost("{doctorId:guid}/{attachmentId:guid}/{language}")]
public async Task<IResponseOutput> SetOfficial(Guid doctorId, Guid attachmentId, int language)
{
var resumeList = await _repository.GetQueryable<Attachment>().Where(t => t.DoctorId == doctorId && t.Type == "Resume" && t.Language == language).ToListAsync();
foreach (var item in resumeList)
{
if (item.Id == attachmentId) item.IsOfficial = true;
else item.IsOfficial = false;
await _repository.UpdateAsync(item);
}
return ResponseOutput.Result(await _repository.SaveChangesAsync());
}
/// <summary>
/// 设置简历的语言类型
/// </summary>
/// <param name="doctorId"></param>
/// <param name="attachmentId"></param>
/// <param name="language">0-未设置,1-中文,2-英文</param>
/// <returns></returns>
[HttpPost("{doctorId:guid}/{attachmentId:guid}/{language}")]
public async Task<IResponseOutput> SetLanguage(Guid doctorId, Guid attachmentId, int language)
{
bool result =await attachmentrepository.UpdateFromQueryAsync(t => t.Id == attachmentId, a => new Attachment
{
Language = language,
IsOfficial = false
});
return ResponseOutput.Result(result);
}
}
}
@@ -0,0 +1,61 @@
namespace IRaCIS.Application.Contracts
{
public class AttachmentDTO
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public bool IsOfficial { get; set; }
public string Type { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string FullPath { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public DateTime? CreateTime { get; set; }
public int Language { get; set; }
public bool ReUpload { get; set; } = false;
}
public class ReviewerAckDTO
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public string Type { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string FullPath => Path;
public string FileName { get; set; } = string.Empty;
}
public class TrialSOWPathDTO
{
public Guid TrialId { get; set; }
public string SowName { get; set; } = string.Empty;
public string SowPath { get; set; } = string.Empty;
}
public class DeleteSowPathDTO
{
public Guid TrialId { get; set; }
public string Path { get; set; } = string.Empty;
}
public class UploadAgreementAttachmentDTO
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public string Type { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string FullPath => Path;
public string FileName { get; set; } = string.Empty;
}
public class AttachementCommand
{
public Guid Id { get; set; }
public string Path { get; set; } = string.Empty;
}
}
@@ -0,0 +1,12 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class DoctorAccountRegisterModel : DoctorAccountLoginDTO
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
public DateTime RegisterTime { get; set; }
}
}
@@ -0,0 +1,665 @@
using System;
using System.Collections.Generic;
using IRaCIS.Core.Infrastructure.Extention;
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
using System.Linq;
namespace IRaCIS.Application.Contracts
{
#region
public class DoctorDTO
{
[JsonIgnore]
public List<DicView> DictionaryList { get; set; } = new List<DicView>();
//临床实践中使用的模式
public List<string> ReadingTypeList => DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList();
public List<string> ReadingTypeCNList => DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).OrderBy(t => t.ShowOrder).Select(t => t.ValueCN).ToList();
public List<Guid> ReadingTypeIds => DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList();
//第二专业
public List<string> SubspecialityList => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList();
public List<string> SubspecialityCNList => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.ValueCN).ToList();
public List<Guid> SubspecialityIds => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList();
public string ReadingTypeOther { get; set; } = String.Empty;
public string ReadingTypeOtherCN { get; set; } = String.Empty;
public Guid Id { get; set; }
public DateTime CreateTime { get; set; }
public string ReviewerCode { get; set; } = String.Empty;//GUID
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string ChineseName { get; set; } = string.Empty;
public List<Guid> TitleIdList { get; set; } = new List<Guid>();
public List<string> TitleList { get; set; } = new List<string>();
public List<string> TitleCNList { get; set; } = new List<string>();
public string Phone { get; set; } = string.Empty;
public string Introduction { get; set; } = string.Empty;
public string EMail { get; set; } = string.Empty;
public string WeChat { get; set; } = string.Empty;
//部门
public string Department { get; set; } = string.Empty;
public string DepartmentCN { get; set; } = string.Empty;
public Guid? DepartmentId { get; set; }
public string DepartmentOther { get; set; } = String.Empty;
public string DepartmentOtherCN { get; set; } = String.Empty;
//增加的
public Guid? SpecialityId { get; set; } = Guid.Empty;
public string Speciality { get; set; } = string.Empty;
public string SpecialityCN { get; set; } = string.Empty;
public string SpecialityOther { get; set; } = string.Empty;
public string SpecialityOtherCN { get; set; } = string.Empty;
//职称
public string Rank { get; set; } = string.Empty;
public string RankCN { get; set; } = string.Empty;
public Guid? RankId { get; set; }
public string RankOther { get; set; } = String.Empty;
public string RankOtherCN { get; set; } = String.Empty;
//职位
public string Position { get; set; } = string.Empty;
public string PositionCN { get; set; } = string.Empty;
public Guid? PositionId { get; set; }
public string PositionOther { get; set; } = String.Empty;
public string PositionOtherCN { get; set; } = String.Empty;
public string SubspecialityOther { get; set; } = String.Empty;
public string SubspecialityOtherCN { get; set; } = String.Empty;
public int GCP { get; set; }
public Guid? GCPId { get; set; }
public string ResumePath { get; set; } = string.Empty;
public bool HasResume
{
get; set;
}
public bool Reconfirmed { get; set; }
public int CooperateStatus { get; set; }
public int ResumeStatus { get; set; }
public bool AcceptingNewTrial { get; set; } = false;
public bool ActivelyReading { get; set; } = false;
//医院
public Guid? HospitalId { get; set; }
public string HospitalOther { get; set; } = String.Empty;
public string HospitalName { get; set; } = string.Empty;
public string City { get; set; } = String.Empty;
public string Country { get; set; } = String.Empty;
public string HospitalNameCN { get; set; } = string.Empty;
public string CityCN { get; set; } = String.Empty;
public string CountryCN { get; set; } = String.Empty;
public int? Reading { get; set; }
public int? Approved { get; set; }
public int? Submitted { get; set; }
public int? Finished { get; set; }
}
/// <summary>
/// Reviewer 列表查询参数
/// </summary>
public class DoctorSearchDTO : PageInput
{
public string Name { get; set; } = string.Empty;
public List<Guid> ReadingTypeIdList { get; set; } = new List<Guid>();
public List<Guid> SubspecialityIdList { get; set; } = new List<Guid>();
public List<Guid> EvaluationCriteriaIdList { get; set; } = new List<Guid>();
public List<Guid> TitleIdList { get; set; } = new List<Guid>();
public Guid? DepartmentId { get; set; }
public Guid? SpecialityId { get; set; }
public Guid? PositionId { get; set; }
public Guid? RankId { get; set; }
public Guid? HospitalId { get; set; }
//合作状态
public ContractorStatusEnum? ContractorStatus { get; set; }
// 简历审核状态
public ResumeStatusEnum? InformationConfirmed { get; set; }
public int? EnrollStatus { get; set; } //入组状态
public bool? AcceptingNewTrial { get; set; }//是否接受新的项目
public bool? ActivelyReading { get; set; }// 是否接受新的读片任务
public int? Nation { get; set; }// 0-中国医生,2-美国医生,3-全部
}
/// <summary>
/// 入组 Selection 列表查询参数
/// </summary>
public class ReviewerSelectionQueryDTO : DoctorSearchDTO
{
public Guid TrialId { get; set; }
}
public class ReviewerSubmissionQueryDTO : PageInput
{
public Guid TrialId { get; set; } = Guid.Empty;
public int IntoGroupSearchState { get; set; }
}
public class ReviewerConfirmationQueryDTO : PageInput
{
public Guid TrialId { get; set; } = Guid.Empty;
}
public class SelectionReviewerDTO : DoctorDTO
{
public int DoctorTrialState { get; set; }
public string OptUserName { get; set; } = string.Empty;
public DateTime? OptTime { get; set; }
public string? OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss");
}
public class DoctorOptDTO
{
public Guid Id { get; set; }
public string Code { get; set; } = String.Empty;//GUID
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string ChineseName { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
public string HospitalName { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
}
public class ConfirmationReviewerDTO : DoctorOptDTO
{
public int DoctorTrialState { get; set; }
public string OptUserName { get; set; } = string.Empty;
public DateTime? OptTime { get; set; }
public string? OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss");
}
public class DoctorStateModelDTO
{
public Guid DoctorId { get; set; }
public int IntoGroupState { get; set; }
public string OptUserName { get; set; } = String.Empty;
public DateTime? OptTime { get; set; }
}
#endregion
public class DoctorDetailDTO
{
public DoctorBasicInfoDTO BasicInfoView { get; set; }
public EmploymentDTO EmploymentView { get; set; }
public SpecialtyDTO SpecialtyView { get; set; }
public IEnumerable<EducationInfoViewModel> EducationList { get; set; }
public IEnumerable<PostgraduateViewModel> PostgraduateList { get; set; }
public ResearchPublicationDTO ResearchPublicationView { get; set; }
public TrialExperienceModel TrialExperienceView { get; set; }
public ResumeConfirmDTO AuditView { get; set; }
public IEnumerable<AttachmentDTO> AttachmentList { get; set; }
public List<SowDTO> SowList { get; set; }
public List<SowDTO> AckSowList { get; set; }
public DoctorEnrollInfoDTO IntoGroupInfo { get; set; }
public bool InHoliday { get; set; }
public DoctorDetailDTO()
{
BasicInfoView = new DoctorBasicInfoDTO();
EmploymentView = new EmploymentDTO();
SpecialtyView = new SpecialtyDTO();
EducationList = new List<EducationInfoViewModel>();
PostgraduateList = new List<PostgraduateViewModel>();
ResearchPublicationView = new ResearchPublicationDTO();
TrialExperienceView = new TrialExperienceModel();
AuditView = new ResumeConfirmDTO();
AttachmentList = new List<AttachmentDTO>();
IntoGroupInfo = new DoctorEnrollInfoDTO();
SowList = new List<SowDTO>();
AckSowList = new List<SowDTO>();
}
}
public class DoctorEnrollInfoDTO
{
public Guid? DoctorId { get; set; }
public int? Submitted { get; set; }
public int? Approved { get; set; }
public int? Reading { get; set; }
}
#region
public class DoctorBasicInfo
{
public Guid? Id { get; set; }
public string ReviewerCode { get; set; } = string.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string ChineseName { get; set; } = String.Empty;
public int Sex { get; set; }
public string Phone { get; set; } = String.Empty;
public string Introduction { get; set; } = String.Empty;
public string EMail { get; set; } = String.Empty;
public string WeChat { get; set; } = String.Empty;
public int Nation { get; set; }
}
public class DoctorBasicInfoCommand : DoctorBasicInfo
{
//职称
public List<Guid> TitleIds { get; set; } = new List<Guid>();
}
public class TempObj
{
public int ShowOrder { get; set; }
public Guid TitleId { get; set; }
public string TitleCN { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
}
public class DicView
{
public int ShowOrder { get; set; }
public Guid Id { get; set; }
public string ValueCN { get; set; } = string.Empty;
public string ParentCode { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
}
public class DoctorBasicInfoDTO : DoctorBasicInfo
{
public List<DicView> DoctorDicViewDtos = new List<DicView>();
//职称
public List<Guid> TitleIds => DoctorDicViewDtos.Select(t => t.Id).ToList();
public List<string> TitleList=> DoctorDicViewDtos.Select(t => t.Value).ToList();
public List<string> TitleCNList=> DoctorDicViewDtos.Select(t => t.ValueCN).ToList();
#region ef select
//[JsonIgnore]
//public List<TempObj> TempObjList { get; set; }
////职称
//public List<Guid> TitleIds
//{
// get
// {
// if (TempObjList.Count > 0)
// {
// return TempObjList.Select(t => t.TitleId).ToList();
// }
// else
// {
// return new List<Guid>();
// }
// }
//}
//public List<string> TitleList
//{
// get
// {
// if (TempObjList.Count > 0)
// {
// return TempObjList.Select(t => t.Title).ToList();
// }
// else
// {
// return new List<string>();
// }
// }
//}
//public List<string> TitleCNList
//{
// get
// {
// if (TempObjList.Count > 0)
// {
// return TempObjList.Select(t => t.TitleCN).ToList();
// }
// else
// {
// return new List<string>();
// }
// }
//}
#endregion
}
public class SowDTO
{
public string FileName { get; set; } = string.Empty;
public string TrialCode { get; set; } = string.Empty;
public string FilePath { get; set; } = string.Empty;
public string FullPath { get { return FilePath; } }
public DateTime CreateTime { get; set; }
}
#endregion
#region
//public class DoctorHospitalView
//{
// public string HospitalName { get; set; }
// public string UniversityAffiliated { get; set; }
// public string Country { get; set; }
// public string Province { get; set; }
// public string City { get; set; }
// public string HospitalNameCN { get; set; }
// public string UniversityAffiliatedCN { get; set; }
// public string CountryCN { get; set; }
// public string ProvinceCN { get; set; }
// public string CityCN { get; set; }
//}
public class EmploymentDTO : EmploymentInfo
{
//public DoctorHospitalView Hospital { get; set; }
public string Department { get; set; } = String.Empty;
public string Rank { get; set; } = String.Empty;
public string Position { get; set; } = String.Empty;
#region
public string HospitalName { get; set; } = String.Empty;
public string UniversityAffiliated { get; set; } = String.Empty;
public string Country { get; set; } = String.Empty;
public string Province { get; set; } = String.Empty;
public string City { get; set; } = String.Empty;
#endregion
public string DepartmentCN { get; set; } = String.Empty;
public string RankCN { get; set; } = String.Empty;
public string PositionCN { get; set; } = String.Empty;
public string HospitalNameCN { get; set; } = String.Empty;
public string UniversityAffiliatedCN { get; set; } = String.Empty;
public string CountryCN { get; set; } = String.Empty;
public string ProvinceCN { get; set; } = String.Empty;
public string CityCN { get; set; } = String.Empty;
}
public class EmploymentCommand : EmploymentInfo
{
}
public class EmploymentInfo
{
public Guid Id { get; set; }
//部门
public Guid? DepartmentId { get; set; } = Guid.Empty;
public string DepartmentOther { get; set; } = string.Empty;
public string DepartmentOtherCN { get; set; } = string.Empty;
//职称
public Guid? RankId { get; set; } = Guid.Empty;
public string RankOther { get; set; } = string.Empty;
public string RankOtherCN { get; set; } = string.Empty;
//职位 主席 副主席
public Guid? PositionId { get; set; } = Guid.Empty;
public string PositionOther { get; set; } = string.Empty;
public string PositionOtherCN { get; set; } = string.Empty;
public Guid? HospitalId { get; set; } = Guid.Empty;
}
#endregion
#region Specialty模型
public class SpecialtyDTO : SpecialtyCommand
{
[JsonIgnore]
public List<DicView> DictionaryList { get; set; } = new List<DicView>();
public string Speciality { get; set; } = string.Empty;
//临床实践中使用的模式
public new List<Guid> ReadingTypeIds
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).Select(t => t.Id).ToList();
}
else
{
return new List<Guid>();
}
}
}
public new List<Guid> SubspecialityIds
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).Select(t => t.Id).ToList();
}
else
{
return new List<Guid>();
}
}
}
public List<string> ReadingTypeList
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).Select(t => t.Value).ToList();
}
else
{
return new List<string>();
}
}
}
public List<string> SubspecialityList
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).Select(t => t.Value).ToList();
}
else
{
return new List<string>();
}
}
}
public List<string> ReadingTypeCNList
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.ReadingType).Select(t => t.ValueCN).ToList();
}
else
{
return new List<string>();
}
}
}
public List<string> SubspecialityCNList
{
get
{
if (DictionaryList.Count > 0)
{
return DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).Select(t => t.ValueCN).ToList();
}
else
{
return new List<string>();
}
}
}
}
public class SpecialtyCommand
{
public List<Guid> ReadingTypeIds { get; set; } = new List<Guid>();
public List<Guid> SubspecialityIds { get; set; } = new List<Guid>();
public Guid Id { get; set; }
public string OtherSkills { get; set; } = string.Empty;
public string ReadingTypeOther { get; set; } = string.Empty;
public string ReadingTypeOtherCN { get; set; } = string.Empty;
//亚专科
public string SubspecialityOther { get; set; } = string.Empty;
public string SubspecialityOtherCN { get; set; } = string.Empty;
public Guid? SpecialityId { get; set; } = Guid.Empty;
public string SpecialityCN { get; set; } = string.Empty;
public string SpecialityOther { get; set; } = string.Empty;
public string SpecialityOtherCN { get; set; } = string.Empty;
}
#endregion
#region
public class DoctorAccountLoginDTO
{
public string Phone { get; set; } = String.Empty;
public string Password { get; set; } = String.Empty;
}
public class DoctorAccountDTO
{
public Guid Id { get; set; }
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string Phone { get; set; } = String.Empty;
public string PhotoPath { get; set; } = String.Empty;
}
public class DoctorAccountUpdatePasswordCommand
{
public string Phone { get; set; } = String.Empty;
public string OldPassword { get; set; } = String.Empty;
public string NewPassword { get; set; } = String.Empty;
}
#endregion
#region
public class ResumeConfirmCommand
{
//int userId, int doctorId, int status, string memo
//public Guid FromUserId { get; set; }
public Guid Id { get; set; }
public ResumeStatusEnum ResumeStatus { get; set; }
public int ReviewStatus { get; set; }
public bool AcceptingNewTrial { get; set; } = false;
public bool ActivelyReading { get; set; } = false;
public string AdminComment { get; set; } = String.Empty;
public string MessageContent { get; set; } = String.Empty;
public ContractorStatusEnum CooperateStatus { get; set; }
}
public class ResumeConfirmDTO
{
public Guid Id { get; set; }
public int CooperateStatus { get; set; }
public int ResumeStatus { get; set; }
public int ReviewStatus { get; set; } //复审状态
public bool AcceptingNewTrial { get; set; }
public bool ActivelyReading { get; set; }
public string AdminComment { get; set; } = String.Empty;
public bool InHoliday { get; set; }
}
#endregion
public class TrialPaymentPriceQueryDTO : PageInput
{
public string KeyWord { get; set; } = String.Empty;
public Guid? CroId { get; set; }
}
public class DoctorPaymentInfoQueryDTO : PageInput
{
public string SearchName { get; set; } = String.Empty;
public Guid? HospitalId { get; set; }
}
}
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
namespace IRaCIS.Application.Contracts
{
public class EducationCommand
{
public Guid? Id { get; set; }
public Guid DoctorId { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public string Degree { get; set; } = String.Empty;
public string Major { get; set; } = String.Empty;
public string Organization { get; set; } = String.Empty;
public string Country { get; set; } = String.Empty;
public string Province { get; set; } = String.Empty;
public string City { get; set; } = String.Empty;
public string DegreeCN { get; set; } = String.Empty;
public string MajorCN { get; set; } = String.Empty;
public string OrganizationCN { get; set; } = String.Empty;
public string CountryCN { get; set; } = String.Empty;
public string ProvinceCN { get; set; } = String.Empty;
public string CityCN { get; set; } = String.Empty;
}
public class EducationInfoViewModel : EducationCommand
{
public DateTime? CreateTime { get; set; }
public string BeginDateStr => BeginDate.ToString("yyyy-MM");
public string EndDateStr => EndDate.ToString("yyyy-MM");
}
public class PostgraduateCommand
{
public Guid? Id { get; set; }
public Guid DoctorId { get; set; }
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public string Training { get; set; } = String.Empty;
public string Major { get; set; } = String.Empty;
public string Hospital { get; set; } = String.Empty;
public string School { get; set; } = String.Empty;
public string Country { get; set; } = String.Empty;
public string Province { get; set; } = String.Empty;
public string City { get; set; } = String.Empty;
public string TrainingCN { get; set; } = String.Empty;
public string MajorCN { get; set; } = String.Empty;
public string HospitalCN { get; set; } = String.Empty;
public string SchoolCN { get; set; } = String.Empty;
public string CountryCN { get; set; } = String.Empty;
public string ProvinceCN { get; set; } = String.Empty;
public string CityCN { get; set; } = String.Empty;
}
public class PostgraduateViewModel: PostgraduateCommand
{
public DateTime? CreateTime { get; set; }
public string BeginDateStr => BeginDate.ToString("yyyy-MM");
public string EndDateStr => EndDate.ToString("yyyy-MM");
}
public class DoctorEducationExperienceDTO
{
public IEnumerable<EducationInfoViewModel> EducationList=new List<EducationInfoViewModel>();
public IEnumerable<PostgraduateViewModel> PostgraduateList = new List<PostgraduateViewModel>();
}
}
@@ -0,0 +1,13 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class VacationCommand
{
public Guid? Id { get; set; }
public Guid DoctorId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Status { get; set; } = 1;
}
}
@@ -0,0 +1,21 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class ResearchPublicationDTO
{
public Guid? Id { get; set; }
public Guid DoctorId { get; set; }
public string Research { get; set; } = String.Empty;
public string Grants { get; set; } = String.Empty;
public string Publications { get; set; } = String.Empty;
public string AwardsHonors { get; set; } = String.Empty;
public string ResearchCN { get; set; } = String.Empty;
public string GrantsCN { get; set; } = String.Empty;
public string PublicationsCN { get; set; } = String.Empty;
public string AwardsHonorsCN { get; set; } = String.Empty;
}
}
@@ -0,0 +1,81 @@
namespace IRaCIS.Application.Contracts
{
public class TrialExperienceCommand
{
public Guid? Id { get; set; }
public Guid DoctorId { get; set; }
public Guid? PhaseId { get; set; }
public string EvaluationContent { get; set; } = String.Empty;
//public string Term { get; set; }
//public string EvaluationCriteria { get; set; }
public List<Guid> EvaluationCriteriaIdList { get; set; } = new List<Guid>();
}
public class TrialExperienceListDTO: TrialExperienceCommand
{
public string Phase { get; set; } = String.Empty;
public List<string> EvaluationCriteriaList { get; set; } = new List<string>();
}
//public class EvaluationCriteriaDTO
//{
// public Guid EvaluationCriteriaId { get; set; }
// public string EvaluationCriteria { get; set; }
//}
public class TrialExperienceModel : GcpAndOtherExperienceDTO
{
public List<TrialExperienceListDTO> ClinicalTrialExperienceList = new List<TrialExperienceListDTO>();
public string ExpiryDateStr { get; set; } = string.Empty;
public string GCPFullPath { get; set; } = String.Empty;
}
public class GcpAndOtherExperienceDTO
{
public Guid Id { get; set; }
public int GCP { get; set; }
public Guid? GCPId { get; set; }
public string OtherClinicalExperience { get; set; }=String.Empty;
public string OtherClinicalExperienceCN { get; set; } = String.Empty;
public string Type { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
}
public class GCPExperienceCommand
{
public Guid Id { get; set; }
public int GCP { get; set; }
public Guid? GCPId { get; set; }
}
public class ClinicalExperienceCommand
{
public Guid DoctorId { get; set; }
public string OtherClinicalExperience { get; set; } = String.Empty;
public string OtherClinicalExperienceCN { get; set; } = String.Empty;
}
}
@@ -0,0 +1,211 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using System.Linq.Dynamic.Core;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Reviewer")]
public class DoctorListService : BaseService, IDoctorListQueryService
{
private readonly IRepository<Doctor> _doctorRepository;
public DoctorListService(IRepository<Doctor> doctorRepository)
{
_doctorRepository = doctorRepository;
}
/// <summary>
/// Reviewer列表分页查询
/// </summary>
[HttpPost]
public async Task<PageOutput<DoctorDTO>> GetDoctorSearchList(DoctorSearchDTO doctorSearch)
{
// 项目经验 多选
var evaluationCriteriaCount = doctorSearch.EvaluationCriteriaIdList.Count();
// 搜索条件 ReadingType 、Subspeciality、Title 多选
var count = doctorSearch.ReadingTypeIdList.Count + doctorSearch.TitleIdList.Count + doctorSearch.SubspecialityIdList.Count;
var guidList = doctorSearch.ReadingTypeIdList.Concat(doctorSearch.SubspecialityIdList).Concat(doctorSearch.TitleIdList);
var query = _doctorRepository.AsQueryable()
.WhereIf(doctorSearch.DepartmentId != null, t => t.DepartmentId == doctorSearch.DepartmentId)
.WhereIf(doctorSearch.SpecialityId != null, t => t.SpecialityId == doctorSearch.SpecialityId)
.WhereIf(doctorSearch.HospitalId != null, t => t.HospitalId == doctorSearch.HospitalId)
.WhereIf(doctorSearch.PositionId != null, t => t.PositionId == doctorSearch.PositionId)
.WhereIf(doctorSearch.RankId != null, t => t.RankId == doctorSearch.RankId)
.WhereIf(doctorSearch.ContractorStatus != null, t => t.CooperateStatus == doctorSearch.ContractorStatus)
.WhereIf(doctorSearch.InformationConfirmed != null, t => t.ResumeStatus == doctorSearch.InformationConfirmed)
.WhereIf(doctorSearch.AcceptingNewTrial != null, t => t.AcceptingNewTrial == doctorSearch.AcceptingNewTrial)
.WhereIf(!string.IsNullOrWhiteSpace(doctorSearch.Name), t => t.ChineseName.Contains(doctorSearch.Name) || (t.LastName + t.FirstName).Contains(doctorSearch.Name))
.WhereIf(doctorSearch.Nation != null, t => t.Nation == doctorSearch.Nation)
.WhereIf(evaluationCriteriaCount > 0, t => t.TrialExperienceCriteriaList.Count(t => doctorSearch.EvaluationCriteriaIdList.Contains(t.EvaluationCriteriaId)) == evaluationCriteriaCount)
//用户类型 看到简历的范围这里需要确认
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ReviewerCoordinator, t => t.UserList.Any(u => u.UserId == _userInfo.Id))
.WhereIf(count > 0, t => t.DoctorDicRelationList.Count(u => guidList.Contains(u.DictionaryId)) == count)
.WhereIf(doctorSearch.EnrollStatus != null && doctorSearch.EnrollStatus == (int)ReviewerEnrollStatus.Yes, t => t.EnrollList.Any(u => u.EnrollStatus == (int)EnrollStatus.DoctorReading))
.ProjectTo<DoctorDTO>(_mapper.ConfigurationProvider);
return await query.ToPagedListAsync(doctorSearch.PageIndex, doctorSearch.PageSize, doctorSearch.SortField == string.Empty ? "CreateTime" : doctorSearch.SortField, doctorSearch.Asc);
}
#region
/// <summary>
/// 获取可筛选筛选及已经筛选的医生列表
/// </summary>
[HttpPost]
public async Task<PageOutput<SelectionReviewerDTO>> GetSelectionReviewerList(
ReviewerSelectionQueryDTO selectionQuery)
{
//项目配置需要的医生过滤 2表示混合
var nation = await _repository.Where<Trial>(s => s.Id == selectionQuery.TrialId).Select(t=>t.AttendedReviewerType).FirstOrDefaultAsync().IfNullThrowException();
// 临床项目经验 多选
var evaluationCriteriaCount = selectionQuery.EvaluationCriteriaIdList.Count();
// 搜索条件 ReadingType 、Subspeciality、Title 多选
var count = selectionQuery.ReadingTypeIdList.Count + selectionQuery.TitleIdList.Count + selectionQuery.SubspecialityIdList.Count;
var guidList = selectionQuery.ReadingTypeIdList.Concat(selectionQuery.SubspecialityIdList).Concat(selectionQuery.TitleIdList);
var query = _doctorRepository.WhereIf(nation != 2, t => t.Nation == nation)
.WhereIf(selectionQuery.DepartmentId != null, t => t.DepartmentId == selectionQuery.DepartmentId)
.WhereIf(selectionQuery.SpecialityId != null, t => t.SpecialityId == selectionQuery.SpecialityId)
.WhereIf(selectionQuery.HospitalId != null, t => t.HospitalId == selectionQuery.HospitalId)
.WhereIf(selectionQuery.PositionId != null, t => t.PositionId == selectionQuery.PositionId)
.WhereIf(selectionQuery.RankId != null, t => t.RankId == selectionQuery.RankId)
.WhereIf(selectionQuery.ContractorStatus != null, t => t.CooperateStatus == selectionQuery.ContractorStatus)
.WhereIf(selectionQuery.InformationConfirmed != null, t => t.ResumeStatus == selectionQuery.InformationConfirmed)
.WhereIf(selectionQuery.AcceptingNewTrial != null, t => t.AcceptingNewTrial == selectionQuery.AcceptingNewTrial)
.WhereIf(!string.IsNullOrWhiteSpace(selectionQuery.Name), t => t.ChineseName.Contains(selectionQuery.Name) || (t.LastName + t.FirstName).Contains(selectionQuery.Name))
.WhereIf(evaluationCriteriaCount > 0, t => t.TrialExperienceCriteriaList.Count(t => selectionQuery.EvaluationCriteriaIdList.Contains(t.EvaluationCriteriaId)) == evaluationCriteriaCount)
//用户类型 看到简历的范围这里需要确认
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ReviewerCoordinator, t => t.UserList.Any(u => u.UserId == _userInfo.Id))
.WhereIf(count > 0, t => t.DoctorDicRelationList.Count(u => guidList.Contains(u.DictionaryId)) == count)
.WhereIf(selectionQuery.EnrollStatus != null && selectionQuery.EnrollStatus == (int)ReviewerEnrollStatus.Yes, t => t.EnrollList.Any(u => u.EnrollStatus == (int)EnrollStatus.DoctorReading))
.ProjectTo<SelectionReviewerDTO>(_mapper.ConfigurationProvider);
var result = await query.ToPagedListAsync(selectionQuery.PageIndex, selectionQuery.PageSize, selectionQuery.SortField == string.Empty ? "ReviewerCode" : selectionQuery.SortField, selectionQuery.Asc);
//是否已申请 申请时间 申请人
var doctorStateList = await _repository.Where<EnrollDetail>(x => x.TrialId == selectionQuery.TrialId && x.EnrollStatus == (int)EnrollStatus.HasApplyDownloadResume)
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
result.CurrentPageData.ToList().ForEach(doctor =>
{
//简历申请列表 --处理已经申请的
var doctorState = doctorStateList.FirstOrDefault(t => t.DoctorId == doctor.Id && t.IntoGroupState == (int)EnrollStatus.HasApplyDownloadResume);
if (doctorState != null)
{
doctor.DoctorTrialState = (int)EnrollStatus.HasApplyDownloadResume;
doctor.OptTime = doctorState.OptTime;
doctor.OptUserName = doctorState.OptUserName;
}
});
return result;
}
/// <summary>
/// 获取提交CRO或者CRO审核的Reviewer列表
/// </summary>
/// <summary>
/// 根据状态获取医生列表,入组 相关接口 (提交CRO-1) CRO确认-4
/// </summary>
[HttpPost]
public async Task<PageOutput<ConfirmationReviewerDTO>> GetSubmissionOrApprovalReviewerList(
ReviewerSubmissionQueryDTO param)
{
var doctorQuery = _repository.Where<Enroll>(x => x.TrialId == param.TrialId)
//提交CRO 以及下载简历列表
.WhereIf(param.IntoGroupSearchState == 1, t => t.EnrollStatus >= (int)EnrollStatus.HasApplyDownloadResume)
//CRO确认列表 状态为 已提交CRO
.WhereIf(param.IntoGroupSearchState == 4, t => t.EnrollStatus >= (int)EnrollStatus.HasCommittedToCRO)
.ProjectTo<ConfirmationReviewerDTO>(_mapper.ConfigurationProvider);
var doctorPageList = await doctorQuery.ToPagedListAsync(param.PageIndex, param.PageSize, param.SortField == "" ? "Code" : param.SortField, param.Asc);
var enrollStateList = await _repository.Where<EnrollDetail>(x => x.TrialId == param.TrialId)
//提交CRO 以及下载简历列表
.WhereIf(param.IntoGroupSearchState == 1, t => t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO)
//CRO确认列表 状态为 已提交CRO
.WhereIf(param.IntoGroupSearchState == 4, t => t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup)
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
doctorPageList.CurrentPageData.ToList().ForEach(u =>
{
var opt = enrollStateList.FirstOrDefault(t => t.DoctorId == u.Id);
if (opt != null)
{
u.DoctorTrialState = param.IntoGroupSearchState == 1 ? (int)EnrollStatus.HasCommittedToCRO : (int)EnrollStatus.InviteIntoGroup;
u.OptTime = opt.OptTime;
u.OptUserName = opt.OptUserName;
}
});
return doctorPageList;
}
/// <summary>
/// 获取项目下医生入组状态列表[Confirmation]
/// </summary>
[HttpPost]
public async Task<PageOutput<ConfirmationReviewerDTO>> GetConfirmationReviewerList(
ReviewerConfirmationQueryDTO param)
{
var doctorQuery = _repository.Where<Enroll>(x => x.TrialId == param.TrialId && x.EnrollStatus >= (int)EnrollStatus.InviteIntoGroup)
.ProjectTo<ConfirmationReviewerDTO>(_mapper.ConfigurationProvider);
var doctorPageList = await doctorQuery.ToPagedListAsync(param.PageIndex, param.PageSize, param.SortField == "" ? "Code" : param.SortField, param.Asc);
var enrollStateList = await _repository.Where<EnrollDetail>(x => x.TrialId == param.TrialId && x.EnrollStatus > (int)EnrollStatus.InviteIntoGroup)
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
doctorPageList.CurrentPageData.ToList().ForEach(u =>
{
u.DoctorTrialState = (int)EnrollStatus.InviteIntoGroup;
var opt = enrollStateList.FirstOrDefault(t => t.DoctorId == u.Id);
if (opt != null)
{
u.DoctorTrialState = opt.IntoGroupState;
u.OptTime = opt.OptTime;
u.OptUserName = opt.OptUserName;
}
});
return doctorPageList;
}
#endregion
}
}
@@ -0,0 +1,558 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using System.Linq.Expressions;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Reviewer")]
public class DoctorService : BaseService, IDoctorService
{
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<Message> _messageRepository;
private readonly IRepository<Enroll> _enrollRepository;
private readonly IRepository<DoctorDictionary> _doctorDictionaryRepository;
private readonly IRepository<Attachment> _attachmentRepository;
private readonly IRepository<UserDoctor> _userDoctorRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<TrialPaymentPrice> _trialExtRepository;
private readonly IRepository<Vacation> _vacationRepository;
public DoctorService(IRepository<Doctor> doctorInfoRepository,
IRepository<Dictionary> dictionaryRepository,
IRepository<Message> sysMessageRepository, IRepository<Enroll> intoGroupRepository,
IRepository<DoctorDictionary> doctorDictionaryRepository,
IRepository<Attachment> attachmentRepository,
IRepository<UserDoctor> userDoctorRepository,
IRepository<Trial> trialRepository,
IRepository<TrialPaymentPrice> trialExtRepository, IRepository<Vacation> vacationRepository)
{
_doctorRepository = doctorInfoRepository;
_messageRepository = sysMessageRepository;
_enrollRepository = intoGroupRepository;
_doctorDictionaryRepository = doctorDictionaryRepository;
_attachmentRepository = attachmentRepository;
_userDoctorRepository = userDoctorRepository;
_trialRepository = trialRepository;
_trialExtRepository = trialExtRepository;
_vacationRepository = vacationRepository;
}
#region --
/// <summary>
/// 添加/更新 医生基本信息 BasicInfo
/// </summary>
[HttpPost]
public async Task<IResponseOutput<DoctorBasicInfoCommand>> AddOrUpdateDoctorBasicInfo(DoctorBasicInfoCommand basicInfoModel)
{
Expression<Func<Doctor, bool>> verifyExp = t => t.Phone == basicInfoModel.Phone || t.EMail == basicInfoModel.EMail;
var verifyPair = new KeyValuePair<Expression<Func<Doctor, bool>>, string>(verifyExp, "current phone or email number already existed");
if (basicInfoModel.Id == Guid.Empty || basicInfoModel.Id == null)
{
var doctor = _mapper.Map<Doctor>(basicInfoModel);
//验证用户手机号
if (await _doctorRepository.AnyAsync(t => t.Phone == doctor.Phone))
{
return ResponseOutput.NotOk("The current phone number already existed!", new DoctorBasicInfoCommand());
}
if (await _doctorRepository.AnyAsync(t => t.EMail == doctor.EMail))
{
return ResponseOutput.NotOk("The current email already existed!", new DoctorBasicInfoCommand());
}
doctor.Code = await _repository.GetQueryable<Doctor>().MaxAsync(t => t.Code) + 1;
doctor.ReviewerCode = AppSettings.CodePrefix + doctor.Code.ToString("D4");
doctor.Password = MD5Helper.Md5(doctor.Phone);
//插入中间表
basicInfoModel.TitleIds.ForEach(titleId => doctor.DoctorDicRelationList.Add(new DoctorDictionary() { DoctorId = doctor.Id, KeyName = StaticData.Title, DictionaryId = titleId }));
await _doctorRepository.AddAsync(doctor);
//_doctorRepository.Add(doctor);
await _repository.AddAsync(new UserDoctor() { DoctorId = doctor.Id, UserId = _userInfo.Id });
//_userDoctorRepository.Add(new UserDoctor() { DoctorId = doctor.Id, UserId = _userInfo.Id });
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, _mapper.Map<DoctorBasicInfoCommand>(doctor));
}
else
{
var updateModel = basicInfoModel;
var phone = updateModel.Phone.Trim();
if ((await _doctorRepository.FirstOrDefaultAsync(t => t.Phone == phone && t.Id != updateModel.Id) )!= null)
{
return ResponseOutput.NotOk("The current phone number already existed!", new DoctorBasicInfoCommand());
}
var email = updateModel.EMail.Trim();
if (await _doctorRepository.AnyAsync(t => t.EMail == email && t.Id != updateModel.Id))
{
return ResponseOutput.NotOk("The current email already existed!", new DoctorBasicInfoCommand());
}
var doctor = await _doctorRepository.FirstOrDefaultAsync(t => t.Id == updateModel.Id).IfNullThrowException();
//删除中间表 Title对应的记录
await _repository.DeleteFromQueryAsync<DoctorDictionary>(t => t.DoctorId == updateModel.Id && t.KeyName == StaticData.Title);
var adddata=new List<DoctorDictionary>();
//重新插入新的 Title记录
updateModel.TitleIds.ForEach(titleId => adddata.Add(new DoctorDictionary() { DoctorId = updateModel.Id.Value, KeyName = StaticData.Title, DictionaryId = titleId }));
await _repository.AddRangeAsync(adddata);
_mapper.Map(basicInfoModel, doctor);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, basicInfoModel);
}
}
/// <summary>
///详情、编辑-获取 医生基本信息 BasicInfo
/// </summary>
/// <param name="doctorId">ReviewerID</param>
/// <returns></returns>
[HttpGet("{doctorId:guid}")]
public async Task<DoctorBasicInfoDTO> GetBasicInfo(Guid doctorId)
{
#region
//SELECT[t].[Id], [t].[Code], [t].[ChineseName], [t].[EMail], [t].[FirstName], [t].[Introduction], [t].[LastName], [t].[Phone], [t].[Sex], [t].[WeChat], [t].[Nation], [t0].[Title], [t0].[TitleCN], [t0].[TitleId], [t0].[ShowOrder], [t0].[Id], [t0].[Id0]
//FROM(
// SELECT TOP(1)[d].[Id], [d].[Code], [d].[ChineseName], [d].[EMail], [d].[FirstName], [d].[Introduction], [d].[LastName], [d].[Phone], [d].[Sex], [d].[WeChat], [d].[Nation]
// FROM[Doctor] AS[d] WITH(NOLOCK)
// WHERE[d].[Id] = @__doctorId_0
//) AS[t]
//LEFT JOIN(
// SELECT[d1].[Value] AS[Title], [d1].[ValueCN] AS[TitleCN], [d0].[DictionaryId] AS[TitleId], [d1].[ShowOrder], [d0].[Id], [d1].[Id] AS[Id0], [d0].[DoctorId]
// FROM [DoctorDictionary] AS [d0] WITH (NOLOCK)
// INNER JOIN[Dictionary] AS [d1] WITH (NOLOCK) ON [d0].[DictionaryId] = [d1].[Id]
// WHERE[d0].[KeyName] = N'Title'
//) AS[t0] ON[t].[Id] = [t0].[DoctorId]
//ORDER BY[t].[Id], [t0].[ShowOrder], [t0].[Id]
//var doctorQueryable = _doctorRepository
// .Find(t => t.Id == doctorId)
// .Select(doctor => new DoctorBasicInfoDTO()
// {
// Id = doctor.Id,
// Code = doctor.Code,
// ChineseName = doctor.ChineseName,
// EMail = doctor.EMail,
// FirstName = doctor.FirstName,
// Introduction = doctor.Introduction,
// LastName = doctor.LastName,
// Phone = doctor.Phone,
// Sex = doctor.Sex,
// WeChat = doctor.WeChat,
// Nation = doctor.Nation,
// //不要分三个属性查询,会做三次左连接,这样 只会一个左连接
// TempObjList = doctor.DoctorDicList.Where(t => t.KeyName == StaticData.Title)
// .Select(t => new TempObj { Title = t.Dictionary.Value, TitleCN = t.Dictionary.ValueCN, TitleId = t.DictionaryId, ShowOrder = t.Dictionary.ShowOrder }).OrderBy(k => k.ShowOrder).ToList(),
// });
//var doctorBasicInfo = doctorQueryable.FirstOrDefault();
#endregion
var doctorBasicInfo = (await _doctorRepository.Where(t => t.Id == doctorId)
.ProjectTo<DoctorBasicInfoDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
return doctorBasicInfo;
}
#endregion
#region Employment信息--
/// <summary>
/// 详情、编辑-获取医生工作信息 Employment
/// </summary>
[HttpGet("{doctorId:Guid}")]
public async Task<EmploymentDTO> GetEmploymentInfo(Guid doctorId)
{
#region init EF select
//var dic = GetDictionary();
//var employmentQueryable = from doctorItem in _doctorRepository
// .Where(t => t.Id == doctorId)
// join hospitalItem in _hospitalRepository.AsQueryable() on doctorItem.HospitalId equals hospitalItem.Id into g
// from hospital in g.DefaultIfEmpty()
// select new EmploymentDTO()
// {
// Id = doctorItem.Id,
// //部门
// DepartmentId = doctorItem.DepartmentId,
// DepartmentOther = doctorItem.DepartmentOther,
// DepartmentOtherCN = doctorItem.DepartmentOtherCN,
// //医院
// HospitalId = doctorItem.HospitalId,
// PositionId = doctorItem.PositionId,
// PositionOther = doctorItem.PositionOther,
// PositionOtherCN = doctorItem.PositionOtherCN,
// RankId = doctorItem.RankId,
// RankOther = doctorItem.RankOther,
// RankOtherCN = doctorItem.RankOtherCN,
// City = hospital.City,
// Country = hospital.Country,
// UniversityAffiliated = hospital.UniversityAffiliated,
// HospitalName = hospital.HospitalName,
// Province = hospital.Province,
// CityCN = hospital.CityCN,
// CountryCN = hospital.CountryCN,
// UniversityAffiliatedCN = hospital.UniversityAffiliatedCN,
// HospitalNameCN = hospital.HospitalNameCN,
// ProvinceCN = hospital.ProvinceCN
// };
//var employmentInfo = employmentQueryable.FirstOrDefault();
//if (employmentInfo != null)
//{
// //医院信息设置
// if (employmentInfo.HospitalId == Guid.Empty)
// {
// employmentInfo.City = string.Empty;
// employmentInfo.Country = string.Empty;
// employmentInfo.UniversityAffiliated = string.Empty;
// employmentInfo.HospitalName = string.Empty;
// employmentInfo.Province = string.Empty;
// }
// employmentInfo.Department = employmentInfo.DepartmentId == Guid.Empty ? employmentInfo.DepartmentOther : dic.FirstOrDefault(o => o.Id == employmentInfo.DepartmentId)?.Value ?? "";
// employmentInfo.Rank = employmentInfo.RankId == Guid.Empty ? employmentInfo.RankOther : dic.FirstOrDefault(o => o.Id == employmentInfo.RankId)?.Value ?? "";
// employmentInfo.Position = employmentInfo.PositionId == Guid.Empty ? employmentInfo.PositionOther : dic.FirstOrDefault(o => o.Id == employmentInfo.PositionId)?.Value ?? "";
// employmentInfo.DepartmentCN = employmentInfo.DepartmentId == Guid.Empty ? employmentInfo.DepartmentOther : dic.FirstOrDefault(o => o.Id == employmentInfo.DepartmentId)?.ValueCN ?? "";
// employmentInfo.RankCN = employmentInfo.RankId == Guid.Empty ? employmentInfo.RankOther : dic.FirstOrDefault(o => o.Id == employmentInfo.RankId)?.ValueCN ?? "";
// employmentInfo.PositionCN = employmentInfo.PositionId == Guid.Empty ? employmentInfo.PositionOther : dic.FirstOrDefault(o => o.Id == employmentInfo.PositionId)?.ValueCN ?? "";
//}
#endregion
var query = _doctorRepository.Where(t => t.Id == doctorId)
.ProjectTo<EmploymentDTO>(_mapper.ConfigurationProvider);
var employmentInfo = (await query.FirstOrDefaultAsync()).IfNullThrowException();
return employmentInfo;
}
[HttpPost]
public async Task<IResponseOutput> UpdateEmploymentInfo(EmploymentCommand doctorWorkInfoModel)
{
#region
//var success = _doctorRepository.Update(d => d.Id == doctorWorkInfoModel.Id, u => new Doctor()
//{
// DepartmentId = doctorWorkInfoModel.DepartmentId,
// DepartmentOther = doctorWorkInfoModel.DepartmentOther,
// DepartmentOtherCN = doctorWorkInfoModel.DepartmentOtherCN,
// SpecialityId = doctorWorkInfoModel.DepartmentId,
// SpecialityOther = doctorWorkInfoModel.DepartmentOther,
// SpecialityOtherCN = doctorWorkInfoModel.DepartmentOtherCN,
// RankId = doctorWorkInfoModel.RankId,
// RankOther = doctorWorkInfoModel.RankOther,
// RankOtherCN = doctorWorkInfoModel.RankOtherCN,
// PositionId = doctorWorkInfoModel.PositionId,
// PositionOther = doctorWorkInfoModel.PositionOther,
// PositionOtherCN = doctorWorkInfoModel.PositionOtherCN,
// HospitalId = doctorWorkInfoModel.HospitalId,
// UpdateTime = DateTime.Now
//});
//var doctor = _doctorRepository.FirstOrDefault(d => d.Id == doctorWorkInfoModel.Id);
//_mapper.Map(doctorWorkInfoModel, doctor);
//var success = _doctorRepository.SaveChanges();
#endregion
var entity = await _repository.InsertOrUpdateAsync<Doctor, EmploymentCommand>(doctorWorkInfoModel, true);
//_doctorRepository.UseMapper(_mapper).InsertOrUpdate(doctorWorkInfoModel, autoSave: true);
return ResponseOutput.Ok();
}
#endregion
#region
[HttpGet, Route("{doctorId:Guid}")]
public async Task<SpecialtyDTO> GetSpecialtyInfo(Guid doctorId)
{
#region sql ok
//var specialtyQueryable = _doctorRepository
// .Where(t => t.Id == doctorId).Include(u => u.DoctorDicRelationList)
// .Select(specialty => new SpecialtyDTO()
// {
// Id = specialty.Id,
// ReadingTypeOther = specialty.ReadingTypeOther,
// ReadingTypeOtherCN = specialty.ReadingTypeOtherCN,
// SubspecialityOther = specialty.SubspecialityOther,
// SubspecialityOtherCN = specialty.SubspecialityOtherCN,
// DictionaryList = specialty.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality)
// .Select(t => new SpecialtyDTO.DoctorDictionaryView() { DictionaryId = t.DictionaryId, Value = t.Dictionary.Value, ValueCN = t.Dictionary.ValueCN, ShowOrder = t.Dictionary.ShowOrder, KeyName = t.Dictionary.KeyName })
// .OrderBy(t => t.ShowOrder).ToList(),
// SpecialityId = specialty.SpecialityId,
// Speciality = specialty.Speciality.Value,
// SpecialityCN = specialty.Speciality.ValueCN,
// SpecialityOther = specialty.SpecialityOther,
// SpecialityOtherCN = specialty.SpecialityOtherCN
// });
//var specialtyInfo = specialtyQueryable.FirstOrDefault();
//return specialtyInfo;
#endregion
var test = await (_doctorRepository.Where(t => t.Id == doctorId)
.ProjectTo<SpecialtyDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
return test;
}
[HttpPost]
public async Task<IResponseOutput> UpdateSpecialtyInfo(SpecialtyCommand specialtyUpdateModel)
{
var doctor = await _doctorRepository.FirstOrDefaultAsync(t => t.Id == specialtyUpdateModel.Id);
if (doctor == null) return Null404NotFound(doctor);
////删除中间表
//_doctorDictionaryRepository.Delete(t =>
// t.DoctorId == specialtyUpdateModel.Id && t.KeyName == StaticData.Subspeciality);
//_doctorDictionaryRepository.Delete(t =>
// t.DoctorId == specialtyUpdateModel.Id && t.KeyName == StaticData.ReadingType);
await _repository.DeleteFromQueryAsync<DoctorDictionary>(t =>
t.DoctorId == specialtyUpdateModel.Id && (t.KeyName == StaticData.Subspeciality || t.KeyName == StaticData.ReadingType));
//重新插入新的
var adddata = new List<DoctorDictionary>();
specialtyUpdateModel.ReadingTypeIds.ForEach(readingTypeId => adddata.Add(
new DoctorDictionary()
{
DoctorId = specialtyUpdateModel.Id,
KeyName = StaticData.ReadingType,
DictionaryId = readingTypeId
}));
specialtyUpdateModel.SubspecialityIds.ForEach(subspecialityId => adddata.Add(
new DoctorDictionary()
{
DoctorId = specialtyUpdateModel.Id,
KeyName = StaticData.Subspeciality,
DictionaryId = subspecialityId
}));
await _repository.AddRangeAsync(adddata);
_mapper.Map(specialtyUpdateModel, doctor);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
#endregion
#region
[HttpPost]
public async Task<IResponseOutput> UpdateAuditResume(ResumeConfirmCommand auditResumeParam)
{
var userId = _userInfo.Id;
//判断 合作协议、正式简历 是否有。如果没有,显示提示信息,并且不能保存
var attachmentList = await _repository.GetQueryable<Attachment>().Where(u => u.DoctorId == auditResumeParam.Id)
.Select(u => u.Type).ToListAsync();
if (auditResumeParam.ResumeStatus == ResumeStatusEnum.Pass && ((!attachmentList.Contains("Resume")) || (!attachmentList.Contains("Consultant Agreement"))))
{
return ResponseOutput.NotOk("Resume & Consultant Agreement must be upload ");
}
var success = await _doctorRepository.UpdateFromQueryAsync(o => o.Id == auditResumeParam.Id, u => new Doctor()
{
CooperateStatus = auditResumeParam.CooperateStatus,
ResumeStatus = auditResumeParam.ResumeStatus,
AdminComment = auditResumeParam.AdminComment,
ReviewStatus = auditResumeParam.ReviewStatus,
AcceptingNewTrial = auditResumeParam.AcceptingNewTrial,
ActivelyReading = auditResumeParam.ActivelyReading,
AuditTime = DateTime.Now,
AuditUserId = userId
});
if (success)
{
if (!string.IsNullOrWhiteSpace(auditResumeParam.MessageContent))
{
var message = new Message
{
FromUserId = userId,
ToDoctorId = auditResumeParam.Id,
Title = "Resume review results",
Content = auditResumeParam.MessageContent,
HasRead = false,
MessageTime = DateTime.Now
};
await _repository.AddAsync(message);
success = await _repository.SaveChangesAsync();
}
}
return ResponseOutput.Result(success);
}
[HttpGet("{doctorId:guid}")]
public async Task<ResumeConfirmDTO> GetAuditState(Guid doctorId)
{
var doctor = (await _doctorRepository
.ProjectTo<ResumeConfirmDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync(t => t.Id == doctorId)).IfNullThrowException();
doctor.InHoliday = (await _repository.CountAsync<Vacation>(x=>x.DoctorId==doctorId&&x.EndDate<=DateTime.Now&&x.StartDate<=DateTime.Now)) > 0;
return doctor;
}
/// <summary>
/// 获取医生入组信息 正在提交的数量 已同意入组项目个数 正在读的
/// </summary>
[HttpPost, Route("{doctorId:guid}")]
public DoctorEnrollInfoDTO GetDoctorIntoGroupInfo(Guid doctorId)
{
var doctorQueryable =
from doctor in _doctorRepository.Where(t => t.Id == doctorId)
join intoGroupItem in _enrollRepository.AsQueryable() on doctor.Id equals intoGroupItem.DoctorId
into t
from intoGroupItem in t.DefaultIfEmpty()
group intoGroupItem by intoGroupItem.DoctorId
into g
select new DoctorEnrollInfoDTO
{
DoctorId = g.Key,
//Submitted = g.Sum(t =>
// t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO ? 1 : 0),
//Approved = g.Sum(t =>
// t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup ? 1 : 0),
//Reading = g.Sum(t =>
// t.EnrollStatus == (int)EnrollStatus.DoctorReading ? 1 : 0)
Submitted = g.Count(t =>
t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO),
Approved = g.Count(t =>
t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup),
Reading = g.Count(t =>
t.EnrollStatus == (int)EnrollStatus.DoctorReading)
};
return doctorQueryable.FirstOrDefault().IfNullThrowException();
}
/// <summary>
/// Get Statement of Work list.[New]
/// </summary>
[HttpGet("{doctorId:guid}")]
public List<SowDTO> GetDoctorSowList(Guid doctorId)
{
var query = from enroll in _enrollRepository.Where(u => u.DoctorId == doctorId && u.EnrollStatus >= 10)
join trialExt in _trialExtRepository.AsQueryable() on enroll.TrialId equals trialExt.TrialId
join trial in _trialRepository.AsQueryable() on enroll.TrialId equals trial.Id
select new SowDTO
{
FileName = trialExt.SowName,
FilePath = trialExt.SowPath,
TrialCode = trial.TrialCode,
CreateTime = trialExt.CreateTime
};
return query.ToList().Where(u => !string.IsNullOrWhiteSpace(u.FileName)).ToList();
}
/// <summary>
/// Get Ack Statement of Work[New]
/// </summary>
[HttpGet("{doctorId:guid}")]
public List<SowDTO> GetDoctorAckSowList(Guid doctorId)
{
var query = from enroll in _enrollRepository.Where(u => u.DoctorId == doctorId)
join attachment in _attachmentRepository.Where(u => u.DoctorId == doctorId)
on enroll.AttachmentId equals attachment.Id
join trial in _trialRepository.AsQueryable() on enroll.TrialId equals trial.Id
select new SowDTO
{
FileName = attachment.FileName,
FilePath = attachment.Path,
TrialCode = trial.TrialCode,
CreateTime = attachment.CreateTime
};
return query.ToList();
}
#endregion
}
}
@@ -0,0 +1,140 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Reviewer")]
public class EducationService : BaseService, IEducationService
{
private readonly IRepository<Postgraduate> _postgraduateRepository;
private readonly IRepository<Education> _educationRepository;
public EducationService(IRepository<Education> doctorNormalEducationRepository,
IRepository<Postgraduate> doctorContinueLearningRepository)
{
_educationRepository = doctorNormalEducationRepository;
_postgraduateRepository = doctorContinueLearningRepository;
}
/// <summary>
/// 根据医生Id获取医生教育经历和继续学习经历列表
/// </summary>
[HttpGet("{doctorId:Guid}")]
public async Task<DoctorEducationExperienceDTO> GetEducation(Guid doctorId)
{
var educationList = await _educationRepository.Where(o => o.DoctorId == doctorId)
.OrderBy(t => t.CreateTime).ProjectTo<EducationInfoViewModel>(_mapper.ConfigurationProvider).ToListAsync();
var postgraduateList = await _repository.GetQueryable<Postgraduate>().Where(o => o.DoctorId == doctorId)
.OrderBy(t => t.CreateTime).ProjectTo<PostgraduateViewModel>(_mapper.ConfigurationProvider).ToListAsync();
return new DoctorEducationExperienceDTO()
{
EducationList = educationList,
PostgraduateList = postgraduateList
};
}
/// <summary>
/// 新增医生教育经历
/// </summary>
/// <param name="educationInfoViewModel"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateEducationInfo(EducationCommand educationInfoViewModel)
{
if (educationInfoViewModel.Id == Guid.Empty || educationInfoViewModel.Id == null)
{
var doctorEducationInfo = _mapper.Map<Education>(educationInfoViewModel);
switch (educationInfoViewModel.Degree)
{
case StaticData.Bachelor:
doctorEducationInfo.ShowOrder = 1;
break;
case StaticData.Master:
doctorEducationInfo.ShowOrder = 2;
break;
case StaticData.Doctorate:
doctorEducationInfo.ShowOrder = 3;
break;
}
await _educationRepository.AddAsync(doctorEducationInfo);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, doctorEducationInfo.Id.ToString());
}
else
{
var needUpdate = await _educationRepository.FirstOrDefaultAsync(t => t.Id == educationInfoViewModel.Id);
if (needUpdate == null) return Null404NotFound(needUpdate);
_mapper.Map(educationInfoViewModel, needUpdate);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Ok(success);
}
//_educationRepository.Update(needUpdate);
}
[HttpDelete, Route("{doctorId:guid}")]
public async Task<IResponseOutput> DeleteEducationInfo(Guid id)
{
var success = await _educationRepository.DeleteFromQueryAsync(o => o.Id == id);
return ResponseOutput.Result(success);
}
/// <summary> 添加/更新医生继续学习经历</summary>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdatePostgraduateInfo(PostgraduateCommand postgraduateViewModel)
{
#region
//if (postgraduateViewModel.Id == Guid.Empty || postgraduateViewModel.Id == null)
//{
// var doctorContinueLearning = _mapper.Map<Postgraduate>(postgraduateViewModel);
// _postgraduateRepository.Add(doctorContinueLearning);
// var success = _postgraduateRepository.SaveChanges();
// return ResponseOutput.Result(success, doctorContinueLearning.Id.ToString());
//}
//else
//{
// _postgraduateRepository.Update(_mapper.Map<Postgraduate>(postgraduateViewModel));
// var success = _postgraduateRepository.SaveChanges();
// return ResponseOutput.Result(success);
//}
#endregion
var entity = await _repository.InsertOrUpdateAsync<Postgraduate, PostgraduateCommand>(postgraduateViewModel, true);
return ResponseOutput.Ok(entity.Id);
}
/// <summary>
/// 删除医生继续学习经历
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <returns></returns>
[HttpDelete("{doctorId:guid}")]
public async Task<IResponseOutput> DeletePostgraduateInfo(Guid doctorId)
{
var success = await _repository.DeleteFromQueryAsync<Postgraduate>(o => o.Id == doctorId);
return ResponseOutput.Result(success);
}
}
}
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IAttachmentService
{
Task<IEnumerable<AttachmentDTO>> SaveAttachments(IEnumerable<AttachmentDTO> attachmentList);
Task<IResponseOutput<AttachmentDTO>> AddAttachment(AttachmentDTO attachment);
Task<IResponseOutput> DeleteAttachment(AttachementCommand param);
Task<AttachmentDTO> GetDetailById(Guid attachmentId);
Task<IEnumerable<AttachmentDTO>> GetAttachmentByType(Guid doctorId, string type);
Task<IEnumerable<AttachmentDTO>> GetAttachmentByTypes(Guid doctorId, string[] types);
Task<IEnumerable<AttachmentDTO>> GetAttachments(Guid doctorId);
Task<string> GetDoctorOfficialCV(int language, Guid doctorId);
Task<IResponseOutput> SetOfficial(Guid doctorId, Guid attachmentId, int language);
Task<IResponseOutput> SetLanguage(Guid doctorId, Guid attachmentId, int language);
}
}
@@ -0,0 +1,14 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IDoctorAccountService
{
IResponseOutput Register(DoctorAccountRegisterModel doctorAccount);
DoctorAccountDTO Login(DoctorAccountLoginDTO doctorAccount);
IResponseOutput UpdatePassword(DoctorAccountUpdatePasswordCommand doctorAccount);
}
}
@@ -0,0 +1,32 @@
using IRaCIS.Application.Contracts;
namespace IRaCIS.Application.Interfaces
{
public interface IDoctorListQueryService
{
/// <summary>
/// 医生多条件查询
/// </summary>
Task<PageOutput<DoctorDTO>> GetDoctorSearchList(DoctorSearchDTO param);
/// <summary>
/// 筛选医生列表
/// </summary>
/// <param name="doctorSearchModel"></param>
/// <returns></returns>
//
Task<PageOutput<SelectionReviewerDTO>> GetSelectionReviewerList(
ReviewerSelectionQueryDTO doctorSearchModel);
/// <summary>
/// //入组 相关接口 (提交CRO-1) CRO确认-4
/// </summary>
Task<PageOutput<ConfirmationReviewerDTO>> GetSubmissionOrApprovalReviewerList(
ReviewerSubmissionQueryDTO doctorIntoGroupSearchModel);
//医生确认状态列表
Task<PageOutput<ConfirmationReviewerDTO>> GetConfirmationReviewerList(
ReviewerConfirmationQueryDTO trialIdPageModel);
}
}
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IDoctorService
{
#region
/// <summary>
/// 基本信息详情展示、编辑使用
/// </summary>
/// <param name="doctorId"></param>
/// <returns></returns>
Task<DoctorBasicInfoDTO> GetBasicInfo(Guid doctorId);
/// <summary>
/// 添加医生基本信息
/// </summary>
/// <param name="addBasicInfoParam"></param>
/// <returns></returns>
Task<IResponseOutput<DoctorBasicInfoCommand>> AddOrUpdateDoctorBasicInfo(DoctorBasicInfoCommand addBasicInfoParam);
#endregion
#region
/// <summary>
/// 获取医生 工作信息
/// </summary>
/// <param name="doctorId"></param>
/// <returns></returns>
Task<EmploymentDTO> GetEmploymentInfo(Guid doctorId);
/// <summary>
/// 更新医生 工作信息
/// </summary>
/// <param name="updateDoctorWorkInfoViewModel"></param>
/// <returns></returns>
Task<IResponseOutput> UpdateEmploymentInfo(EmploymentCommand updateDoctorWorkInfoViewModel);
#endregion
/// <summary>
/// 获取医生技能信息
/// </summary>
Task<SpecialtyDTO> GetSpecialtyInfo(Guid doctorId);
/// <summary>
/// 更新医生技能信息
/// </summary>
Task<IResponseOutput> UpdateSpecialtyInfo(SpecialtyCommand specialtyUpdateModel);
/// <summary>
/// 获取医生 审核状态
/// </summary>
Task<ResumeConfirmDTO> GetAuditState(Guid doctorId);
/// <summary>
/// 审核简历 和合作关系
/// </summary>
Task<IResponseOutput> UpdateAuditResume(ResumeConfirmCommand auditResumeParam);
/// <summary> 医生详情 入组信息 </summary>
DoctorEnrollInfoDTO GetDoctorIntoGroupInfo(Guid doctorId);
/// <summary> 获取医生参与项目的Sow协议 </summary>
List<SowDTO> GetDoctorSowList(Guid doctorId);
/// <summary> 获取医生入组的 ack Sow </summary>
List<SowDTO> GetDoctorAckSowList(Guid doctorId);
}
}
@@ -0,0 +1,26 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IEducationService
{
Task<DoctorEducationExperienceDTO> GetEducation(Guid doctorId);
#region
Task<IResponseOutput> AddOrUpdateEducationInfo(EducationCommand doctorEducationInfoViewModel);
Task<IResponseOutput> DeleteEducationInfo(Guid doctorId);
#endregion
#region
Task<IResponseOutput> AddOrUpdatePostgraduateInfo(PostgraduateCommand doctorContinueLearningViewModel);
Task<IResponseOutput> DeletePostgraduateInfo(Guid doctorId);
#endregion
}
}
@@ -0,0 +1,13 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IResearchPublicationService
{
Task<ResearchPublicationDTO> GetResearchPublication(Guid doctorId);
Task<IResponseOutput> AddOrUpdateResearchPublication(ResearchPublicationDTO param);
}
}
@@ -0,0 +1,15 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface ITrialExperienceService
{
Task<TrialExperienceModel> GetTrialExperience(Guid doctorId);
Task<IResponseOutput> AddOrUpdateTrialExperience(TrialExperienceCommand model);
Task<IResponseOutput> DeleteTrialExperience(Guid id);
Task<IResponseOutput> UpdateGcpExperience(GCPExperienceCommand model);
Task<IResponseOutput> UpdateOtherExperience(ClinicalExperienceCommand updateOtherClinicalExperience);
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IVacationService
{
Task<IResponseOutput> AddOrUpdateVacation(VacationCommand vacationViewModel);
Task<IResponseOutput> DeleteVacation(Guid id);
Task<PageOutput<VacationCommand>> GetVacationList(Guid doctorId, int pageIndex, int pageSize);
/// <summary> 判断当前时间是否在休假 </summary>
Task<IResponseOutput> OnVacation(Guid reviewerId);
}
}
@@ -0,0 +1,46 @@
using AutoMapper.QueryableExtensions;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Reviewer")]
public class ResearchPublicationService : BaseService, IResearchPublicationService
{
private readonly IRepository<ResearchPublication> researchPublicationRepository;
public ResearchPublicationService(IRepository<ResearchPublication> _researchPublicationRepository)
{
researchPublicationRepository = _researchPublicationRepository;
}
/// <summary>
/// 查询-医生科学研究信息
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <returns></returns>
[HttpGet("{doctorId:guid}")]
public async Task<ResearchPublicationDTO> GetResearchPublication(Guid doctorId)
{
var doctorScientificResearchInfo = await researchPublicationRepository.Where(o => o.DoctorId == doctorId)
.ProjectTo<ResearchPublicationDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
return doctorScientificResearchInfo;
}
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateResearchPublication(ResearchPublicationDTO param)
{
var entity = await _repository.InsertOrUpdateAsync<ResearchPublication, ResearchPublicationDTO>(param, true);
return ResponseOutput.Ok(entity.Id);
}
}
}
@@ -0,0 +1,189 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Reviewer")]
public class TrialExperienceService : BaseService, ITrialExperienceService
{
//private readonly IRepository<TrialExperience> _trialExperienceRepository;
//private readonly IRepository<Doctor> _doctorRepository;
//private readonly IRepository<Attachment> _attachmentRepository;
//private readonly IRepository<TrialExperienceCriteria> _trialExperienceCriteriaRepository;
//public TrialExperienceService(IRepository<TrialExperience> trialExperienceRepository, IRepository<Doctor> doctorRepository, IRepository<Attachment> attachmentRepository,
// IRepository<TrialExperienceCriteria> trialExperienceCriteriaRepository)
//{
// _trialExperienceRepository = trialExperienceRepository;
// _doctorRepository = doctorRepository;
// _attachmentRepository = attachmentRepository;
// _trialExperienceCriteriaRepository = trialExperienceCriteriaRepository;
//}
private IQueryable<Doctor> _doctor => _repository.GetQueryable<Doctor>();
private IQueryable<Attachment> _attachment => _repository.GetQueryable<Attachment>();
private IQueryable<TrialExperience> _trialExperience => _repository.GetQueryable<TrialExperience>();
private IQueryable<TrialExperienceCriteria> _trialExperienceCriteria => _repository.GetQueryable<TrialExperienceCriteria>();
/// <summary>
/// 根据医生Id,获取临床试验经历 界面所有数据
/// </summary>
[HttpGet("{doctorId:guid}")]
public async Task<TrialExperienceModel> GetTrialExperience(Guid doctorId)
{
var trialExperience = new TrialExperienceModel();
var doctor = await _doctor.Where(o => o.Id == doctorId)
.ProjectTo<TrialExperienceModel>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
trialExperience.ClinicalTrialExperienceList = await GetTrialExperienceList(doctorId);
if (doctor != null)
{
trialExperience.GCP = doctor.GCP;
trialExperience.Id = doctor.Id;
trialExperience.OtherClinicalExperience = doctor.OtherClinicalExperience ?? "";
trialExperience.OtherClinicalExperienceCN = doctor.OtherClinicalExperienceCN ?? "";
var attachment = await _attachment.FirstOrDefaultAsync(t => t.Id == doctor.GCPId);
if (attachment != null)
{
trialExperience.ExpiryDateStr = attachment.ExpiryDate == null ? "" : attachment.ExpiryDate.Value.ToString("yyyy-MM-dd HH:mm");
trialExperience.Path = attachment.Path;
trialExperience.GCPFullPath = attachment.Path + "?access_token=" + _userInfo.UserToken;
trialExperience.Type = attachment.Type;
trialExperience.FileName = attachment.FileName;
trialExperience.GCPId = attachment.Id;
}
}
return trialExperience;
}
private async Task<List<TrialExperienceListDTO>> GetTrialExperienceList(Guid doctorId)
{
var doctorClinicalTrialExperienceList = await _trialExperience.Where(o => o.DoctorId == doctorId).OrderBy(t => t.CreateTime)
.ProjectTo<TrialExperienceListDTO>(_mapper.ConfigurationProvider).ToListAsync();
return doctorClinicalTrialExperienceList;
}
/// <summary> 添加或更新医生临床经验列表项</summary>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateTrialExperience(TrialExperienceCommand trialExperienceViewModel)
{
if (trialExperienceViewModel.Id == Guid.Empty || trialExperienceViewModel.Id == null)
{
var trialExperience =
_mapper.Map<TrialExperience>(trialExperienceViewModel);
trialExperience = await _repository.AddAsync(trialExperience);
List<TrialExperienceCriteria> criteriaList = new List<TrialExperienceCriteria>();
trialExperienceViewModel.EvaluationCriteriaIdList.ForEach(t => criteriaList.Add(new TrialExperienceCriteria()
{
DoctorId = trialExperienceViewModel.DoctorId,
//EvaluationCriteria = t.EvaluationCriteria,
EvaluationCriteriaId = t,
TrialExperienceId = trialExperience.Id
}));
await _repository.AddRangeAsync(criteriaList);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, trialExperience.Id);
}
else
{
var needUpdate = await _trialExperience.FirstOrDefaultAsync(t => t.Id == trialExperienceViewModel.Id);
if (needUpdate == null) return Null404NotFound(needUpdate);
_mapper.Map(trialExperienceViewModel, needUpdate);
await _repository.UpdateAsync(needUpdate);
await _repository.DeleteFromQueryAsync<TrialExperienceCriteria>(t => t.TrialExperienceId == needUpdate.Id);
List<TrialExperienceCriteria> criteriaList = new List<TrialExperienceCriteria>();
trialExperienceViewModel.EvaluationCriteriaIdList.ForEach(t => criteriaList.Add(new TrialExperienceCriteria()
{
DoctorId = trialExperienceViewModel.DoctorId,
EvaluationCriteriaId = t,
TrialExperienceId = needUpdate.Id
}));
await _repository.AddRangeAsync<TrialExperienceCriteria>(criteriaList);
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, trialExperienceViewModel.Id);
}
}
/// <summary>
/// 删除临床经验
/// </summary>
[HttpDelete, Route("{doctorId:guid}")]
public async Task<IResponseOutput> DeleteTrialExperience(Guid doctorId)
{
var success = await _repository.DeleteFromQueryAsync<TrialExperience>(o => o.Id == doctorId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 更新-GCP和其他临床经验
/// </summary>
/// <param name="updateGCPExperienceParam"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> UpdateGcpExperience(GCPExperienceCommand updateGCPExperienceParam)
{
//_attachmentRepository.Delete(t => t.DoctorId == updateGCPExperienceParam.Id && t.Type == StaticData.GCP);
var successs = await _repository.UpdateFromQueryAsync<Doctor>(o => o.Id == updateGCPExperienceParam.Id, u => new Doctor()
{
GCP = updateGCPExperienceParam.GCP,
GCPId = updateGCPExperienceParam.GCP==0&&updateGCPExperienceParam.GCPId==null?Guid.Empty: updateGCPExperienceParam.GCPId!.Value
});
if (updateGCPExperienceParam.GCP == 0 && updateGCPExperienceParam.GCPId != null)
{
await _repository.DeleteFromQueryAsync<Attachment>(a => a.Id == updateGCPExperienceParam.GCPId);
}
return ResponseOutput.Result(successs, updateGCPExperienceParam.GCPId.ToString());
}
/// <summary>
/// 更新其他技能经验
/// </summary>
[HttpPost]
public async Task<IResponseOutput> UpdateOtherExperience(ClinicalExperienceCommand updateOtherClinicalExperience)
{
var success = await _repository.UpdateFromQueryAsync<Doctor>(o => o.Id == updateOtherClinicalExperience.DoctorId, u => new Doctor()
{
OtherClinicalExperience = updateOtherClinicalExperience.OtherClinicalExperience ?? string.Empty,
OtherClinicalExperienceCN = updateOtherClinicalExperience.OtherClinicalExperienceCN ?? string.Empty
});
return ResponseOutput.Result(success);
}
}
}
@@ -0,0 +1,88 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
[ ApiExplorerSettings(GroupName = "Reviewer")]
public class VacationService : BaseService, IVacationService
{
private readonly IRepository<Vacation> _vacationRepository;
public VacationService(IRepository<Vacation> vacationRepository)
{
_vacationRepository = vacationRepository;
}
/// <summary>
/// 添加休假时间段
/// </summary>
/// <param name="param">Status不传</param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateVacation(VacationCommand param)
{
if (param.Id == Guid.Empty|| param.Id ==null)
{
var result = await _vacationRepository.AddAsync(_mapper.Map<Vacation>(param));
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, result.Id);
}
else
{
var success = await _vacationRepository.UpdateFromQueryAsync(u => u.Id == param.Id,
h => new Vacation
{
StartDate = param.StartDate,
EndDate = param.EndDate
});
return ResponseOutput.Result(success);
}
}
/// <summary>
/// 删除休假时间段
/// </summary>
/// <param name="holidayId">记录Id</param>
/// <returns></returns>
[HttpDelete("{holidayId:guid}")]
public async Task<IResponseOutput> DeleteVacation(Guid holidayId)
{
var success = await _vacationRepository.DeleteFromQueryAsync(u => u.Id == holidayId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取休假时间段列表
/// </summary>
/// <returns></returns>
[HttpGet("{doctorId:guid}/{pageIndex:int}/{pageSize:int}")]
public async Task<PageOutput<VacationCommand>> GetVacationList(Guid doctorId, int pageIndex, int pageSize)
{
var query = _vacationRepository.Where(u => u.DoctorId == doctorId)
.ProjectTo<VacationCommand>(_mapper.ConfigurationProvider);
return await query.ToPagedListAsync(pageIndex, pageSize, "StartDate");
}
[NonDynamicMethod]
public async Task<IResponseOutput> OnVacation(Guid doctorId)
{
var count = await _vacationRepository.CountAsync(u => u.DoctorId == doctorId && u.EndDate >= DateTime.Now && u.StartDate <= DateTime.Now);
return ResponseOutput.Result(count > 0);
}
}
}
@@ -0,0 +1,152 @@
using AutoMapper;
using AutoMapper.EquivalencyExpression;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.Application.Service
{
public class DoctorConfig : Profile
{
public DoctorConfig()
{
#region reviewer
//基本信息 工作信息 添加时转换使用
CreateMap<DoctorBasicInfoCommand, Doctor>().EqualityComparison((odto, o) => odto.Id == o.Id);
//学习经历 添加时转换使用
CreateMap<EducationCommand, Education>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<PostgraduateCommand, Postgraduate>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<ResearchPublicationDTO, ResearchPublication>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<TrialExperienceCommand, TrialExperience>().EqualityComparison((odto, o) => odto.Id == o.Id);
//医生账户
CreateMap<DoctorAccountLoginDTO, Doctor>();
CreateMap<DoctorAccountRegisterModel, Doctor>();
CreateMap<VacationCommand, Vacation>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<AttachmentDTO, Attachment>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<ReviewerAckDTO, Attachment>().EqualityComparison((odto, o) => odto.Id == o.Id);
CreateMap<Doctor, DoctorBasicInfoCommand>();
CreateMap<Education, EducationInfoViewModel>();
CreateMap<Vacation, VacationCommand>();
CreateMap<Education, EducationInfoViewModel>();
CreateMap<ResearchPublication, ResearchPublicationDTO>();
CreateMap<Postgraduate, PostgraduateViewModel>();
CreateMap<Attachment, AttachmentDTO>();
CreateMap<Doctor, ResumeConfirmDTO>();
CreateMap<Doctor, DoctorSelectDTO>();
CreateMap<Doctor, TrialExperienceModel>();
CreateMap<TrialExperience, TrialExperienceCommand>();
CreateMap<Doctor, DoctorBasicInfo>();
#endregion
CreateMap<Dictionary, KeyNameType>();
CreateMap<Dictionary, DicViewModelDTO>();
CreateMap<AddOrUpdateDicDTO, Dictionary>().ReverseMap();
//医生列表、项目显示列表模型转换
CreateMap<DoctorDTO, SelectionReviewerDTO>();
CreateMap<User, UserBasicInfo>()
.ForMember(d => d.UserTypeShortName, u => u.MapFrom(t => t.UserTypeRole.UserTypeShortName))
.ForMember(d => d.Code, u => u.MapFrom(t => t.UserCode))
.ForMember(d => d.PermissionStr, u => u.MapFrom(t => t.UserTypeRole.PermissionStr))
.ForMember(d => d.RealName, u => u.MapFrom(user => string.IsNullOrEmpty(user.FirstName) ? user.LastName : user.LastName + " / " + user.FirstName));
CreateMap<TrialExperience, TrialExperienceListDTO>()
.ForMember(d => d.Phase, u => u.MapFrom(t => t.Phase.Value))
.ForMember(d => d.EvaluationCriteriaList, u => u.MapFrom(t => t.ExperienceCriteriaList.Select(t => t.EvaluationCriteria.Value)))
.ForMember(d => d.EvaluationCriteriaIdList, u => u.MapFrom(t => t.ExperienceCriteriaList.Select(t => t.EvaluationCriteriaId)));
CreateMap<Doctor, UserBasicInfo>()
.ForMember(d => d.Code, u => u.MapFrom(t => t.ReviewerCode))
.ForMember(d => d.RealName, u => u.MapFrom(t => t.ChineseName))
.ForMember(d => d.IsReviewer, u => u.MapFrom(t => true))
.ForMember(d => d.UserName, u => u.MapFrom(doctor => doctor.LastName + " / " + doctor.FirstName));
#region
CreateMap<Doctor, SelectionReviewerDTO>();
CreateMap<Doctor, DoctorDTO>().IncludeMembers(t => t.Hospital).Include<Doctor, SelectionReviewerDTO>()
.ForMember(d => d.Department, u => u.MapFrom(s => s.Department.Value))
.ForMember(d => d.DepartmentCN, u => u.MapFrom(s => s.Department.ValueCN))
.ForMember(d => d.Position, u => u.MapFrom(s => s.Position.Value))
.ForMember(d => d.PositionCN, u => u.MapFrom(s => s.Position.ValueCN))
.ForMember(d => d.Rank, u => u.MapFrom(s => s.Rank.Value))
.ForMember(d => d.RankCN, u => u.MapFrom(s => s.Rank.ValueCN))
.ForMember(d => d.Speciality, u => u.MapFrom(s => s.Speciality.Value))
.ForMember(d => d.SpecialityCN, u => u.MapFrom(s => s.Speciality.ValueCN))
.ForMember(d => d.HasResume, u => u.MapFrom(s => s.AttachmentList.Any(u => u.Type == "Resume" && u.IsOfficial)))
.ForMember(d => d.Submitted, u => u.MapFrom(s => s.EnrollList.Count(t => t.EnrollStatus == (int)EnrollStatus.HasCommittedToCRO)))
.ForMember(d => d.Approved, u => u.MapFrom(s => s.EnrollList.Count(t => t.EnrollStatus == (int)EnrollStatus.InviteIntoGroup)))
.ForMember(d => d.Reading, u => u.MapFrom(s => s.EnrollList.Count(t => t.EnrollStatus == (int)EnrollStatus.DoctorReading)))
.ForMember(d => d.Finished, u => u.MapFrom(s => s.EnrollList.Count(t => t.EnrollStatus == (int)EnrollStatus.Finished)))
.ForMember(d => d.Reconfirmed, u => u.MapFrom(s => s.ReviewStatus == 1))
.ForMember(o => o.DictionaryList, t => t.MapFrom(u => u.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)));
CreateMap<Hospital, DoctorDTO>();
CreateMap<EmploymentCommand, Doctor>();
//这样会左连接三次
// CreateMap<Doctor, DoctorBasicInfoDTO>()
//.ForMember(d => d.TitleCNList, u => u.MapFrom(s => s.DoctorDicRelationList.Where(t => t.KeyName == StaticData.Title)
//.Select(t => new { TitleCN = t.Dictionary.ValueCN, ShowOrder = t.Dictionary.ShowOrder }).OrderBy(k => k.ShowOrder).Select(t => t.TitleCN)))
// .ForMember(d => d.TitleList, u => u.MapFrom(s => s.DoctorDicRelationList.Where(t => t.KeyName == StaticData.Title)
//.Select(t => new { Title = t.Dictionary.Value, ShowOrder = t.Dictionary.ShowOrder }).OrderBy(k => k.ShowOrder).Select(t => t.Title)))
// .ForMember(d => d.TitleIds, u => u.MapFrom(s => s.DoctorDicRelationList.Where(t => t.KeyName == StaticData.Title)
//.Select(t => new { TitleId = t.Dictionary.Id, ShowOrder = t.Dictionary.ShowOrder }).OrderBy(k => k.ShowOrder).Select(t => t.TitleId)));
//这样只会查询一次
CreateMap<Doctor, DoctorBasicInfoDTO>()
.ForMember(o => o.DoctorDicViewDtos, t => t.MapFrom(u => u.DoctorDicRelationList.Where(t => t.KeyName == StaticData.Title).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)));
CreateMap<Dictionary, DicView>()
.ForMember(t=>t.ParentCode,u=>u.MapFrom(c=>c.Parent.Code));
//CreateMap<DoctorDictionary, DicView>();
CreateMap<Doctor, SpecialtyDTO>()
.ForMember(o => o.Speciality, t => t.MapFrom(u => u.Speciality.Value))
.ForMember(o => o.DictionaryList, t => t.MapFrom(u => u.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)));
CreateMap<SpecialtyCommand, Doctor>();
//医生职业信息
CreateMap<Doctor, EmploymentDTO>().IncludeMembers(t => t.Hospital)
.ForMember(d => d.Department, u => u.MapFrom(s => s.Department.Value))
.ForMember(d => d.DepartmentCN, u => u.MapFrom(s => s.Department.ValueCN))
.ForMember(d => d.Position, u => u.MapFrom(s => s.Position.Value))
.ForMember(d => d.PositionCN, u => u.MapFrom(s => s.Position.ValueCN))
.ForMember(d => d.Rank, u => u.MapFrom(s => s.Rank.Value))
.ForMember(d => d.RankCN, u => u.MapFrom(s => s.Rank.ValueCN));
CreateMap<Hospital, EmploymentDTO>();
CreateMap<EnrollDetail, DoctorStateModelDTO>()
.ForMember(d => d.IntoGroupState, u => u.MapFrom(s => s.EnrollStatus))
.ForMember(d => d.OptTime, u => u.MapFrom(s => s.CreateTime))
.ForMember(d => d.OptUserName, u => u.MapFrom(s => s.CreateUser.UserName));
CreateMap<Enroll, ConfirmationReviewerDTO>().IncludeMembers(t => t.Doctor, t => t.Doctor.Hospital)
.ForMember(d => d.Id, u => u.MapFrom(s => s.Doctor.Id));
CreateMap<Doctor, ConfirmationReviewerDTO>();
CreateMap<Hospital, ConfirmationReviewerDTO>();
#endregion
}
}
}
@@ -0,0 +1,162 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:10
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> SystemDocumentView 列表视图模型 </summary>
public class SystemDocumentView : SystemDocumentAddOrEdit
{
public string FullFilePath { get; set; } = string.Empty;
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public List<NeedConfirmedUserTypeView> NeedConfirmedUserTypeList { get; set; }=new List<NeedConfirmedUserTypeView>();
}
public class UnionDocumentView : SystemDocumentAddOrEdit
{
public string FullFilePath { get; set; } = string.Empty;
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public bool IsSystemDoc { get; set; }
}
public class UnionDocumentWithConfirmInfoView: UnionDocumentView
{
public DateTime? ConfirmTime { get; set; }
public Guid? ConfirmUserId { get; set; }
public string UserName { get; set; } = string.Empty;
public string RealName { get; set; } = string.Empty;
public string UserTypeShortName { get; set; } = string.Empty;
}
public class TrialUserDto
{
public Guid UserId { get; set; }
public string UserName { get; set; } = string.Empty;
public string RealName { get; set; } = string.Empty;
}
public class DocumentUnionWithUserStatView: UnionDocumentView
{
public int? DocumentUserCount { get; set; }
public int? DocumentConfirmedUserCount { get; set; }
}
public class TrialUserUnionDocumentView
{
public Guid UserId { get; set; }
public string UserTypeShortName { get; set; } = string.Empty;
public string UserName { get; set; } = string.Empty;
public string RealName { get; set; } = string.Empty;
public int? SystemDocumentCount { get; set; }
public int? TrialDocumentCount { get; set; }
public int? TrialDocumentConfirmedCount { get; set; }
public int? SystemDocumentConfirmedCount { get; set; }
//public List<UnionDocumentView> DocumentList { get; set; }
}
///<summary>SystemDocumentQuery 列表查询参数模型</summary>
public class SystemDocumentQuery : PageInput
{
public Guid? SystemDocumentId { get; set; }
public string Type { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
}
public class TrialUserDocUnionQuery: PageInput
{
[NotDefault]
public Guid TrialId { get; set; }
public string Type { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
}
public class UserConfirmCommand
{
[NotDefault]
public Guid TrialId { get; set; }
[NotDefault]
public Guid DocumentId { get; set; }
public bool isSystemDoc { get; set; }
public string UserName { get; set; } = String.Empty;
public string PassWord { get; set; } = String.Empty;
public string SignText { get; set; } = String.Empty;
}
public class DocumentTrialUnionQuery : TrialUserDocUnionQuery
{
public Guid? UserTypeId { get; set; }
public Guid? UserId { get; set; }
}
///<summary> SystemDocumentAddOrEdit 列表查询参数模型</summary>
public class SystemDocumentAddOrEdit
{
public Guid? Id { get; set; }
public string Type { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public bool IsAbandon { get; set; }
public int SignViewMinimumMinutes { get; set; }
}
public class AddOrEditSystemDocument : SystemDocumentAddOrEdit
{
public List<Guid> NeedConfirmedUserTypeIdList { get; set; }=new List<Guid>();
}
}
@@ -0,0 +1,47 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:10
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> TrialDocumentUserConfirmView 列表视图模型 </summary>
public class TrialDocumentUserConfirmView
{
public Guid TrialId { get; set; }
public Guid? TrialDocumentId { get; set; }
public DateTime? ConfirmTime { get; set; }
public Guid? ConfirmUserId { get; set; }
public string UserName { get; set; } = string.Empty;
public string RealName { get; set; } = string.Empty;
}
public class NeedConfirmedUserTypeView
{
public Guid NeedConfirmUserTypeId { get; set; }
public string UserTypeShortName { get; set; } = string.Empty;
}
}
@@ -0,0 +1,72 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:10
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Infrastructure.Extention;
using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> TrialDocumentView 列表视图模型 </summary>
public class TrialDocumentView : TrialDocumentAddOrEdit
{
public string FullFilePath { get; set; } = String.Empty;
public bool IsSomeUserSigned{get;set;}
public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
public List<NeedConfirmedUserTypeView> NeedConfirmedUserTypeList { get; set; } = new List<NeedConfirmedUserTypeView>();
}
///<summary>TrialDocumentQuery 列表查询参数模型</summary>
public class TrialDocumentQuery : PageInput
{
public string Type { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
[NotDefault]
public Guid TrialId { get; set; }
}
///<summary> TrialDocumentAddOrEdit 列表查询参数模型</summary>
public class TrialDocumentAddOrEdit
{
public Guid? Id { get; set; }
public Guid TrialId { get; set; }
public string Type { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
public string Path { get; set; } = String.Empty;
public string Description { get; set; } = String.Empty;
public bool IsAbandon { get; set; }
public int SignViewMinimumMinutes { get; set; }
}
public class AddOrEditTrialDocument: TrialDocumentAddOrEdit
{
public List<Guid> NeedConfirmedUserTypeIdList { get; set; } = new List<Guid>();
}
}
@@ -0,0 +1,31 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:00
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary>
/// ISystemDocumentService
/// </summary>
public interface ISystemDocumentService
{
//PageOutput<SystemDocumentView> GetSystemDocumentList(SystemDocumentQuery querySystemDocument);
//IResponseOutput AddOrUpdateSystemDocument(AddOrEditSystemDocument addOrEditSystemDocument);
//IResponseOutput DeleteSystemDocument(Guid systemDocumentId);
Task<PageOutput<SystemDocumentView>> GetSystemDocumentListAsync(SystemDocumentQuery querySystemDocument);
Task<IResponseOutput> AddOrUpdateSystemDocumentAsync(AddOrEditSystemDocument addOrEditSystemDocument);
Task<IResponseOutput> DeleteSystemDocumentAsync(Guid systemDocumentId);
}
}
@@ -0,0 +1,30 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:03
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Core.Application.Contracts
{
public interface ITrialDocumentService
{
Task<IResponseOutput> AddOrUpdateTrialDocument(AddOrEditTrialDocument addOrEditTrialDocument);
Task<IResponseOutput> DeleteTrialDocument(Guid trialDocumentId, Guid trialId);
Task<PageOutput<UnionDocumentWithConfirmInfoView>> GetDocumentConfirmList(DocumentTrialUnionQuery querySystemDocument);
Task<PageOutput<TrialDocumentView>> GetTrialDocumentList(TrialDocumentQuery queryTrialDocument);
Task<PageOutput<UnionDocumentWithConfirmInfoView>> GetUserDocumentList(TrialUserDocUnionQuery querySystemDocument);
Task<IResponseOutput> SetFirstViewDocumentTime(Guid documentId, bool isSystemDoc);
Task<IResponseOutput> UserConfirm(UserConfirmCommand userConfirmCommand);
Task<List<TrialUserDto>> GetTrialUserSelect(Guid trialId);
PageOutput<DocumentUnionWithUserStatView> GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument);
List<TrialUserUnionDocumentView> GetTrialUserDocumentList(Guid trialId);
}
}
@@ -0,0 +1,122 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:03
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
namespace IRaCIS.Core.Application.Services
{
/// <summary>
/// SystemDocumentService
/// </summary>
[ApiExplorerSettings(GroupName = "Trial")]
public class SystemDocumentService : BaseService, ISystemDocumentService
{
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IRepository<SystemDocument> systemDocumentRepository;
public SystemDocumentService(IWebHostEnvironment hostEnvironment, IRepository<SystemDocument> systemDocumentRepository)
{
_hostEnvironment = hostEnvironment;
this.systemDocumentRepository = systemDocumentRepository;
}
/// <summary>
/// 管理端列表
/// </summary>
/// <param name="querySystemDocument"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<SystemDocumentView>> GetSystemDocumentListAsync(SystemDocumentQuery querySystemDocument)
{
var systemDocumentQueryable = systemDocumentRepository
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name))
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Type), t => t.Type.Contains(querySystemDocument.Type))
.ProjectTo<SystemDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, userId = _userInfo.Id });
return await systemDocumentQueryable.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc);
}
public async Task<IResponseOutput> AddOrUpdateSystemDocumentAsync(AddOrEditSystemDocument addOrEditSystemDocument)
{
if (addOrEditSystemDocument.Id == null)
{
var entity = _mapper.Map<SystemDocument>(addOrEditSystemDocument);
if (await systemDocumentRepository.AnyAsync(t => t.Type == addOrEditSystemDocument.Type && t.Name == addOrEditSystemDocument.Name))
{
return ResponseOutput.NotOk("同类型已存在该文件名");
}
await systemDocumentRepository.AddAsync(entity,true);
return ResponseOutput.Ok(entity.Id.ToString());
}
else
{
var document = await systemDocumentRepository.Where(t => t.Id == addOrEditSystemDocument.Id, true).Include(t => t.NeedConfirmedUserTypeList).FirstOrDefaultAsync();
if (document == null) return Null404NotFound(document);
if (await systemDocumentRepository.AnyAsync(t => t.Type == addOrEditSystemDocument.Type && t.Name == addOrEditSystemDocument.Name && t.Id != addOrEditSystemDocument.Id))
{
return ResponseOutput.NotOk("同类型已存在该文件名");
}
var dbDocumentType = document.Type;
_mapper.Map(addOrEditSystemDocument, document);
if (dbDocumentType != addOrEditSystemDocument.Type)
{
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
var beforeFilePath = Path.Combine(rootPath, document.Path);
document.Path = document.Path.Replace(dbDocumentType, addOrEditSystemDocument.Type);
var nowPath = Path.Combine(rootPath, document.Path);
if (File.Exists(beforeFilePath))
{
File.Move(beforeFilePath, nowPath, true);
File.Delete(beforeFilePath);
}
}
var success = _repository.SaveChangesAsync();
return ResponseOutput.Ok(document.Id.ToString());
}
}
[HttpDelete("{systemDocumentId:guid}")]
public async Task<IResponseOutput> DeleteSystemDocumentAsync(Guid systemDocumentId)
{
if (await _repository.Where<SystemDocument>(t => t.Id == systemDocumentId).AnyAsync(u => u.SystemDocConfirmedUserList.Any()))
{
return ResponseOutput.NotOk("该文档下已有签名的用户");
}
var success = await _repository.DeleteFromQueryAsync<SystemDocument>(t => t.Id == systemDocumentId);
return ResponseOutput.Result(success);
}
}
}
@@ -0,0 +1,642 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-01-05 09:17:03
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Core.Application.Services
{
/// <summary>
/// TrialDocumentService
/// </summary>
[ApiExplorerSettings(GroupName = "Trial")]
public class TrialDocumentService : BaseService, ITrialDocumentService
{
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IRepository<TrialDocument> trialDocumentRepository;
public TrialDocumentService(IWebHostEnvironment hostEnvironment, IRepository<TrialDocument> trialDocumentRepository)
{
_hostEnvironment = hostEnvironment;
this.trialDocumentRepository = trialDocumentRepository;
}
/// <summary>
/// Setting 界面的 项目所有文档列表
/// </summary>
/// <param name="queryTrialDocument"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<TrialDocumentView>> GetTrialDocumentList(TrialDocumentQuery queryTrialDocument)
{
var trialDocumentQueryable = trialDocumentRepository.Where(t => t.TrialId == queryTrialDocument.TrialId)
.WhereIf(!string.IsNullOrEmpty(queryTrialDocument.Name), t => t.Name.Contains(queryTrialDocument.Name))
.WhereIf(!string.IsNullOrEmpty(queryTrialDocument.Type), t => t.Type.Contains(queryTrialDocument.Type))
.ProjectTo<TrialDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken });
return await trialDocumentQueryable.ToPagedListAsync(queryTrialDocument.PageIndex, queryTrialDocument.PageSize, queryTrialDocument.SortField, queryTrialDocument.Asc);
}
/// <summary>
/// 具体用户看到的 系统文件列表 + 项目类型文档
/// </summary>
/// <param name="querySystemDocument"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<UnionDocumentWithConfirmInfoView>> GetUserDocumentList(TrialUserDocUnionQuery querySystemDocument)
{
#region https://github.com/dotnet/efcore/issues/16243 操作不行
////系统文档查询
//var systemDocumentQueryable = _systemDocumentRepository
// .WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
// .WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.SystemDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
//.ProjectTo<UnionDocumentView>(_mapper.ConfigurationProvider, new { userId = _userInfo.Id, token = _userInfo.UserToken });
////项目文档查询
//var trialDocQueryable = _trialDocumentRepository.Where(t => t.TrialId == querySystemDocument.TrialId)
// .WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
// .WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.TrialDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
// .ProjectTo<UnionDocumentView>(_mapper.ConfigurationProvider, new { userId = _userInfo.Id, token = _userInfo.UserToken });
//var unionQuery = systemDocumentQueryable.Union(trialDocQueryable);
// .WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name))
// .WhereIf(!string.IsNullOrEmpty(querySystemDocument.Type), t => t.Type.Contains(querySystemDocument.Type));
#endregion
#region
////系统文档查询
//var systemDocumentQueryable = _systemDocumentRepository
// .WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
// .WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.SystemDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
// .Select(t => new UnionDocumentView()
// {
// Id = t.Id,
// IsSystemDoc = true,
// CreateTime = t.CreateTime,
// FullFilePath = t.Path + "?access_token=" + _userInfo.UserToken,
// IsAbandon = t.IsAbandon,
// Name = t.Name,
// Path = t.Path,
// Type = t.Type,
// UpdateTime = t.UpdateTime,
// SignViewMinimumMinutes = t.SignViewMinimumMinutes,
// });
////项目文档查询
//var trialDocQueryable = _trialDocumentRepository.Where(t => t.TrialId == querySystemDocument.TrialId)
// .WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
// .WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.TrialDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
// .Select(t => new UnionDocumentView()
// {
// Id = t.Id,
// IsSystemDoc = false,
// CreateTime = t.CreateTime,
// FullFilePath = t.Path + "?access_token=" + _userInfo.UserToken,
// IsAbandon = t.IsAbandon,
// Name = t.Name,
// Path = t.Path,
// Type = t.Type,
// UpdateTime = t.UpdateTime,
// SignViewMinimumMinutes = t.SignViewMinimumMinutes,
// });
#endregion
var trialFininshedTime = await _repository.Where<Trial>(t => t.Id == querySystemDocument.TrialId).Select(t => t.TrialFinishedTime).FirstOrDefaultAsync();
//系统文档查询
var systemDocumentQueryable = from needConfirmedUserType in _repository.Where<SystemDocNeedConfirmedUserType>(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId)
//.Where(u => u.UserTypeRole.UserList.SelectMany(cc => cc.UserTrials.Where(t => t.TrialId == querySystemDocument.TrialId)).Any(e => e.Trial.TrialFinishedTime < u.SystemDocument.CreateTime))
.WhereIf(trialFininshedTime != null, u => u.SystemDocument.CreateTime < trialFininshedTime)
.WhereIf(!_userInfo.IsAdmin, t => t.SystemDocument.IsAbandon == false || (t.SystemDocument.IsAbandon == true && t.SystemDocument.SystemDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == querySystemDocument.TrialId && t.UserId == _userInfo.Id)
on needConfirmedUserType.NeedConfirmUserTypeId equals trialUser.User.UserTypeId
join confirm in _repository.GetQueryable<SystemDocConfirmedUser>() on new { ConfirmUserId = trialUser.UserId, SystemDocumentId = needConfirmedUserType.SystemDocumentId } equals new { confirm.ConfirmUserId, confirm.SystemDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = needConfirmedUserType.SystemDocument.Id,
CreateTime = needConfirmedUserType.SystemDocument.CreateTime,
IsAbandon = needConfirmedUserType.SystemDocument.IsAbandon,
SignViewMinimumMinutes = needConfirmedUserType.SystemDocument.SignViewMinimumMinutes,
Name = needConfirmedUserType.SystemDocument.Name,
Path = needConfirmedUserType.SystemDocument.Path,
Type = needConfirmedUserType.SystemDocument.Type,
UpdateTime = needConfirmedUserType.SystemDocument.UpdateTime,
FullFilePath = needConfirmedUserType.SystemDocument.Path + "?access_token=" + _userInfo.UserToken,
ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
RealName = trialUser.User.LastName + " / " + trialUser.User.FirstName,
UserName = trialUser.User.UserName,
UserTypeShortName = trialUser.User.UserTypeRole.UserTypeShortName
};
//项目文档查询
var trialDocQueryable = from trialDoc in trialDocumentRepository.Where(t => t.TrialId == querySystemDocument.TrialId)
.WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
.WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.TrialDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == querySystemDocument.TrialId && t.UserId == _userInfo.Id) on trialDoc.TrialId equals trialUser.TrialId
join confirm in _repository.Where<TrialDocUserTypeConfirmedUser>(t => t.TrialDocument.TrialId == querySystemDocument.TrialId) on
new { trialUser.UserId, TrialDocumentId = trialDoc.Id } equals new { UserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
{
Id = trialDoc.Id,
IsSystemDoc = false,
CreateTime = trialDoc.CreateTime,
FullFilePath = trialDoc.Path + "?access_token=" + _userInfo.UserToken,
IsAbandon = trialDoc.IsAbandon,
Name = trialDoc.Name,
Path = trialDoc.Path,
Type = trialDoc.Type,
UpdateTime = trialDoc.UpdateTime,
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
RealName = trialUser.User.LastName + " / " + trialUser.User.FirstName,
UserName = trialUser.User.UserName,
UserTypeShortName = trialUser.User.UserTypeRole.UserTypeShortName
};
var unionQuery = systemDocumentQueryable.Union(trialDocQueryable)
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name))
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Type), t => t.Type.Contains(querySystemDocument.Type));
return await unionQuery.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc);
}
/// <summary>
/// 获取用户是否有文档未签署
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpGet("{trialId:guid}")]
public async Task<bool> GetUserIsHaveDocumentNeedSign(Guid trialId)
{
var trialFininshedTime = await _repository.Where<Trial>(t => t.Id == trialId).Select(t => t.TrialFinishedTime).FirstOrDefaultAsync();
//系统文档查询
var systemDocumentQueryable = from needConfirmedUserType in _repository.Where<SystemDocNeedConfirmedUserType>(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId)
//.Where(u => u.UserTypeRole.UserList.SelectMany(cc => cc.UserTrials.Where(t => t.TrialId == querySystemDocument.TrialId)).Any(e => e.Trial.TrialFinishedTime < u.SystemDocument.CreateTime))
.WhereIf(trialFininshedTime != null, u => u.SystemDocument.CreateTime < trialFininshedTime)
.WhereIf(!_userInfo.IsAdmin, t => t.SystemDocument.IsAbandon == false || (t.SystemDocument.IsAbandon == true && t.SystemDocument.SystemDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == trialId && t.UserId == _userInfo.Id)
on needConfirmedUserType.NeedConfirmUserTypeId equals trialUser.User.UserTypeId
join confirm in _repository.GetQueryable<SystemDocConfirmedUser>() on new { ConfirmUserId = trialUser.UserId, SystemDocumentId = needConfirmedUserType.SystemDocumentId } equals new { confirm.ConfirmUserId, confirm.SystemDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new
{
//ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
};
//项目文档查询
var trialDocQueryable = from trialDoc in trialDocumentRepository.Where(t => t.TrialId == trialId)
.WhereIf(!_userInfo.IsAdmin, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
.WhereIf(!_userInfo.IsAdmin, t => t.IsAbandon == false || (t.IsAbandon == true && t.TrialDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.Id)))
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == trialId && t.UserId == _userInfo.Id) on trialDoc.TrialId equals trialUser.TrialId
join confirm in _repository.Where<TrialDocUserTypeConfirmedUser>(t => t.TrialDocument.TrialId == trialId) on
new { trialUser.UserId, TrialDocumentId = trialDoc.Id } equals new { UserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new
{
//ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
};
var unionQuery = systemDocumentQueryable.Union(trialDocQueryable);
return await unionQuery.AnyAsync(t => t.ConfirmTime == null);
}
/// <summary>
/// 获取确认列表情况 项目文档+系统文档+具体的人
/// </summary>
/// <param name="querySystemDocument"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<UnionDocumentWithConfirmInfoView>> GetDocumentConfirmList(DocumentTrialUnionQuery querySystemDocument)
{
#region linq join
//var trialDocQuery = from trialDocumentNeedConfirmedUserType in _trialDocumentNeedConfirmedUserTypeRepository.Where(t => t.TrialDocument.TrialId == querySystemDocument.TrialId)
// join trialUser in _trialUserRepository.Where(t => t.TrialId == querySystemDocument.TrialId)
// .WhereIf(querySystemDocument.UserId != null, t => t.UserId == querySystemDocument.UserId)
// on trialDocumentNeedConfirmedUserType.NeedConfirmUserTypeId equals trialUser.User.UserTypeId
// join confirm in _trialDocuserConfrimedRepository.AsQueryable() on trialUser.UserId equals confirm.ConfirmUserId into cc
// from confirm in cc.DefaultIfEmpty()
// select new UnionDocumentConfirmListView()
// {
// Id = trialDocumentNeedConfirmedUserType.TrialDocument.Id,
// CreateTime = trialDocumentNeedConfirmedUserType.TrialDocument.CreateTime,
// IsAbandon = trialDocumentNeedConfirmedUserType.TrialDocument.IsAbandon,
// SignViewMinimumMinutes = trialDocumentNeedConfirmedUserType.TrialDocument.SignViewMinimumMinutes,
// Name = trialDocumentNeedConfirmedUserType.TrialDocument.Name,
// Path = trialDocumentNeedConfirmedUserType.TrialDocument.Path,
// Type = trialDocumentNeedConfirmedUserType.TrialDocument.Type,
// UpdateTime = trialDocumentNeedConfirmedUserType.TrialDocument.UpdateTime,
// UserConfirmInfo = /*confirm == null ? null : */new UnionDocumentUserConfirmView()
// {
// ConfirmUserId = confirm.ConfirmUserId,
// ConfirmTime = confirm.ConfirmTime,
// RealName = trialUser.User.LastName + " / " + trialUser.User.LastName,
// UserName = trialUser.User.UserName,
// },
// FullFilePath = trialDocumentNeedConfirmedUserType.TrialDocument.Path + "?access_token=" + _userInfo.UserToken
// };
#endregion
var trialFininshedTime = await _repository.Where<Trial>(t => t.Id == querySystemDocument.TrialId).Select(t => t.TrialFinishedTime).FirstOrDefaultAsync();
var trialDocQuery = from trialDocumentNeedConfirmedUserType in _repository.Where<TrialDocNeedConfirmedUserType>(t => t.TrialDocument.TrialId == querySystemDocument.TrialId)
//.Where(t => t.TrialDocument.Trial.TrialUserList.Any(cc => cc.User.UserTypeId == t.NeedConfirmUserTypeId))
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == querySystemDocument.TrialId)
.WhereIf(querySystemDocument.UserId != null, t => t.UserId == querySystemDocument.UserId)
.WhereIf(querySystemDocument.UserTypeId != null, t => t.User.UserTypeId == querySystemDocument.UserTypeId)
on trialDocumentNeedConfirmedUserType.NeedConfirmUserTypeId equals trialUser.User.UserTypeId
join confirm in _repository.Where<TrialDocUserTypeConfirmedUser>(t => t.TrialDocument.TrialId == querySystemDocument.TrialId) on
new { trialUser.UserId, TrialDocumentId = trialDocumentNeedConfirmedUserType.TrialDocumentId } equals new { UserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = false,
Id = trialDocumentNeedConfirmedUserType.TrialDocument.Id,
CreateTime = trialDocumentNeedConfirmedUserType.TrialDocument.CreateTime,
IsAbandon = trialDocumentNeedConfirmedUserType.TrialDocument.IsAbandon,
SignViewMinimumMinutes = trialDocumentNeedConfirmedUserType.TrialDocument.SignViewMinimumMinutes,
Name = trialDocumentNeedConfirmedUserType.TrialDocument.Name,
Path = trialDocumentNeedConfirmedUserType.TrialDocument.Path,
Type = trialDocumentNeedConfirmedUserType.TrialDocument.Type,
UpdateTime = trialDocumentNeedConfirmedUserType.TrialDocument.UpdateTime,
ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
RealName = trialUser.User.LastName + " / " + trialUser.User.FirstName,
UserName = trialUser.User.UserName,
UserTypeShortName = trialUser.User.UserTypeRole.UserTypeShortName,
FullFilePath = trialDocumentNeedConfirmedUserType.TrialDocument.Path + "?access_token=" + _userInfo.UserToken
};
var systemDocQuery = from needConfirmEdUserType in _repository.WhereIf<SystemDocNeedConfirmedUserType>(trialFininshedTime != null, u => u.SystemDocument.CreateTime < trialFininshedTime)
join trialUser in _repository.Where<TrialUser>(t => t.TrialId == querySystemDocument.TrialId)
.WhereIf(querySystemDocument.UserId != null, t => t.UserId == querySystemDocument.UserId)
on needConfirmEdUserType.NeedConfirmUserTypeId equals trialUser.User.UserTypeId
join confirm in _repository.GetQueryable<SystemDocConfirmedUser>() on new { ConfirmUserId = trialUser.UserId, SystemDocumentId = needConfirmEdUserType.SystemDocumentId } equals new { confirm.ConfirmUserId, confirm.SystemDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
{
IsSystemDoc = true,
Id = needConfirmEdUserType.SystemDocument.Id,
CreateTime = needConfirmEdUserType.SystemDocument.CreateTime,
IsAbandon = needConfirmEdUserType.SystemDocument.IsAbandon,
SignViewMinimumMinutes = needConfirmEdUserType.SystemDocument.SignViewMinimumMinutes,
Name = needConfirmEdUserType.SystemDocument.Name,
Path = needConfirmEdUserType.SystemDocument.Path,
Type = needConfirmEdUserType.SystemDocument.Type,
UpdateTime = needConfirmEdUserType.SystemDocument.UpdateTime,
ConfirmUserId = confirm.ConfirmUserId,
ConfirmTime = confirm.ConfirmTime,
RealName = trialUser.User.LastName + " / " + trialUser.User.FirstName,
UserName = trialUser.User.UserName,
UserTypeShortName = trialUser.User.UserTypeRole.UserTypeShortName,
FullFilePath = needConfirmEdUserType.SystemDocument.Path + "?access_token=" + _userInfo.UserToken
};
var unionQuery = trialDocQuery.Union(systemDocQuery)
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name))
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Type), t => t.Type.Contains(querySystemDocument.Type));
return await unionQuery.ToPagedListAsync(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc);
}
[HttpGet("{trialId:guid}")]
public async Task<List<TrialUserDto>> GetTrialUserSelect(Guid trialId)
{
return await _repository.Where<TrialUser>(t => t.TrialId == trialId)
.Select(t => new TrialUserDto() { UserId = t.UserId, RealName = t.User.LastName + " / " + t.User.FirstName, UserName = t.User.UserName })
.ToListAsync();
}
[HttpGet("{trialId:guid}")]
public async Task<List<string>> GetTrialDocAndSystemDocType(Guid trialId)
{
return await trialDocumentRepository.Where(t => t.TrialId == trialId).Select(t => t.Type).Union(_repository.GetQueryable<SystemDocument>().Select(t => t.Type)).Distinct()
.ToListAsync();
}
public async Task<IResponseOutput> AddOrUpdateTrialDocument(AddOrEditTrialDocument addOrEditTrialDocument)
{
if (addOrEditTrialDocument.Id == null)
{
var entity = _mapper.Map<TrialDocument>(addOrEditTrialDocument);
if (await trialDocumentRepository.AnyAsync(t => t.Type == addOrEditTrialDocument.Type && t.Name == addOrEditTrialDocument.Name && t.TrialId == addOrEditTrialDocument.TrialId))
{
return ResponseOutput.NotOk("同类型已存在该文件名");
}
await _repository.AddAsync(entity, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
else
{
if (await trialDocumentRepository.AnyAsync(t => t.Type == addOrEditTrialDocument.Type && t.Name == addOrEditTrialDocument.Name && t.Id != addOrEditTrialDocument.Id && t.TrialId == addOrEditTrialDocument.TrialId))
{
return ResponseOutput.NotOk("同类型已存在该文件名");
}
var document = trialDocumentRepository.Where(t => t.Id == addOrEditTrialDocument.Id, true).Include(t => t.NeedConfirmedUserTypeList).FirstOrDefault();
if (document == null) return Null404NotFound(document);
var dbDocumentType = document.Type;
_mapper.Map(addOrEditTrialDocument, document);
if (dbDocumentType != addOrEditTrialDocument.Type)
{
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
var beforeFilePath = Path.Combine(rootPath, document.Path);
document.Path = document.Path.Replace(dbDocumentType, addOrEditTrialDocument.Type);
var nowPath = Path.Combine(rootPath, document.Path);
if (File.Exists(beforeFilePath))
{
File.Move(beforeFilePath, nowPath, true);
File.Delete(beforeFilePath);
}
}
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Ok(document.Id.ToString());
}
}
/// <summary>
/// 已签名的文档 不允许删除
/// </summary>
/// <param name="trialDocumentId"></param>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpDelete("{trialId:guid}/{trialDocumentId:guid}")]
public async Task<IResponseOutput> DeleteTrialDocument(Guid trialDocumentId, Guid trialId)
{
if (await trialDocumentRepository.Where(t => t.Id == trialDocumentId).AnyAsync(t => t.TrialDocConfirmedUserList.Any()))
{
return ResponseOutput.NotOk("该文档,已有用户签名 不允许删除");
}
var success = await trialDocumentRepository.DeleteFromQueryAsync(t => t.Id == trialDocumentId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 浏览文档说明时调用,记录第一次看的时间
/// </summary>
/// <param name="documentId"></param>
/// <param name="isSystemDoc"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{documentId:guid}/{isSystemDoc:bool}")]
[UnitOfWork]
public async Task<IResponseOutput> SetFirstViewDocumentTime(Guid documentId, bool isSystemDoc)
{
var success = false;
if (isSystemDoc)
{
await _repository.AddAsync(new SystemDocConfirmedUser() { SystemDocumentId = documentId, SignFirstViewTime = DateTime.Now });
//success = await _repository.UpdateFromQueryAsync<SystemDocConfirmedUser>(t => t.Id == documentId, d => new SystemDocConfirmedUser() { SignFirstViewTime = DateTime.Now });
}
else
{
await _repository.AddAsync(new TrialDocUserTypeConfirmedUser() { TrialDocumentId = documentId, SignFirstViewTime = DateTime.Now });
//success = await _repository.UpdateFromQueryAsync<TrialDocUserTypeConfirmedUser>(t => t.Id == documentId , d => new TrialDocUserTypeConfirmedUser() { SignFirstViewTime = DateTime.Now });
}
success= await _repository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
/// <summary>
/// 用户 签名某个文档
/// </summary>
/// <returns></returns>
[NonDynamicMethod]
public async Task<IResponseOutput> UserConfirm(UserConfirmCommand userConfirmCommand)
{
var user = await _repository.FirstOrDefaultAsync<User>(u => u.UserName == userConfirmCommand.UserName && u.Password == userConfirmCommand.PassWord);
if (user == null)
{
return ResponseOutput.NotOk("password error");
}
else if (user.Status == UserStateEnum.Disable)
{
return ResponseOutput.NotOk("The user has been disabled!");
}
if (userConfirmCommand.isSystemDoc)
{
if (await _repository.AnyAsync<SystemDocConfirmedUser>(t => t.SystemDocumentId == userConfirmCommand.DocumentId && t.ConfirmUserId == _userInfo.Id))
{
return ResponseOutput.NotOk("该文档已经签名");
}
if (!await _repository.AnyAsync<SystemDocument>(t => t.Id == userConfirmCommand.DocumentId) || await trialDocumentRepository.AnyAsync(t => t.Id == userConfirmCommand.DocumentId && t.IsAbandon))
{
return ResponseOutput.NotOk("文件已删除或者废除,签署失败!");
}
await _repository.AddAsync(new SystemDocConfirmedUser() { ConfirmTime = DateTime.Now, ConfirmUserId = _userInfo.Id, SystemDocumentId = userConfirmCommand.DocumentId });
}
else
{
if (await _repository.AnyAsync<TrialDocUserTypeConfirmedUser>(t => t.TrialDocumentId == userConfirmCommand.DocumentId && t.ConfirmUserId == _userInfo.Id))
{
return ResponseOutput.NotOk("该文档已经签名");
}
if (!await trialDocumentRepository.AnyAsync(t => t.Id == userConfirmCommand.DocumentId) || await _repository.AnyAsync<TrialDocument>(t => t.Id == userConfirmCommand.DocumentId && t.IsAbandon))
{
return ResponseOutput.NotOk("文件已删除或者废除,签署失败!");
}
await _repository.AddAsync(new TrialDocUserTypeConfirmedUser() { ConfirmTime = DateTime.Now, ConfirmUserId = _userInfo.Id, TrialDocumentId = userConfirmCommand.DocumentId });
}
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 用户 废除某个文档
/// </summary>
/// <param name="documentId"></param>
/// <param name="isSystemDoc"></param>
/// <returns></returns>
[HttpPut("{documentId:guid}/{isSystemDoc:bool}")]
public async Task<IResponseOutput> UserAbandonDoc(Guid documentId, bool isSystemDoc)
{
if (isSystemDoc)
{
await _repository.UpdateFromQueryAsync<SystemDocument>(t => t.Id == documentId, u => new SystemDocument() { IsAbandon = true });
}
else
{
await trialDocumentRepository.UpdateFromQueryAsync(t => t.Id == documentId, u => new TrialDocument() { IsAbandon = true });
}
return ResponseOutput.Ok();
}
/// <summary>
/// 从项目下参与者的维度 先看人员列表(展示统计数字) 点击数字 再看人员具体签署的 系统文档+项目文档(共用上面与人相关的具体文档列表)
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpGet("{trialId:guid}")]
public List<TrialUserUnionDocumentView> GetTrialUserDocumentList(Guid trialId)
{
var query = _repository.Where<TrialUser>(t => t.TrialId == trialId)
.Select(t => new TrialUserUnionDocumentView()
{
UserId = t.UserId,
UserName = t.User.UserName,
RealName = t.User.LastName + " / " + t.User.FirstName,
UserTypeShortName = t.User.UserTypeRole.UserTypeShortName,
TrialDocumentCount = t.Trial.TrialDocumentList.Count(u => u.NeedConfirmedUserTypeList.Any(k => k.NeedConfirmUserTypeId == t.User.UserTypeId)),
TrialDocumentConfirmedCount = t.Trial.TrialDocumentList.SelectMany(u => u.TrialDocConfirmedUserList).Count(k => k.ConfirmUserId == t.UserId),
SystemDocumentConfirmedCount = t.User.SystemDocConfirmedList.Count(),
//这样写不行
//SystemDocumentCount = _systemDocumentRepository.Where(s => s.NeedConfirmedUserTypeList.Any(kk => kk.NeedConfirmUserTypeId == t.User.UserTypeId))
// .WhereIf(!_userInfo.IsAdmin, s => s.IsAbandon == false || (s.IsAbandon == true && s.SystemDocConfirmedUserList.Any(uu => uu.ConfirmUserId == t.UserId))).Count()
SystemDocumentCount = t.User.UserTypeRole.SystemDocNeedConfirmedUserTypeList.Where(cc => cc.NeedConfirmUserTypeId == t.User.UserTypeId).Select(y => y.SystemDocument).Count()
});
return query.ToList();
}
/// <summary>
/// 从 文档的维度 先看到文档列表(系统文档+项目文档 以及需要确认的人数 和已经确认人数) 点击数字查看某文档下面人确认情况
/// </summary>
/// <param name="querySystemDocument"></param>
/// <returns></returns>
[HttpPost]
public PageOutput<DocumentUnionWithUserStatView> GetTrialSystemDocumentList(DocumentTrialUnionQuery querySystemDocument)
{
var systemDocumentQueryable = _repository
.WhereIf<SystemDocument>(!_userInfo.IsAdmin, t => t.IsAbandon == false)
.Select(t => new DocumentUnionWithUserStatView()
{
Id = t.Id,
IsSystemDoc = true,
CreateTime = t.CreateTime,
FullFilePath = t.Path + "?access_token=" + _userInfo.UserToken,
IsAbandon = t.IsAbandon,
Name = t.Name,
Path = t.Path,
Type = t.Type,
UpdateTime = t.UpdateTime,
SignViewMinimumMinutes = t.SignViewMinimumMinutes,
DocumentConfirmedUserCount = t.SystemDocConfirmedUserList.Count(),
//DocumentUserCount= _trialUserRepository.Where(tu=>tu.TrialId== querySystemDocument.TrialId).Count(u=>t.NeedConfirmedUserTypeList.Any(cc=>cc.NeedConfirmUserTypeId== u.User.UserTypeId ))
DocumentUserCount = t.NeedConfirmedUserTypeList.SelectMany(u => u.UserTypeRole.UserList.SelectMany(b => b.UserTrials.Where(r => r.TrialId == querySystemDocument.TrialId))).Count()
});
var trialDocQueryable = trialDocumentRepository.Where(t => t.TrialId == querySystemDocument.TrialId).Select(t => new DocumentUnionWithUserStatView()
{
Id = t.Id,
IsSystemDoc = false,
CreateTime = t.CreateTime,
FullFilePath = t.Path + "?access_token=" + _userInfo.UserToken,
IsAbandon = t.IsAbandon,
Name = t.Name,
Path = t.Path,
Type = t.Type,
UpdateTime = t.UpdateTime,
SignViewMinimumMinutes = t.SignViewMinimumMinutes,
DocumentConfirmedUserCount = t.TrialDocConfirmedUserList.Count(),
DocumentUserCount = t.Trial.TrialUserList.Count(cc => t.NeedConfirmedUserTypeList.Any(k => k.NeedConfirmUserTypeId == cc.User.UserTypeId))
});
var unionQuery = systemDocumentQueryable.Union(trialDocQueryable)
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Name), t => t.Name.Contains(querySystemDocument.Name))
.WhereIf(!string.IsNullOrEmpty(querySystemDocument.Type), t => t.Type.Contains(querySystemDocument.Type));
return unionQuery.ToPagedList(querySystemDocument.PageIndex, querySystemDocument.PageSize, querySystemDocument.SortField, querySystemDocument.Asc);
}
}
}
@@ -0,0 +1,71 @@
using AutoMapper;
using AutoMapper.EquivalencyExpression;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.Application.Service
{
public class DocumentConfig : Profile
{
public DocumentConfig()
{
var userId = Guid.Empty;
var token = string.Empty;
CreateMap<SystemDocument, SystemDocumentView>()
//.ForMember(d => d.UserConfirmInfo, u => u.MapFrom(s => s.SystemDocConfirmedUserList.FirstOrDefault(t=>t.ConfirmUserId==userId)))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path + "?access_token=" + token));
CreateMap<TrialDocument, TrialDocumentView>()
.ForMember(d => d.IsSomeUserSigned, u => u.MapFrom(s => s.TrialDocConfirmedUserList.Any()))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path + "?access_token=" + token));
CreateMap<SystemDocument, UnionDocumentView>()
.ForMember(d => d.IsSystemDoc, u => u.MapFrom(s => true))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path + "?access_token=" + token));
CreateMap<TrialDocument, UnionDocumentView>()
.ForMember(d => d.IsSystemDoc, u => u.MapFrom(s => false))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path + "?access_token=" + token));
CreateMap<TrialDocNeedConfirmedUserType, NeedConfirmedUserTypeView>().ForMember(d => d.UserTypeShortName, t => t.MapFrom(c => c.UserTypeRole.UserTypeShortName));
CreateMap<SystemDocNeedConfirmedUserType, NeedConfirmedUserTypeView>().ForMember(d => d.UserTypeShortName, t => t.MapFrom(c => c.UserTypeRole.UserTypeShortName));
//CreateMap<TrialDocument, TrialDocumentUserView>()
// .ForMember(t => t.UserConfirmInfo, c => c.MapFrom(t => t.TrialDocConfirmedUserList.Where(u => u.ConfirmUserId == userId).FirstOrDefault()))
// .ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path + "?access_token=" + token)); ;
CreateMap<TrialDocUserTypeConfirmedUser, TrialDocumentUserConfirmView>()
.ForMember(d => d.UserName, c => c.MapFrom(t => t.User.UserName))
.ForMember(d => d.RealName, c => c.MapFrom(t => t.User.LastName + " / " + t.User.FirstName));
//CreateMap<SystemDocConfirmedUser, SystemDocumentUserConfirmView>()
// .ForMember(d => d.UserName, c => c.MapFrom(t => t.User.UserName))
// .ForMember(d => d.RealName, c => c.MapFrom(t => t.User.LastName + " / " + t.User.FirstName));
CreateMap<TrialUser, TrialDocumentUserConfirmView>();
CreateMap<AddOrEditTrialDocument, TrialDocument>()
.ForMember(d => d.NeedConfirmedUserTypeList, c => c.MapFrom(t => t.NeedConfirmedUserTypeIdList));
CreateMap<Guid, TrialDocNeedConfirmedUserType>().EqualityComparison((odto, o) => odto == o.NeedConfirmUserTypeId)
.ForMember(d => d.NeedConfirmUserTypeId, c => c.MapFrom(t => t))
.ForMember(d => d.TrialDocumentId, c => c.Ignore());
CreateMap<AddOrEditSystemDocument, SystemDocument>().ForMember(d => d.NeedConfirmedUserTypeList, c => c.MapFrom(t => t.NeedConfirmedUserTypeIdList));
CreateMap<Guid, SystemDocNeedConfirmedUserType>().EqualityComparison((odto, o) => odto == o.NeedConfirmUserTypeId)
.ForMember(d => d.NeedConfirmUserTypeId, c => c.MapFrom(t => t))
.ForMember(d => d.SystemDocumentId, c => c.Ignore());
}
}
}
@@ -0,0 +1,714 @@
using AutoMapper;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.ExpressionExtend;
using System.Linq.Expressions;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
public class CalculateService : ICalculateService
{
private readonly IRepository<Payment> _paymentRepository;
private readonly IRepository<TrialPaymentPrice> _trialPaymentRepository;
private readonly IRepository<ReviewerPayInformation> _doctorPayInfoRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<Workload> _doctorWorkloadRepository;
private readonly IRepository<RankPrice> _rankPriceRepository;
private readonly IRepository<PaymentDetail> _paymentDetailRepository;
private readonly IVolumeRewardService _volumeRewardPriceService;
private readonly IRepository<ExchangeRate> _exchangeRateRepository;
private readonly IRepository<PaymentAdjustment> _payAdjustmentRepository;
private readonly IRepository<Enroll> _enrollRepository;
private readonly IMapper _mapper;
public CalculateService(IRepository<Payment> paymentRepository, IRepository<TrialPaymentPrice> trialPaymentPriceRepository,
IRepository<ReviewerPayInformation> reviewerPayInfoRepository,
IRepository<Trial> trialRepository,
IRepository<Doctor> doctorRepository,
IRepository<Workload> workloadRepository,
IRepository<RankPrice> rankPriceRepository,
IRepository<PaymentDetail> paymentDetailRepository,
IVolumeRewardService volumeRewardService,
IRepository<ExchangeRate> exchangeRateRepository,
IRepository<Enroll> EnrollRepository,
IRepository<PaymentAdjustment> paymentAdjustmentRepository, IMapper mapper)
{
_paymentRepository = paymentRepository;
_trialPaymentRepository = trialPaymentPriceRepository;
_doctorPayInfoRepository = reviewerPayInfoRepository;
_trialRepository = trialRepository;
_doctorRepository = doctorRepository;
_doctorWorkloadRepository = workloadRepository;
_rankPriceRepository = rankPriceRepository;
_paymentDetailRepository = paymentDetailRepository;
_volumeRewardPriceService = volumeRewardService;
_exchangeRateRepository = exchangeRateRepository;
_payAdjustmentRepository = paymentAdjustmentRepository;
this._enrollRepository = EnrollRepository;
_mapper = mapper;
}
/// <summary>
/// 获取某个月下的某些医生最终确认的工作量,用于计算月度费用
/// </summary>
private async Task< List<CalculatePaymentDTO>> GetFinalConfirmedWorkloadAndPayPriceList(CalculateDoctorAndMonthDTO calculateFeeParam)
{
Expression<Func<Workload, bool>> workloadLambda = x => true;
DateTime bTime = new DateTime(calculateFeeParam.CalculateMonth.Year, calculateFeeParam.CalculateMonth.Month, 1);
var eTime = bTime.AddMonths(1);
workloadLambda = workloadLambda.And(t =>
t.WorkTime >= bTime && t.WorkTime < eTime);
workloadLambda = workloadLambda.And(t => calculateFeeParam.NeedCalculateReviewers.Contains(t.DoctorId) && t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm);
var workLoadQueryable = from doctor in _doctorRepository.AsQueryable()
join workLoad in _doctorWorkloadRepository.Where(workloadLambda) on
doctor.Id equals workLoad.DoctorId
join trial in _trialRepository.AsQueryable() on workLoad.TrialId equals trial.Id
join trialPay in _trialPaymentRepository.AsQueryable() on trial.Id equals trialPay.TrialId
into temp
from trialPay in temp.DefaultIfEmpty()
join doctorPayInfo in _doctorPayInfoRepository.AsQueryable() on doctor.Id equals doctorPayInfo.DoctorId
join rankPrice in _rankPriceRepository.AsQueryable() on doctorPayInfo.RankId equals rankPrice.Id
select new CalculatePaymentDTO()
{
Id = workLoad.Id,
DoctorId = workLoad.DoctorId,
WorkTime = workLoad.WorkTime,
DataFrom = workLoad.DataFrom,
TrialId = workLoad.TrialId,
TrialCode = trial.TrialCode,
Timepoint = workLoad.Timepoint,
TimepointIn24H = workLoad.TimepointIn24H,
TimepointIn48H = workLoad.TimepointIn48H,
Global = workLoad.Global,
Adjudication = workLoad.Adjudication,
AdjudicationIn24H = workLoad.AdjudicationIn24H,
AdjudicationIn48H = workLoad.AdjudicationIn48H,
Training = workLoad.Training,
RefresherTraining = workLoad.RefresherTraining,
Downtime = workLoad.Downtime,
TrialAdditional = trialPay.TrialAdditional,
PersonalAdditional = doctorPayInfo.Additional,
AdjustmentMultiple = trialPay.AdjustmentMultiple,
TimepointPrice = rankPrice.Timepoint,
TimepointIn24HPrice = rankPrice.TimepointIn24H,
TimepointIn48HPrice = rankPrice.TimepointIn48H,
AdjudicationPrice = rankPrice.Adjudication,
AdjudicationIn24HPrice = rankPrice.AdjudicationIn24H,
AdjudicationIn48HPrice = rankPrice.AdjudicationIn48H,
DowntimePrice = rankPrice.Downtime,
GlobalPrice = rankPrice.Global,
TrainingPrice = rankPrice.Training,
RefresherTrainingPrice = rankPrice.RefresherTraining
};
return await workLoadQueryable.ToListAsync();
}
/// <summary>
/// 计算月度费用,并调用AddOrUpdateMonthlyPayment和AddOrUpdateMonthlyPaymentDetail方法,
/// 将费用计算的月度数据及详情保存
/// </summary>
[NonDynamicMethod]
public async Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token)
{
var yearMonth = param.CalculateMonth.ToString("yyyy-MM");
var rate = await _exchangeRateRepository.FirstOrDefaultAsync(u => u.YearMonth == yearMonth);
decimal exchangeRate = rate?.Rate ?? 0;
var workLoadAndPayPriceList = await GetFinalConfirmedWorkloadAndPayPriceList(param);
var volumeRewardPriceList = await _volumeRewardPriceService.GetVolumeRewardPriceList();
#region
for (int i = 0; i < volumeRewardPriceList.Count; i++)
{
if (i == 0 && volumeRewardPriceList[i].Min != 0)
{
return ResponseOutput.NotOk("Volume reward data error.");
}
if (i > 0)
{
if (volumeRewardPriceList[i - 1].Max + 1 != volumeRewardPriceList[i].Min)
return ResponseOutput.NotOk("Volume reward data error.");
}
}
#endregion
List<PaymentModel> paymentList = new List<PaymentModel>();
List<ReviewerPaymentUSD> reviewerPaymentUSDList = new List<ReviewerPaymentUSD>();
// 获取所有医生费用 一次从数据库里面全部取出来
var allDoctorList = workLoadAndPayPriceList.Where(x => param.NeedCalculateReviewers.Contains(x.DoctorId)).ToList();
var allDoctorIds = allDoctorList.Select(x => x.DoctorId).Distinct().ToList();
var listTrialId = allDoctorList.Select(x => x.TrialId).Distinct().ToList();
var trialDoctorlist= await (from enroll in _enrollRepository.Where(x=> listTrialId.Contains(x.TrialId)|| allDoctorIds.Contains(x.DoctorId))
join price in _trialPaymentRepository.Where() on enroll.TrialId equals price.TrialId
select new DoctorPrice()
{
IsNewTrial = price.IsNewTrial,
AdjustmentMultiple = enroll.AdjustmentMultiple,
TrialId=enroll.TrialId,
DoctorId = enroll.DoctorId,
Training=enroll.Training,
Adjudication=enroll.Adjudication,
Adjudication24H=enroll.Adjudication24H,
Adjudication48H= enroll.Adjudication48H,
Downtime=enroll.Downtime,
Global=enroll.Global,
RefresherTraining=enroll.RefresherTraining,
Timepoint= enroll.Timepoint,
Timepoint24H=enroll.Timepoint24H,
Timepoint48H=enroll.Timepoint48H,
}).ToListAsync();
foreach (var doctor in param.NeedCalculateReviewers)
{
if (await _paymentRepository.AnyAsync(u => u.DoctorId == doctor && u.YearMonth == yearMonth && u.IsLock))
{
break;
}
List<PaymentDetailCommand> paymentDetailList = new List<PaymentDetailCommand>();
decimal totalNormal = 0;
//计算单个医生费用统,并且插入到统计表
var doctorWorkloadAndPayPriceList = workLoadAndPayPriceList.Where(u => u.DoctorId == doctor).ToList();
//阅片数量 计算奖励费用
int readCount = 0;
int codeOrder = 0;
//这里需要改
foreach (var item in doctorWorkloadAndPayPriceList)
{
var doctordata = trialDoctorlist.Where(x => x.IsNewTrial ?? false && x.Training == item.Training && x.DoctorId == item.DoctorId).FirstOrDefault();
if (doctordata != null)
{
item.Training = doctordata.Training??0;
item.Adjudication = doctordata.Adjudication??0;
item.AdjudicationIn24H = doctordata.Adjudication24H??0;
item.AdjudicationIn48H = doctordata.Adjudication48H??0;
item.Downtime = doctordata.Downtime??0;
item.Global = doctordata.Global??0;
item.RefresherTraining = doctordata.RefresherTraining??0;
item.Timepoint = doctordata.Timepoint??0;
item.TimepointIn24H = doctordata.Timepoint24H??0;
item.TimepointIn48H = doctordata.Timepoint48H??0;
item.PersonalAdditional = 0;
}
++codeOrder;
readCount += (item.Timepoint + item.TimepointIn24H + item.TimepointIn48H
+ item.Adjudication + item.AdjudicationIn24H + item.AdjudicationIn48H);
decimal trainingTotal = item.Training * item.TrainingPrice;
decimal refresherTrainingTotal = item.RefresherTraining * item.RefresherTrainingPrice;
decimal downtimeTotal = item.Downtime * item.DowntimePrice;
//规则定义 global 的价格是Tp和个人附加的一半
decimal globalTotal = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2);
//项目如果没有添加附加数据 默认为0
decimal timePointTotal = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional));
decimal timePointIn24HTotal = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
decimal timePointIn48HTotal = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
decimal adjudicationTotal = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional));
decimal adjudicationIn24HTotal = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
decimal adjudicationIn48HTotal = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
totalNormal += (trainingTotal + refresherTrainingTotal + downtimeTotal + globalTotal + timePointTotal + timePointIn24HTotal
+ timePointIn48HTotal + adjudicationTotal + adjudicationIn24HTotal + adjudicationIn48HTotal);
#region
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Training",
Count = item.Training,
BasePrice = item.TrainingPrice,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 1,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.Training * item.TrainingPrice,
PaymentCNY = item.Training * item.TrainingPrice * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Refresher Training",
Count = item.RefresherTraining,
BasePrice = item.RefresherTrainingPrice,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 2,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.RefresherTraining * item.RefresherTrainingPrice,
PaymentCNY = item.RefresherTraining * item.RefresherTrainingPrice * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Downtime",
Count = item.Downtime,
BasePrice = item.DowntimePrice,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 3,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.Downtime * item.DowntimePrice,
PaymentCNY = item.Downtime * item.DowntimePrice * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Timepoint Regular",
Count = item.Timepoint,
BasePrice = item.TimepointPrice,
PersonalAdditional = doctordata!=null?0: item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.TimepointPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional),
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 4,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)),
PaymentCNY = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Timepoint 48-Hour",
Count = item.TimepointIn48H,
BasePrice = item.TimepointIn48HPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.TimepointIn48HPrice * (item.AdjustmentMultiple - 1) + 0,//48小时不加项目附加
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 5,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
PaymentCNY = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Timepoint 24-Hour",
Count = item.TimepointIn24H,
BasePrice = item.TimepointIn24HPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.TimepointIn24HPrice * (item.AdjustmentMultiple - 1) + 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 6,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
PaymentCNY = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Adjudication Regular",
Count = item.Adjudication,
BasePrice = item.AdjudicationPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.AdjudicationPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional),
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 7,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)),
PaymentCNY = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Adjudication 48-Hour",
Count = item.AdjudicationIn48H,
BasePrice = item.AdjudicationIn48HPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn48HPrice * (item.AdjustmentMultiple - 1) + 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 8,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0),
PaymentCNY = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Adjudication 24-Hour",
Count = item.AdjudicationIn24H,
BasePrice = item.AdjudicationIn24HPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn24HPrice * (item.AdjustmentMultiple - 1) + 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 9,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
PaymentCNY = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
});
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = item.TrialCode,
PaymentType = "Global",
Count = item.Global,
BasePrice = item.TimepointPrice / 2,//item.GlobalPrice,
PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional / 2,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = item.DoctorId,
TrialId = item.TrialId,
ShowTypeOrder = 10,
ShowCodeOrder = codeOrder,
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2),
PaymentCNY = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2) * exchangeRate
});
#endregion
}
int typeOrder = 0;
if (readCount > 0)
{
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = "Volume Reward",
PaymentType = "Total TP & AD",
Count = readCount,
BasePrice = 0,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = doctor,
TrialId = Guid.Empty,
ShowTypeOrder = typeOrder,
ShowCodeOrder = (++codeOrder),
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = 0,
PaymentCNY = 0
});
foreach (var awardItem in volumeRewardPriceList)
{
++typeOrder;
if ((readCount - awardItem.Min + 1) < 0)
{
break;
}
if (awardItem.Min == 0)
{
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = "Volume Reward",
PaymentType = awardItem.Min + "-" + awardItem.Max,
Count = readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min) : (readCount - awardItem.Min),
BasePrice = awardItem.Price,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,//result.Data,
DoctorId = doctor,
TrialId = Guid.Empty,
ShowTypeOrder = typeOrder,
ShowCodeOrder = (++codeOrder),
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = (readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price,
PaymentCNY = (readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price * exchangeRate
});
}
else
{
paymentDetailList.Add(new PaymentDetailCommand
{
TrialCode = "Volume Reward",
PaymentType = awardItem.Min + "-" + awardItem.Max,
Count = readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1),
BasePrice = awardItem.Price,
PersonalAdditional = 0,
TrialAdditional = 0,
PaymentId = Guid.Empty,
DoctorId = doctor,
TrialId = Guid.Empty,
ShowTypeOrder = typeOrder,
ShowCodeOrder = (++codeOrder),
ExchangeRate = exchangeRate,
YearMonth = yearMonth,
PaymentUSD = (readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price,
PaymentCNY = (readCount >= awardItem.Max ?
(awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price * exchangeRate
});
}
}
}
decimal award = 0;
volumeRewardPriceList = volumeRewardPriceList.OrderBy(u => u.Min).ToList();
var levelTemp = -1; //用来计算属于哪一个挡位
foreach (var awarPriceitem in volumeRewardPriceList)
{
if (awarPriceitem.Min == 0)
{
if (readCount > awarPriceitem.Max)
{
++levelTemp;
award += (awarPriceitem.Max - awarPriceitem.Min) * awarPriceitem.Price;
}
if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max)
{
++levelTemp;
award += (readCount - awarPriceitem.Min) * awarPriceitem.Price;
break; ;
}
}
else
{
if (readCount > awarPriceitem.Max)
{
++levelTemp;
award += (awarPriceitem.Max - awarPriceitem.Min + 1) * awarPriceitem.Price;
}
if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max)
{
++levelTemp;
award += (readCount - awarPriceitem.Min + 1) * awarPriceitem.Price;
break; ;
}
}
}
decimal totalUSD = award + totalNormal;//总费用
var result = await AddOrUpdateMonthlyPayment(new PaymentCommand
{
DoctorId = doctor,
Year = param.CalculateMonth.Year,
Month = param.CalculateMonth.Month,
PaymentUSD = totalUSD,
CalculateUser = token,
CalculateTime = DateTime.Now,
ExchangeRate = exchangeRate,
PaymentCNY = exchangeRate * totalUSD,
});
reviewerPaymentUSDList.Add(new ReviewerPaymentUSD { DoctorId = doctor, PaymentUSD = totalUSD, RecordId = result.Data });
foreach (var detail in paymentDetailList)
{
//var data = trialDoctorlist.FirstOrDefault(x => x.DoctorId == detail.DoctorId && x.TrialId == detail.TrialId && x.IsNewTrial == true && (x.AdjustmentMultiple??0) != 0);
//if (data != null)
//{
// detail.BasePrice = data.AdjustmentMultiple??0;
// detail.PersonalAdditional = 0;
// detail.TrialAdditional = 0;
//}
detail.PaymentId = result.Data;
}
await AddOrUpdateMonthlyPaymentDetail(paymentDetailList, result.Data);
await UpdatePaymentAdjustment(doctor, yearMonth);
}
return ResponseOutput.Ok(reviewerPaymentUSDList);
}
// 重新计算调整费用
private async Task UpdatePaymentAdjustment(Guid reviewerId, string yearMonth)
{
var adjustList = await _payAdjustmentRepository.Where(u => u.YearMonth == yearMonth &&
!u.IsLock && u.ReviewerId == reviewerId).ToListAsync();
var needUpdatePayment = adjustList.GroupBy(t => t.ReviewerId).Select(g => new
{
ReviewerId = g.Key,
AdjustCNY = g.Sum(t => t.AdjustmentCNY),
AdjustUSD = g.Sum(t => t.AdjustmentUSD)
});
foreach (var reviewer in needUpdatePayment)
{
await _paymentRepository.UpdateFromQueryAsync(u => u.YearMonth == yearMonth &&
!u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment()
{
AdjustmentUSD = reviewer.AdjustUSD,
AdjustmentCNY = reviewer.AdjustCNY
});
}
}
/// <summary>
/// 保存费用计算的月度数据
/// </summary>
private async Task<IResponseOutput<Guid>> AddOrUpdateMonthlyPayment(PaymentCommand addOrUpdateModel)
{
var success = false;
var paymentModel = await _paymentRepository.FirstOrDefaultAsync(t =>
t.DoctorId == addOrUpdateModel.DoctorId && t.YearMonth == addOrUpdateModel.YearMonth);
//var taxCNY = GetTax(addOrUpdateModel.PaymentCNY);
//var actuallyPaidCNY = addOrUpdateModel.PaymentCNY - taxCNY;
//var bankTransferCNY = addOrUpdateModel.PaymentCNY - taxCNY;
if (paymentModel == null)
{
var payment = _mapper.Map<Payment>(addOrUpdateModel);
//payment.BankTransferCNY = bankTransferCNY;
//payment.TaxCNY= taxCNY;
//payment.BankTransferCNY = bankTransferCNY;
payment.YearMonthDate = DateTime.Parse(payment.YearMonth);
payment =await _paymentRepository.AddAsync(payment);
success =await _paymentRepository.SaveChangesAsync();
return ResponseOutput.Result(success, payment.Id);
}
else
{
// 如果是 当月计算的工作量费用 和 调整费用都为0,则删除该行记录
if (addOrUpdateModel.PaymentUSD == 0 && paymentModel.AdjustmentUSD == 0)
{
success =await _paymentRepository.DeleteFromQueryAsync(u => u.Id == paymentModel.Id);
//_paymentDetailRepository.Delete(u=>u.PaymentId==paymentModel.Id);
}
else
{
success = await _paymentRepository.UpdateFromQueryAsync(t => t.Id == paymentModel.Id, u => new Payment()
{
PaymentUSD = addOrUpdateModel.PaymentUSD,
CalculateTime = addOrUpdateModel.CalculateTime,
CalculateUser = addOrUpdateModel.CalculateUser,
//TaxCNY = taxCNY,
//ActuallyPaidCNY = actuallyPaidCNY,
//BankTransferCNY = bankTransferCNY,
PaymentCNY = addOrUpdateModel.PaymentCNY,
ExchangeRate = addOrUpdateModel.ExchangeRate
});
}
return ResponseOutput.Result(success, paymentModel.Id);
}
}
/// <summary>
/// 保存费用计算的月度详情
/// </summary>
private async Task<bool> AddOrUpdateMonthlyPaymentDetail(List<PaymentDetailCommand> addOrUpdateList, Guid paymentId)
{
//var paymentDetailIds = addOrUpdateList.Select(t => t.PaymentId).ToList();
await _paymentDetailRepository.DeleteFromQueryAsync(t => t.PaymentId == paymentId);
await _paymentDetailRepository.AddRangeAsync(_mapper.Map<List<PaymentDetail>>(addOrUpdateList));
return await _paymentDetailRepository.SaveChangesAsync();
}
/// <summary>
/// 获取待计算费用的Reviewer对应的月份列表
/// </summary>
public async Task<List<CalculateNeededDTO>> GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth)
{
Expression<Func<Payment, bool>> calculateLambda = u => !u.IsLock;
if (reviewerId != Guid.Empty)
{
calculateLambda = calculateLambda.And(u => u.DoctorId == reviewerId);
}
if (!string.IsNullOrWhiteSpace(yearMonth))
{
calculateLambda = calculateLambda.And(u => u.YearMonth == yearMonth);
}
return await _paymentRepository.Where(calculateLambda).ProjectTo<CalculateNeededDTO>(_mapper.ConfigurationProvider).ToListAsync();
}
/// <summary>
/// 查询Reviewer某个月的费用是否被锁定
/// </summary>
public async Task<bool> IsLock(Guid reviewerId, string yearMonth)
{
return await _paymentRepository.AnyAsync(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth && u.IsLock);
}
//public bool ResetMonthlyPayment(Guid reviewerId, Guid trialId, string yearMonth)
//{
// var payment = _paymentRepository.FindSingleOrDefault(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth);
// payment.PaymentCNY = 0;
// payment.PaymentUSD = 0;
// _paymentRepository.Update(payment);
// _paymentDetailRepository.Delete(u=>u.DoctorId==reviewerId && u.TrialId==trial)
//}
}
}
@@ -0,0 +1,37 @@
using System;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public class AwardPriceDTO: AwardPriceCalculateDTO
{
public Guid Id { get; set; }
}
public class AwardPriceCalculateDTO
{
public decimal Price { get; set; }
public int Max { get; set; }
public int Min { get; set; }
}
public class AwardPriceCommand
{
//public Guid Id { get; set; }
public decimal Price { get; set; }
public int Min { get; set; }
public int Max { get; set; }
public Guid OptUserId { get; set; }
}
public class AwardPriceQueryDTO : PageInput
{
}
public class ExchangeRateQueryDTO : PageInput
{
public DateTime? SearchMonth { get; set; }
}
}
@@ -0,0 +1,44 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class CalculateNeededDTO
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public string YearMonth { get; set; } = String.Empty;
public bool IsLock { get; set; }
}
public class DoctorPrice
{
public decimal? AdjustmentMultiple { get; set; }
public Guid? DoctorId { get; set; }
public Guid? TrialId { get; set; }
public bool? IsNewTrial { get; set; }
public int? Training { get; set; }
public int? RefresherTraining { get; set; }
public int? Timepoint { get; set; }
public int? Timepoint48H { get; set; }
public int? Timepoint24H { get; set; }
public int? Adjudication { get; set; }
public int? Adjudication48H { get; set; }
public int? Adjudication24H { get; set; }
public int? Global { get; set; }
public int? Downtime { get; set; }
}
}
@@ -0,0 +1,13 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class ExchangeRateCommand
{
public Guid? Id { get; set; }
public string YearMonth { get; set; }=String.Empty;
public decimal Rate { get; set; }
public DateTime UpdateTime { get; set; }
}
}
@@ -0,0 +1,54 @@
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts.Pay
{
public class PaymentAdjustmentCommand
{
public Guid? Id { get; set; }
public Guid ReviewerId { get; set; }
public DateTime YearMonth { get; set; }
public decimal AdjustPaymentUSD { get; set; }
public decimal AdjustPaymentCNY { get; set; }
public string Note { get; set; } = string.Empty;
}
public class PaymentAdjustmentDTO
{
public Guid Id { get; set; }
public Guid ReviewerId { get; set; }
public string YearMonth { get; set; }=String.Empty;
public DateTime YearMonthDate { get; set; }
public bool IsLock { get; set; }
public decimal AdjustPaymentUSD { get; set; }
public decimal AdjustPaymentCNY { get; set; }
public string Note { get; set; } = String.Empty;
}
public class PaymentAdjustmentDetailDTO: PaymentAdjustmentDTO
{
public string ReviewerCode { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string FullName => LastName + " / " + FirstName;
public string ChineseName { get; set; } = String.Empty;
}
public class PaymentAdjustmentQueryDTO:PageInput
{
public string TrialCode { get; set; } = string.Empty;
public string Reviewer { get; set; } = string.Empty;
public DateTime BeginMonth { get; set; }
public DateTime EndMonth { get; set; }
}
public class DoctorSelectDTO
{
public Guid Id { get; set; }
public string Code { get; set; } = string.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string FullName => LastName + " / " + FirstName;
public string ChineseName { get; set; } = String.Empty;
}
}
@@ -0,0 +1,193 @@
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts.Pay
{
public class PaymentDetailDTO
{
public Guid Id { get; set; }
public Guid PaymentId { get; set; }
public string YearMonth { get; set; } = String.Empty;
public Guid DoctorId { get; set; }
public Guid TrialId { get; set; }
public string TrialCode { get; set; } = String.Empty;
public string PaymentType { get; set; } = String.Empty;
public int Count { get; set; }
public decimal BasePrice { get; set; }
public decimal PersonalAdditional { get; set; }
public decimal? NewPersonalAdditional { get; set; }
public decimal TrialAdditional { get; set; }
public int ShowTypeOrder { get; set; }
public int ShowCodeOrder { get; set; }
public decimal ExchangeRate { get; set; }
public decimal PaymentUSD { get; set; }
public decimal PaymentCNY { get; set; }
public bool? IsNewTrial { get; set; }
public decimal TotalUnitPrice => BasePrice + PersonalAdditional + TrialAdditional;
public AdjustmentDTO AdjustmentView { get; set; } = new AdjustmentDTO();
}
public class AdjustmentDTO
{
public decimal AdjustPaymentUSD { get; set; }
public decimal AdjustPaymentCNY { get; set; }
public string AdjustType
{
get
{
if (AdjustPaymentUSD > 0)
{
return "+";
}
else if (AdjustPaymentUSD < 0)
{
return "-";
}
else { return string.Empty; }
}
}
public string Note { get; set; } = String.Empty;
}
public class PaymentDetailCommand : PaymentDetailDTO
{
}
public class PayDetailDTO
{
public IEnumerable<PaymentDetailDTO> DetailList { get; set; } = new List<PaymentDetailDTO>();
public DoctorPayInfo DoctorInfo { get; set; } = new DoctorPayInfo();
}
public class LockPaymentDTO
{
public List<Guid> ReviewerIdList { get; set; }=new List<Guid>();
public DateTime Month { get; set; }
public bool IsLock { get; set; } = true;
}
public class DoctorPayInfo
{
public Guid DoctorId { get; set; }
public string ChineseName { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string Phone { get; set; } = String.Empty;
public string PayTitle { get; set; } = String.Empty;
public string Code { get; set; } = String.Empty;
public string YearMonth { get; set; } = String.Empty;
}
public class ReviewerPaymentUSD
{
public Guid RecordId { get; set; }
public Guid DoctorId { get; set; }
public decimal PaymentUSD { get; set; }
}
public class PaymentQueryDTO : PageInput
{
public string Reviewer { get; set; } = String.Empty;
public DateTime BeginMonth { get; set; }
public DateTime EndMonth { get; set; }
public int? Nation { get; set; }
}
public class MonthlyPaymentDTO
{
public Guid ReviewerId { get; set; }
public string ReviewerCode { get; set; } = String.Empty;
public string ChineseName { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public decimal AdjustmentUSD { get; set; }
public decimal AdjustmentCNY { get; set; }
public decimal PaymentUSD { get; set; }
public decimal PaymentCNY { get; set; }
public decimal TotalUSD { get; set; }
public decimal TotalCNY { get; set; }
}
public class VolumeStatisticsDTO
{
public Guid StatisticsId { get; set; }
public string Month { get; set; } = String.Empty;
public decimal VolumeReward { get; set; }
public decimal ExchangeRate { get; set; }
public decimal AdjustmentUSD { get; set; }
public decimal AdjustmentCNY { get; set; }
public decimal PaymentUSD { get; set; }
public decimal PaymentCNY { get; set; }
public decimal TotalCNY => AdjustmentCNY + PaymentCNY;
public decimal TotalUSD => AdjustmentUSD + PaymentUSD;
public List<TrialPaymentDTO> TrialPaymentList = new List<TrialPaymentDTO>();
}
public class TrialPaymentDTO
{
public Guid TrialId { get; set; }
public string TrialCode { get; set; } = String.Empty;
public decimal TrialPayment { get; set; }
}
public class VolumeQueryDTO
{
public DateTime BeginMonth { get; set; }
public DateTime EndMonth { get; set; }
public Guid ReviewerId { get; set; }
}
public class RevenuesDTO
{
public List<string> MissingTrialCodes = new List<string>();
public Guid Id { get; set; }
public string TrialCode { get; set; } = String.Empty;
public Guid TrialId { get; set; }
public string Indication { get; set; } = String.Empty;
public Guid? CroId { get; set; }
public string Cro { get; set; } = string.Empty;
public int Expedited { get; set; }
public string ChineseName { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string ReviewerCode { get; set; } = string.Empty;
public decimal Training { get; set; }
public decimal Downtime { get; set; }
public decimal Timepoint { get; set; }
public decimal TimepointIn24H { get; set; }
public decimal TimepointIn48H { get; set; }
public decimal Adjudication { get; set; }
public decimal AdjudicationIn24H { get; set; }
public decimal AdjudicationIn48H { get; set; }
public decimal Global { get; set; }
public decimal Total { get; set; }
public string YearMonth { get; set; } = String.Empty;
}
}
@@ -0,0 +1,178 @@
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts
{
public class PaymentDTO
{
public PageOutput<PaymentModel> CostList { get; set; }=new PageOutput<PaymentModel>();
public decimal ExchangeRate { get; set; }
}
public class PaymentModel
{
public Guid Id { get; set; }
public string RankName { get; set; } = String.Empty;
public Guid DoctorId { get; set; }
public string YearMonth { get; set; } = String.Empty;
public DateTime YearMonthDate { get; set; }
public DateTime? CalculateTime { get; set; }
public string CalculateUser { get; set; } = String.Empty;
//额外信息
public string Code { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string ChineseName { get; set; } = String.Empty;
public string Phone { get; set; } = String.Empty;
public string DoctorNameInBank { get; set; } = String.Empty;
public string IDCard { get; set; } = String.Empty;
public string BankCardNumber { get; set; } = String.Empty;
public string BankName { get; set; } = String.Empty;
public bool IsLock { get; set; } = false;
public decimal ExchangeRate { get; set; }
public decimal PaymentCNY { get; set; }
public decimal AdjustPaymentCNY { get; set; }
public decimal TotalPaymentCNY { get; set; }
public decimal PaymentUSD { get; set; }
public decimal AdjustPaymentUSD { get; set; }
public decimal TotalPaymentUSD { get; set; }
}
public class PaymentCommand
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public string YearMonth => new DateTime(Year, Month, 1).ToString("yyyy-MM");
public int Year { get; set; }
public int Month { get; set; }
public decimal PaymentUSD { get; set; }
public DateTime CalculateTime { get; set; }
public decimal PaymentCNY { get; set; }
public decimal ExchangeRate { get; set; }
public string CalculateUser { get; set; } = String.Empty;
}
public class MonthlyPaymentQueryDTO : PageInput
{
public DateTime StatisticsDate { get; set; }
public string KeyWord { get; set; } = String.Empty;
public int? Nation { get; set; }
}
public class MonthlyPaymentDetailQuery
{
public Guid PaymentId { get; set; }
public Guid ReviewerId { get; set; }
public DateTime YearMonth { get; set; }
}
//public class LaborPaymentQuery
//{
// public Guid PaymentId { get; set; }
// public Guid ReviewerId { get; set; }
// public DateTime YearMonth { get; set; }
//}
public class TrialAnalysisDTO
{
public Guid TrialId { get; set; }
public string Indication { get; set; } = String.Empty;
public string TrialCode { get; set; } = String.Empty;
public string Cro { get; set; } = string.Empty;
public int Expedited { get; set; }
public string Type { get; set; } = String.Empty;
public decimal PaymentUSD { get; set; }
public decimal RevenusUSD { get; set; }
public decimal GrossProfit => RevenusUSD - PaymentUSD;
public decimal GrossProfitMargin
{
get {
if (RevenusUSD == 0)
return 0;
else
{
return GrossProfit / RevenusUSD;
}
}
}
}
public class LaborPayment
{
public string ChineseName { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string ResidentId { get; set; } = String.Empty;
public string Phone { get; set; } = String.Empty;
public string AccountNumber { get; set; } = String.Empty;
public string Bank { get; set; } = String.Empty;
public string YearMonth { get; set; } = String.Empty;
public decimal PaymentCNY { get; set; }
public decimal TaxCNY { get; set; }
public decimal ActuallyPaidCNY { get; set; }
public decimal BankTransferCNY { get; set; }
}
public class ReviewerAnalysisDTO
{
public List<string> MissingTrialCodes = new List<string>();
public string ChineseName { get; set; } = String.Empty;
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public Guid ReviewerId { get; set; }
public string ReviewerCode { get; set; } = String.Empty;
public decimal PaymentUSD { get; set; }
public decimal RevenusUSD { get; set; }
public decimal GrossProfit => RevenusUSD - PaymentUSD;
public decimal GrossProfitMargin
{
get {
if (RevenusUSD == 0)
return 0;
else
{
return GrossProfit / RevenusUSD;
}
}
}
}
public class AnalysisQueryDTO
{
public string Reviewer { get; set; } = String.Empty;
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public int? Nation { get; set; }
}
public class TrialAnalysisQueryDTO
{
public Guid? CroId { get; set; }
public string TrialCode { get; set; } = String.Empty;
public DateTime BeginDate { get; set; }
public DateTime EndDate { get; set; }
public int? AttendedReviewerType { get; set; }
}
}
@@ -0,0 +1,50 @@
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts
{
public class RankPriceDTO
{
public Guid Id { get; set; }
public string RankName { get; set; } = string.Empty;
public decimal Timepoint { get; set; }
public decimal TimepointIn24H { get; set; }
public decimal TimepointIn48H { get; set; }
public decimal Adjudication { get; set; }
public decimal AdjudicationIn24H { get; set; }
public decimal AdjudicationIn48H { get; set; }
public decimal Global { get; set; }
public decimal Training { get; set; }
public decimal Downtime { get; set; }
public decimal RefresherTraining { get; set; }
public int ShowOrder { get; set; }
}
public class RankDic
{
public Guid Id { get; set; }
public string RankName { get; set; } = string.Empty;
}
public class RankPriceCommand
{
public Guid? Id { get; set; }
public string RankName { get; set; } = string.Empty;
public decimal Timepoint { get; set; }
public decimal TimepointIn24H { get; set; }
public decimal TimepointIn48H { get; set; }
public decimal Adjudication { get; set; }
public decimal AdjudicationIn24H { get; set; }
public decimal AdjudicationIn48H { get; set; }
public decimal Global { get; set; }
public decimal Training { get; set; }
public decimal Downtime { get; set; }
public decimal RefresherTraining { get; set; }
}
public class RankPriceQueryDTO : PageInput
{
}
}
@@ -0,0 +1,40 @@
using System;
namespace IRaCIS.Application.Contracts
{
public class ReviewerPayInfoQueryDTO
{
public Guid DoctorId { get; set; }
public string FirstName { get; set; } = String.Empty;
public string LastName { get; set; } = String.Empty;
public string ChineseName { get; set; } = String.Empty;
public string Code { get; set; } = String.Empty;
public string Phone { get; set; } = String.Empty;
public string DoctorNameInBank { get; set; } = String.Empty;
public string IDCard { get; set; } = String.Empty;
public string BankCardNumber { get; set; } = String.Empty;
public string BankName { get; set; } = String.Empty;
public Guid? RankId { get; set; }
public decimal? Additional { get; set; }
public DateTime? CreateTime { get; set; }
}
public class DoctorPayInfoQueryListDTO : ReviewerPayInfoQueryDTO
{
public string Hospital { get; set; } = String.Empty;
public string RankName { get; set; } = String.Empty;
}
public class ReviewerPayInfoCommand
{
//public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public string DoctorNameInBank { get; set; } = String.Empty;
public string IDCard { get; set; } = String.Empty;
public string BankCardNumber { get; set; } = String.Empty;
public string BankName { get; set; } = String.Empty;
public Guid RankId { get; set; }
public decimal? Additional { get; set; }
}
}
@@ -0,0 +1,46 @@
using IRaCIS.Core.Domain.Share;
using System;
namespace IRaCIS.Application.Contracts
{
public class DtoDoctorList
{
public Guid TrialId { get; set; }
public string Name { get; set; }
}
public class TrialPaymentPriceDTO
{
public Guid TrialId { get; set; }
public string TrialCode { get; set; } = String.Empty;
public string Indication { get; set; } = String.Empty;
public string Cro { get; set; } = String.Empty;
public int Expedited { get; set; }
public bool? IsNewTrial { get; set; }
public decimal? TrialAdditional { get; set; }
public DateTime? CreateTime { get; set; }
public string SowName { get; set; } = String.Empty;
public string SowPath { get; set; } = String.Empty;
public string SowFullPath => SowPath;
public decimal AdjustmentMultiple { get; set; } = 1;
public string DoctorsNames{ get; set; }=String.Empty;
public string ReviewMode { get; set; } = String.Empty;
}
public class TrialPaymentPriceCommand
{
public Guid TrialId { get; set; }
public decimal TrialAdditional { get; set; }
public decimal AdjustmentMultiple { get; set; }
public bool? IsNewTrial { get; set; }
}
}
@@ -0,0 +1,37 @@
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Contracts
{
public class TrialRevenuesPriceDTO
{
public Guid TrialId { get; set; }
public decimal Timepoint { get; set; }
public decimal TimepointIn24H { get; set; }
public decimal TimepointIn48H { get; set; }
public decimal Adjudication { get; set; }
public decimal AdjudicationIn24H { get; set; }
public decimal AdjudicationIn48H { get; set; }
public decimal RefresherTraining { get; set; }
public decimal Global { get; set; }
public decimal Training { get; set; }
public decimal Downtime { get; set; }
}
public class TrialRevenuesPriceDetialDTO : TrialRevenuesPriceDTO
{
public Guid Id { get; set; }
public string TrialCode { get; set; } = String.Empty;
public string Indication { get; set; } = string.Empty;
public int Expedited { get; set; }
public string ReviewMode { get; set; } = String.Empty;
public string Cro { get; set; } = String.Empty;
}
public class TrialRevenuesPriceQueryDTO : PageInput
{
public string KeyWord { get; set; } = String.Empty;
public Guid? CroId { get; set; }
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.Contracts
{
public class RevenusVerifyQueryDTO
{
public DateTime BeginDate { get; set; } = DateTime.Now;
public DateTime EndDate { get; set; } = DateTime.Now;
}
public class AnalysisVerifyQueryDTO
{
public DateTime BeginDate { get; set; } = DateTime.Now;
public DateTime EndDate { get; set; } = DateTime.Now;
}
public class AnalysisNeedLockDTO
{
public string YearMonth { get; set; } = string.Empty;
public string ReviewerCode { get; set; } = string.Empty;
public string ReviewerName { get; set; } = string.Empty;
public string ReviewerNameCN { get; set; } = string.Empty;
}
public class AnalysisVerifyResultDTO
{
public List<MonthlyResult> MonthVerifyResult = new List<MonthlyResult>();
public List<RevenusVerifyDTO> RevenuesVerifyList = new List<RevenusVerifyDTO>();
}
public class MonthlyResult
{
public string YearMonth { get; set; } = string.Empty;
public List<string> ReviewerNameList = new List<string>();
public List<string> ReviewerNameCNList = new List<string>();
public List<string> ReviewerCodeList = new List<string>();
}
public class RevenusVerifyDTO
{
public string TrialCode { get; set; } = string.Empty;
public bool Training { get; set; } = false;
public bool Downtime { get; set; } = false;
public bool Global { get; set; } = false;
public bool Timepoint { get; set; } = false;
public bool TimepointIn24H { get; set; } = false;
public bool TimepointIn48H { get; set; } = false;
public bool Adjudication { get; set; } = false;
public bool AdjudicationIn24H { get; set; } = false;
public bool AdjudicationIn48H { get; set; } = false;
}
}
@@ -0,0 +1,115 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Financial")]
public class ExchangeRateService : BaseService, IExchangeRateService
{
private readonly IRepository<ExchangeRate> _exchangeRateRepository;
private readonly IRepository<Payment> _paymentRepository;
public ExchangeRateService(IRepository<ExchangeRate> exchangeRateRepository, IRepository<Payment> paymentRepository)
{
_exchangeRateRepository = exchangeRateRepository;
_paymentRepository = paymentRepository;
}
[NonDynamicMethod]
public async Task<IResponseOutput> AddOrUpdateExchangeRate(ExchangeRateCommand model)
{
if (model.Id == Guid.Empty || model.Id == null)
{
var existItem = await _exchangeRateRepository.FirstOrDefaultAsync(u => u.YearMonth == model.YearMonth);
if (existItem != null)
{
return ResponseOutput.NotOk("The exchange rate of the same month already existed.");
}
var rate = _mapper.Map<ExchangeRate>(model);
rate = await _exchangeRateRepository.AddAsync(rate);
if (await _exchangeRateRepository.SaveChangesAsync())
{
return ResponseOutput.Ok(rate.Id.ToString());
}
else
{
return ResponseOutput.NotOk();
}
}
else
{
var success = await _exchangeRateRepository.UpdateFromQueryAsync(t => t.Id == model.Id, u => new ExchangeRate()
{
//YearMonth = model.YearMonth,
Rate = model.Rate,
UpdateTime = DateTime.Now
});
return ResponseOutput.Result(success);
}
}
/// <summary>
/// 根据记录Id,删除汇率记录
/// </summary>
/// <param name="id">汇率记录Id</param>
[HttpDelete("{id:guid}")]
public async Task<IResponseOutput> DeleteExchangeRate(Guid id)
{
var monthInfo = await _exchangeRateRepository.FirstOrDefaultAsync(t => t.Id == id);
if (await _paymentRepository.AnyAsync(t => t.YearMonth == monthInfo.YearMonth))
{
return ResponseOutput.NotOk("The exchange rate has been used in monthly payment");
}
var success = await _exchangeRateRepository.DeleteFromQueryAsync(t => t.Id == id);
return ResponseOutput.Ok(success);
}
[NonDynamicMethod]
public async Task<decimal> GetExchangeRateByMonth(string month)
{
//var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth.Equals(month));
//if (rate == null)
//{
// return 0;
//}
//return rate.Rate;
var rate = await _exchangeRateRepository.FirstOrDefaultAsync(t => t.YearMonth == month);
if (rate == null)
{
return 0;
}
return rate.Rate;
}
[HttpPost]
public async Task<PageOutput<ExchangeRateCommand>> GetExchangeRateList(ExchangeRateQueryDTO queryParam)
{
var yearMonth = queryParam.SearchMonth?.ToString("yyyy-MM");
var exchangeRateQueryable = _exchangeRateRepository.AsQueryable()
.WhereIf(queryParam.SearchMonth != null, o => o.YearMonth == yearMonth)
.ProjectTo<ExchangeRateCommand>(_mapper.ConfigurationProvider);
return await exchangeRateQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, "YearMonth", false);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,16 @@
using IRaCIS.Application.Contracts;
using System;
using System.Collections.Generic;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface ICalculateService
{
Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token);
//IResponseOutput LockMonthlyPayment(LockPaymentDTO param);
Task<List<CalculateNeededDTO>> GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth);
Task<bool> IsLock(Guid reviewerId, string yearMonth);
//bool ResetMonthlyPayment(Guid reviewerId, Guid trialId,string yearMonth);
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IReviewerPayInfoService
{
Task<IResponseOutput> AddOrUpdateReviewerPayInfo(ReviewerPayInfoCommand addOrUpdateModel, Guid userId);
Task<PageOutput<DoctorPayInfoQueryListDTO>> GetReviewerPayInfoList(DoctorPaymentInfoQueryDTO queryParam);
Task<DoctorPayInfoQueryListDTO> GetReviewerPayInfo(Guid doctorId);
Task<List<Guid>> GetReviewerIdByRankId(Guid rankId);
}
}
@@ -0,0 +1,15 @@
using IRaCIS.Application.Contracts;
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IExchangeRateService
{
Task<IResponseOutput> AddOrUpdateExchangeRate(ExchangeRateCommand model);
Task<decimal> GetExchangeRateByMonth(string month);
Task<PageOutput<ExchangeRateCommand>> GetExchangeRateList(ExchangeRateQueryDTO queryParam);
Task<IResponseOutput> DeleteExchangeRate(Guid id);
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IPaymentAdjustmentService
{
Task<PageOutput<PaymentAdjustmentDetailDTO>> GetPaymentAdjustmentList(PaymentAdjustmentQueryDTO queryParam);
Task<IResponseOutput> AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel);
Task<IResponseOutput> DeletePaymentAdjustment(Guid id);
Task CalculateCNY(string yearMonth, decimal rate);
Task<List<DoctorSelectDTO>> GetReviewerSelectList();
}
}
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IPaymentService
{
Task<IResponseOutput> LockMonthlyPayment(LockPaymentDTO param);
Task<PageOutput<PaymentModel>> GetMonthlyPaymentList(MonthlyPaymentQueryDTO queryParam);
Task<PayDetailDTO> GetMonthlyPaymentDetailList(Guid PaymentId, Guid doctorId, DateTime yearMonth);
Task<List<LaborPayment>> GetLaborPaymentList(List<Guid> paymentId);
//导出多个医生的付费详细
Task<List<PayDetailDTO>> GetReviewersMonthlyPaymentDetail(List<MonthlyPaymentDetailQuery> manyReviewers);
Task<PageOutput<MonthlyPaymentDTO>> GetPaymentHistoryList(PaymentQueryDTO param);
Task<List<VolumeStatisticsDTO>> GetPaymentHistoryDetailList(VolumeQueryDTO param);
Task<PageOutput<RevenuesDTO>> GetRevenuesStatistics(StatisticsQueryDTO param);
Task<List<TrialAnalysisDTO>> GetTrialAnalysisList(TrialAnalysisQueryDTO param);
Task<List<ReviewerAnalysisDTO>> GetReviewerAnalysisList(AnalysisQueryDTO param);
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IRankPriceService
{
Task<IResponseOutput> AddOrUpdateRankPrice(RankPriceCommand addOrUpdateModel, Guid userId);
Task<PageOutput<RankPriceDTO>> GetRankPriceList(RankPriceQueryDTO queryParam);
Task<IResponseOutput> DeleteRankPrice( Guid id);
Task<List<RankDic>> GetRankDic();
}
}
@@ -0,0 +1,21 @@
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface ITrialPaymentPriceService
{
Task<IResponseOutput> AddOrUpdateTrialPaymentPrice(TrialPaymentPriceCommand addOrUpdateModel);//新增也不需要返回Id,TrialId 也是唯一
Task<PageOutput<TrialPaymentPriceDTO>> GetTrialPaymentPriceList(TrialPaymentPriceQueryDTO queryParam);
/// <summary>
/// 上传入组后的Ack-SOW
/// </summary>
Task<IResponseOutput> UploadTrialSOW( TrialSOWPathDTO trialSowPath);
Task<IResponseOutput> DeleteTrialSOW( DeleteSowPathDTO trialSowPath);
}
}
@@ -0,0 +1,14 @@
using IRaCIS.Application.Contracts;
using System;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface ITrialRevenuesPriceService
{
Task<IResponseOutput> AddOrUpdateTrialRevenuesPrice(TrialRevenuesPriceDTO model);
Task<bool> DeleteTrialCost(Guid Id);
Task<PageOutput<TrialRevenuesPriceDetialDTO>> GetTrialRevenuesPriceList(TrialRevenuesPriceQueryDTO param);
}
}
@@ -0,0 +1,17 @@
using IRaCIS.Core.Application.Contracts;
using System.Collections.Generic;
namespace IRaCIS.Application.Interfaces
{
public interface ITrialRevenuesPriceVerificationService
{
//List<RevenusVerifyDTO> GetRevenuesVerifyResultList(RevenusVerifyQueryDTO param);
Task<AnalysisVerifyResultDTO> GetAnalysisVerifyList(RevenusVerifyQueryDTO param);
Task<List<RevenusVerifyDTO>> GetRevenuesVerifyList(RevenusVerifyQueryDTO param);
}
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Application.Interfaces
{
public interface IVolumeRewardService
{
Task<IResponseOutput> AddOrUpdateVolumeRewardPriceList(IEnumerable<AwardPriceCommand> addOrUpdateModels);
Task<PageOutput<AwardPriceDTO>> GetVolumeRewardPriceList(AwardPriceQueryDTO queryParam);
Task<List<AwardPriceCalculateDTO>> GetVolumeRewardPriceList();
}
}
@@ -0,0 +1,292 @@
using AutoMapper;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Financial")]
public class PaymentAdjustmentService : BaseService, IPaymentAdjustmentService
{
private readonly IRepository<PaymentAdjustment> _payAdjustmentRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<ExchangeRate> _exchangeRateRepository;
private readonly IRepository<Payment> _paymentRepository;
public PaymentAdjustmentService(IRepository<PaymentAdjustment> costAdjustmentRepository, IRepository<Doctor> doctorRepository,
IRepository<ExchangeRate> exchangeRateRepository, IRepository<Payment> paymentRepository, IMapper mapper)
{
_payAdjustmentRepository = costAdjustmentRepository;
_doctorRepository = doctorRepository;
_exchangeRateRepository = exchangeRateRepository;
_paymentRepository = paymentRepository;
}
/// <summary>
/// 添加或更新费用调整[AUTH]
/// </summary>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdatePaymentAdjustment(PaymentAdjustmentCommand addOrUpdateModel)
{
var yearMonthDate = new DateTime(addOrUpdateModel.YearMonth.Year, addOrUpdateModel.YearMonth.Month, 1);
var yearMonth = addOrUpdateModel.YearMonth.ToString("yyyy-MM");
var payment = await _paymentRepository.FirstOrDefaultAsync(u => u.DoctorId == addOrUpdateModel.ReviewerId
&& u.YearMonth == yearMonth);
//判断付费表中是否有记录
if (payment == null)
{
//没有 添加仅有的调整费用记录
payment = new Payment
{
DoctorId = addOrUpdateModel.ReviewerId,
YearMonth = yearMonth,
YearMonthDate = yearMonthDate,
PaymentCNY = 0,
PaymentUSD = 0,
AdjustmentCNY = 0,
AdjustmentUSD = 0
};
await _paymentRepository.AddAsync(payment);
await _paymentRepository.SaveChangesAsync();
}
else
{
if (payment.IsLock)
{
return ResponseOutput.NotOk("Doctor payment has confirmed lock");
}
}
var exchangeRate = await _exchangeRateRepository.FirstOrDefaultAsync(t => t.YearMonth == yearMonth);
if (addOrUpdateModel.Id == Guid.Empty || addOrUpdateModel.Id == null)
{
var costAdjustment = _mapper.Map<PaymentAdjustment>(addOrUpdateModel);
//视图模型和领域模型没对应 重新赋值
costAdjustment.ExchangeRate = exchangeRate?.Rate ?? 0;
costAdjustment.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);
costAdjustment.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;
await _payAdjustmentRepository.AddAsync(costAdjustment);
//添加的时候,每个月调整汇总费用 需要加上本次调整的费用
payment.AdjustmentCNY += costAdjustment.AdjustmentCNY;
payment.AdjustmentUSD += costAdjustment.AdjustmentUSD;
await _paymentRepository.UpdateAsync(payment);
await _payAdjustmentRepository.SaveChangesAsync();
return ResponseOutput.Ok(costAdjustment.Id.ToString());
}
else
{
// 更新的时候,先查出来,更新前的调整费用数据
var paymentAdjust = await _payAdjustmentRepository.FirstOrDefaultAsync(t => t.Id == addOrUpdateModel.Id);
_mapper.Map(addOrUpdateModel, paymentAdjust);
paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0;
paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;
paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);
await _payAdjustmentRepository.UpdateAsync(paymentAdjust);
var success = await _payAdjustmentRepository.SaveChangesAsync();
if (success)
{
var adjustmentList = await _payAdjustmentRepository.Where(u => u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth).ToListAsync();
payment.AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY);
payment.AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD);
await _paymentRepository.UpdateAsync(payment);
await _paymentRepository.SaveChangesAsync();
}
//查询得到历史汇总
return ResponseOutput.Ok(success);
#region
//// 更新的时候,先查出来,更新前的调整费用数据
//var paymentAdjust = _payAdjustmentRepository.FindSingleOrDefault(t => t.Id == addOrUpdateModel.Id);
////减去数据库本条记录的值
//payment.AdjustmentCNY = -paymentAdjust.AdjustmentCNY;
//payment.AdjustmentUSD = -paymentAdjust.AdjustmentUSD;
//_mapper.Map(addOrUpdateModel, paymentAdjust);
//paymentAdjust.ExchangeRate = exchangeRate?.Rate ?? 0;
//paymentAdjust.AdjustmentUSD = addOrUpdateModel.AdjustPaymentUSD;
//paymentAdjust.AdjustmentCNY = addOrUpdateModel.AdjustPaymentUSD * (exchangeRate?.Rate ?? 0);
//_payAdjustmentRepository.Update(paymentAdjust);
////查询得到历史汇总
//var adjustment = _payAdjustmentRepository.Find(u => u.ReviewerId == addOrUpdateModel.ReviewerId && u.YearMonth == yearMonth)
// .GroupBy(u => new { u.ReviewerId, u.YearMonth }).Select(g => new
// {
// AdjustCNY = g.Sum(t => t.AdjustmentCNY),
// AdjustUSD = g.Sum(t => t.AdjustmentUSD)
// }).FirstOrDefault();
////最终的值 等于历史汇总 减去更新前的加上当前更新的值
//payment.AdjustmentCNY += (adjustment.AdjustCNY + paymentAdjust.AdjustmentCNY);
//payment.AdjustmentUSD += (adjustment.AdjustUSD + paymentAdjust.AdjustmentUSD);
//_paymentRepository.Update(payment);
//var success = _payAdjustmentRepository.SaveChanges();
//return ResponseOutput.Result(success, success ? string.Empty : StaticData.UpdateFailed);
#endregion
}
}
/// <summary>
/// 删除费用调整记录
/// </summary>
[HttpDelete("{id:guid}")]
public async Task<IResponseOutput> DeletePaymentAdjustment(Guid id)
{
var adjustPayment = await _payAdjustmentRepository.FirstOrDefaultAsync(u => u.Id == id);
var monthPay = await _paymentRepository.FirstOrDefaultAsync(t =>
t.DoctorId == adjustPayment.ReviewerId && t.YearMonth == adjustPayment.YearMonth);
await _payAdjustmentRepository.DeleteAsync(new PaymentAdjustment() { Id = id });
var success = await _payAdjustmentRepository.SaveChangesAsync();
if (success)
{
var adjustmentList = await _payAdjustmentRepository.Where(u =>
u.ReviewerId == adjustPayment.ReviewerId && u.YearMonth == adjustPayment.YearMonth).ToListAsync();
monthPay.AdjustmentCNY = adjustmentList.Sum(t => t.AdjustmentCNY);
monthPay.AdjustmentUSD = adjustmentList.Sum(t => t.AdjustmentUSD);
await _paymentRepository.UpdateAsync(monthPay);
await _paymentRepository.SaveChangesAsync();
}
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取费用调整列表
/// </summary>
[HttpPost]
public async Task<PageOutput<PaymentAdjustmentDetailDTO>> GetPaymentAdjustmentList(PaymentAdjustmentQueryDTO queryParam)
{
var beginYearMonth = queryParam.BeginMonth.AddDays(1 - queryParam.BeginMonth.Day);
var endYearMonth = queryParam.EndMonth.AddDays(1 - queryParam.EndMonth.Day).AddMonths(1).AddDays(-1);
var costAdjustmentQueryable = from costAdjustment in _payAdjustmentRepository
.Where(t => t.YearMonthDate >= beginYearMonth && t.YearMonthDate <= endYearMonth)
join doctor in _doctorRepository.AsQueryable().
WhereIf(!string.IsNullOrWhiteSpace(queryParam.Reviewer),
u => u.ChineseName.Contains(queryParam.Reviewer) ||
(u.LastName + u.FirstName).Contains(queryParam.Reviewer) ||
u.ReviewerCode.Contains(queryParam.Reviewer))
on costAdjustment.ReviewerId equals doctor.Id
select new PaymentAdjustmentDetailDTO()
{
AdjustPaymentCNY = costAdjustment.AdjustmentCNY,
AdjustPaymentUSD = costAdjustment.AdjustmentUSD,
IsLock = costAdjustment.IsLock,
Id = costAdjustment.Id,
YearMonth = costAdjustment.YearMonth,
YearMonthDate = costAdjustment.YearMonthDate,
Note = costAdjustment.Note,
ReviewerId = costAdjustment.ReviewerId,
ReviewerCode = doctor.ReviewerCode,
FirstName = doctor.FirstName,
LastName = doctor.LastName,
ChineseName = doctor.ChineseName
};
return await costAdjustmentQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, string.IsNullOrWhiteSpace(queryParam.SortField) ? "YearMonthDate" : queryParam.SortField, queryParam.Asc);
}
public async Task<List<DoctorSelectDTO>> GetReviewerSelectList()
{
return await _doctorRepository.Where(t => t.CooperateStatus == ContractorStatusEnum.Cooperation && t.ResumeStatus == ResumeStatusEnum.Pass).ProjectTo<DoctorSelectDTO>(_mapper.ConfigurationProvider).ToListAsync();
}
[NonDynamicMethod]
public async Task CalculateCNY(string yearMonth, decimal rate)
{
//如果是double 不会保留两位小数
await _payAdjustmentRepository.UpdateFromQueryAsync(u => u.YearMonth == yearMonth &&
!u.IsLock, t => new PaymentAdjustment
{
AdjustmentCNY = t.AdjustmentUSD * rate,
ExchangeRate = rate,
UpdateTime = DateTime.Now
});
var adjustList = await _payAdjustmentRepository.Where(u => u.YearMonth == yearMonth &&
!u.IsLock).ToListAsync();
var needUpdatePayment = adjustList.GroupBy(t => t.ReviewerId).Select(g => new
{
ReviewerId = g.Key,
AdjustCNY = g.Sum(t => t.AdjustmentCNY),
AdjustUSD = g.Sum(t => t.AdjustmentUSD)
});
foreach (var reviewer in needUpdatePayment)
{
await _paymentRepository.UpdateFromQueryAsync(u => u.YearMonth == yearMonth &&
!u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment()
{
AdjustmentUSD = reviewer.AdjustUSD,
AdjustmentCNY = reviewer.AdjustCNY
});
}
}
}
}
@@ -0,0 +1,104 @@
using AutoMapper;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
namespace IRaCIS.Application.Services
{
[ ApiExplorerSettings(GroupName = "Financial")]
public class RankPriceService : BaseService, IRankPriceService
{
private readonly IRepository<RankPrice> _rankPriceRepository;
private readonly IRepository<ReviewerPayInformation> _reviewerPayInfoRepository;
public RankPriceService(IRepository<RankPrice> rankPriceRepository, IRepository<ReviewerPayInformation> reviewerPayInfoRepository,IMapper mapper)
{
_rankPriceRepository = rankPriceRepository;
_reviewerPayInfoRepository = reviewerPayInfoRepository;
}
[NonDynamicMethod]
public async Task<IResponseOutput> AddOrUpdateRankPrice(RankPriceCommand addOrUpdateModel, Guid userId)
{
if (addOrUpdateModel.Id == Guid.Empty|| addOrUpdateModel.Id ==null)
{
var rankPrice = _mapper.Map<RankPrice>(addOrUpdateModel);
rankPrice = await _rankPriceRepository.AddAsync(rankPrice);
if (await _rankPriceRepository.SaveChangesAsync())
{
return ResponseOutput.Ok(rankPrice.Id.ToString());
}
else
{
return ResponseOutput.NotOk();
}
}
else
{
var success =await _rankPriceRepository.UpdateFromQueryAsync(t => t.Id == addOrUpdateModel.Id, u => new RankPrice()
{
UpdateUserId = userId,
UpdateTime = DateTime.Now,
RefresherTraining=addOrUpdateModel.RefresherTraining,
RankName = addOrUpdateModel.RankName,
Timepoint = addOrUpdateModel.Timepoint,
TimepointIn24H = addOrUpdateModel.TimepointIn24H,
TimepointIn48H = addOrUpdateModel.TimepointIn48H,
Adjudication = addOrUpdateModel.Adjudication,
AdjudicationIn24H = addOrUpdateModel.AdjudicationIn24H,
AdjudicationIn48H = addOrUpdateModel.AdjudicationIn48H,
Global = addOrUpdateModel.Global,
Training = addOrUpdateModel.Training,
Downtime = addOrUpdateModel.Downtime
});
return ResponseOutput.Result(success);
}
}
[HttpDelete("{id:guid}")]
public async Task<IResponseOutput> DeleteRankPrice(Guid id)
{
if (await _reviewerPayInfoRepository.AnyAsync(t => t.RankId == id))
{
return ResponseOutput.NotOk("This title has been used by reviewer payment information");
}
var success = await _rankPriceRepository.DeleteFromQueryAsync(t => t.Id == id);
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取职称单价列表
/// </summary>
[HttpPost]
public async Task<PageOutput<RankPriceDTO>> GetRankPriceList(RankPriceQueryDTO queryParam)
{
var rankPriceQueryable = _rankPriceRepository.ProjectTo<RankPriceDTO>(_mapper.ConfigurationProvider);
return await rankPriceQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, "ShowOrder", queryParam.Asc);
}
public async Task<List<RankDic>> GetRankDic()
{
var rankQueryable = _rankPriceRepository.ProjectTo<RankDic>(_mapper.ConfigurationProvider);
return await rankQueryable.ToListAsync();
}
}
}

Some files were not shown because too many files have changed in this diff Show More