添加项目文件。

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,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();
}
}
}
@@ -0,0 +1,147 @@
using AutoMapper;
using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using System.Linq.Expressions;
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 ReviewerPayInfoService : BaseService, IReviewerPayInfoService
{
private readonly IRepository<ReviewerPayInformation> _doctorPayInfoRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<RankPrice> _rankPriceRepository;
private readonly IRepository<Hospital> _hospitalRepository;
public ReviewerPayInfoService(IRepository<Doctor> doctorRepository, IRepository<ReviewerPayInformation> doctorPayInfoRepository,
IRepository<RankPrice> rankPriceRepository, IRepository<Hospital> hospitalRepository, IMapper mapper)
{
_doctorPayInfoRepository = doctorPayInfoRepository;
_doctorRepository = doctorRepository;
_rankPriceRepository = rankPriceRepository;
_hospitalRepository = hospitalRepository;
}
[NonDynamicMethod]
public async Task<IResponseOutput> AddOrUpdateReviewerPayInfo(ReviewerPayInfoCommand addOrUpdateModel, Guid userId)
{
var success = false;
var doctorPayInfoExistedItem = await _doctorPayInfoRepository.FirstOrDefaultAsync(u => u.DoctorId == addOrUpdateModel.DoctorId);
if (doctorPayInfoExistedItem == null)//insert
{
var doctorPayInfo = _mapper.Map<ReviewerPayInformation>(addOrUpdateModel);
//doctorPayInfo.CreateTime = DateTime.Now;
//doctorPayInfo.CreateUserId = userId;
await _doctorPayInfoRepository.AddAsync(doctorPayInfo);
}
else//update
{
await _doctorPayInfoRepository.UpdateAsync(_mapper.Map(addOrUpdateModel, doctorPayInfoExistedItem));
}
success = await _doctorPayInfoRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取医生支付信息列表
/// </summary>
[HttpPost]
public async Task<PageOutput<DoctorPayInfoQueryListDTO>> GetReviewerPayInfoList(DoctorPaymentInfoQueryDTO queryParam)
{
var doctorQueryable = from doctor in _doctorRepository.AsQueryable()
.WhereIf(queryParam.HospitalId != null, o => o.HospitalId == queryParam.HospitalId)
.WhereIf(!string.IsNullOrEmpty(queryParam.SearchName),
u => u.ChineseName.Contains(queryParam.SearchName)|| (u.LastName+ u.FirstName).Contains(queryParam.SearchName))
join hospitalItem in _hospitalRepository.AsQueryable() on doctor.HospitalId equals hospitalItem.Id into gt
from hospital in gt.DefaultIfEmpty()
join trialPayInfo in _doctorPayInfoRepository.Where()
on doctor.Id equals trialPayInfo.DoctorId into payInfo
from doctorPayInfo in payInfo.DefaultIfEmpty()
join rankPrice in _rankPriceRepository.Where()
on doctorPayInfo.RankId equals rankPrice.Id into rankPriceInfo
from rankPrice in rankPriceInfo.DefaultIfEmpty()
select new DoctorPayInfoQueryListDTO
{
//Id = doctorPayInfo.Id,
DoctorId = doctor.Id,
Code = doctor.ReviewerCode,
LastName = doctor.LastName,
FirstName = doctor.FirstName,
ChineseName = doctor.ChineseName,
Phone = doctor.Phone,
DoctorNameInBank = doctorPayInfo.DoctorNameInBank,
IDCard = doctorPayInfo.IDCard,
BankCardNumber = doctorPayInfo.BankCardNumber,
BankName = doctorPayInfo.BankName,
RankId = doctorPayInfo.RankId,
RankName = rankPrice.RankName,
Additional = doctorPayInfo.Additional,
Hospital = hospital.HospitalName,
CreateTime = doctor.CreateTime
};
return await doctorQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, "Code", queryParam.Asc);
}
/// <summary>
/// 根据医生Id获取支付信息
/// </summary>
/// <param name="doctorId">医生Id</param>
/// <returns></returns>
[HttpGet("{doctorId:guid}")]
public async Task<DoctorPayInfoQueryListDTO> GetReviewerPayInfo(Guid doctorId)
{
var doctorQueryable = from doctor in _doctorRepository.Where(u => u.Id == doctorId)
join trialPayInfo in _doctorPayInfoRepository.Where()
on doctor.Id equals trialPayInfo.DoctorId into payInfo
from doctorPayInfo in payInfo.DefaultIfEmpty()
join rankPrice in _rankPriceRepository.Where()
on doctorPayInfo.RankId equals rankPrice.Id into rankPriceInfo
from rankPrice in rankPriceInfo.DefaultIfEmpty()
select new DoctorPayInfoQueryListDTO
{
//Id = doctorPayInfo.Id,
DoctorId = doctor.Id,
Code = doctor.ReviewerCode,
LastName = doctor.LastName,
FirstName = doctor.FirstName,
ChineseName = doctor.ChineseName,
Phone = doctor.Phone,
DoctorNameInBank = doctorPayInfo.DoctorNameInBank,
IDCard = doctorPayInfo.IDCard,
BankCardNumber = doctorPayInfo.BankCardNumber,
BankName = doctorPayInfo.BankName,
RankId = doctorPayInfo.RankId,
RankName = rankPrice.RankName,
Additional = doctorPayInfo.Additional,
CreateTime = doctor.CreateTime
};
return (await doctorQueryable.FirstOrDefaultAsync()).IfNullThrowException();
}
/// <summary>
/// 根据rankId 获取ReviewerId,用于当Rank的单价信息改变时,触发费用计算
/// </summary>
/// <param name="rankId"></param>
/// <returns></returns>
public async Task<List<Guid>> GetReviewerIdByRankId(Guid rankId)
{
return await _doctorPayInfoRepository.Where(u => u.RankId == rankId).Select(u => u.DoctorId).ToListAsync();
}
}
}
@@ -0,0 +1,189 @@
using AutoMapper;
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 = "Financial")]
public class TrialPaymentPriceService : BaseService, ITrialPaymentPriceService
{
private readonly IRepository<TrialPaymentPrice> _trialExtRepository;
private readonly IRepository<Enroll> _enrollRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<CRO> _croRepository;
private readonly IRepository<Trial> _trialRepository;
public TrialPaymentPriceService(IRepository<Trial> trialRepository, IRepository<TrialPaymentPrice> trialExtRepository,
IRepository<Enroll> enrollRepository,
IRepository<Doctor> doctorRepository,
IRepository<CRO> croCompanyRepository, IMapper mapper)
{
_trialExtRepository = trialExtRepository;
_croRepository = croCompanyRepository;
_enrollRepository = enrollRepository;
_doctorRepository = doctorRepository;
_trialRepository = trialRepository;
}
/// <summary>
/// 添加或更新项目支付价格信息
/// </summary>
[NonDynamicMethod]
public async Task<IResponseOutput> AddOrUpdateTrialPaymentPrice(TrialPaymentPriceCommand addOrUpdateModel)
{
var trialExistedItem = await _trialExtRepository.FirstOrDefaultAsync(u => u.TrialId == addOrUpdateModel.TrialId);
if (trialExistedItem == null)//insert
{
var trialExt = _mapper.Map<TrialPaymentPrice>(addOrUpdateModel);
await _trialExtRepository.AddAsync(trialExt);
}
else//update
{
await _trialExtRepository.UpdateAsync(_mapper.Map(addOrUpdateModel, trialExistedItem));
}
var success = await _trialExtRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
[HttpPost]
public async Task<IResponseOutput> UploadTrialSOW(TrialSOWPathDTO trialSowPath)
{
var trialPaymentPrice = await _trialExtRepository.FirstOrDefaultAsync(u => u.TrialId == trialSowPath.TrialId);
if (trialPaymentPrice == null)//添加
{
await _trialExtRepository.AddAsync(_mapper.Map<TrialPaymentPrice>(trialSowPath));
}
else//更新
{
await _trialExtRepository.UpdateAsync(_mapper.Map(trialSowPath, trialPaymentPrice));
}
var success = await _trialExtRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
[HttpPost]
public async Task<IResponseOutput> DeleteTrialSOW(DeleteSowPathDTO trialSowPath)
{
var success = await _trialExtRepository.UpdateFromQueryAsync(u => u.TrialId == trialSowPath.TrialId, s => new TrialPaymentPrice
{
SowPath = "",
SowName = "",
UpdateTime = DateTime.Now,
UpdateUserId = _userInfo.Id
});
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取项目支付价格信息列表
/// </summary>
[HttpPost]
public async Task<PageOutput<TrialPaymentPriceDTO>> GetTrialPaymentPriceList(TrialPaymentPriceQueryDTO queryParam)
{
#region hwt
//var trialQueryable = from trial in _trialRepository.AsQueryable()
// .WhereIf(queryParam.CroId != null, o => o.CROId == queryParam.CroId)
// .WhereIf(!string.IsNullOrEmpty(queryParam.KeyWord), o => o.TrialCode.Contains(queryParam.KeyWord) || o.Indication.Contains(queryParam.KeyWord))
// join cro in _croRepository.AsQueryable() on trial.CROId equals cro.Id into CRO
// from croInfo in CRO.DefaultIfEmpty()
// join trialExt in _trialExtRepository.Where()
// on trial.Id equals trialExt.TrialId into trialInfo
// from trialExt in trialInfo.DefaultIfEmpty()
// select new TrialPaymentPriceDTO
// {
// //Id = trialExt.Id ,
// IsNewTrial = trialExt.IsNewTrial,
// TrialId = trial.Id,
// TrialCode = trial.TrialCode,
// Cro = croInfo.CROName,
// Indication = trial.Indication,
// Expedited = trial.Expedited,
// TrialAdditional = trialExt.TrialAdditional,
// AdjustmentMultiple = trialExt.AdjustmentMultiple,
// SowName = trialExt.SowName,
// SowPath = trialExt.SowPath,
// CreateTime = trial.CreateTime,
// };
//var namelist = (from enroll in _enrollRepository.AsQueryable()
// join doctor in _doctorRepository.Where() on enroll.DoctorId equals doctor.Id
// select new DtoDoctorList()
// {
// TrialId = enroll.TrialId,
// Name = doctor.ChineseName
// }).ToList().GroupBy(x => new { x.TrialId },
//(key, lst) => new DtoDoctorList
//{
// TrialId = key.TrialId,
// Name = string.Join(',', lst.Select(x => x.Name))
//});
//var returndata = trialQueryable.ToPagedList(queryParam.PageIndex, queryParam.PageSize, "CreateTime", queryParam.Asc);
//returndata.CurrentPageData.ForEach(x => {
// x.DoctorsNames = namelist.Where(y => y.TrialId == x.TrialId).Select(y => y.Name).FirstOrDefault() ?? string.Empty;
//});
//return returndata;
#endregion
#region byzhouhang
//var trialQueryable = _trialExtRepository.Where(t => t.Trial.IsDeleted == false)
// .WhereIf(queryParam.CroId != null, o => o.Trial.CROId == queryParam.CroId)
// .WhereIf(!string.IsNullOrEmpty(queryParam.KeyWord), o => o.Trial.TrialCode.Contains(queryParam.KeyWord) || o.Trial.Indication.Contains(queryParam.KeyWord))
// .Select(trialExt => new TrialPaymentPriceDTO()
// {
// TrialCode = trialExt.Trial.TrialCode,
// Cro = trialExt.Trial.CRO.CROName,
// Indication = trialExt.Trial.Indication,
// Expedited = trialExt.Trial.Expedited,
// TrialId = trialExt.TrialId,
// IsNewTrial = trialExt.IsNewTrial,
// SowName = trialExt.SowName,
// SowPath = trialExt.SowPath,
// TrialAdditional = trialExt.TrialAdditional,
// AdjustmentMultiple = trialExt.AdjustmentMultiple,
// CreateTime = trialExt.CreateTime,
// DoctorsNames = string.Join(',', trialExt.Trial.EnrollList.Select(t => t.Doctor.ChineseName))
// });
//return trialQueryable.ToPagedList(queryParam.PageIndex, queryParam.PageSize, string.IsNullOrEmpty(queryParam.SortField) ? "CreateTime" : queryParam.SortField, queryParam.Asc);
#endregion
#region byzhouhang
var trialQueryable2 = _trialExtRepository.Where(t => t.Trial.IsDeleted == false)
.WhereIf(queryParam.CroId != null, o => o.Trial.CROId == queryParam.CroId)
.WhereIf(!string.IsNullOrEmpty(queryParam.KeyWord), o => o.Trial.TrialCode.Contains(queryParam.KeyWord) || o.Trial.Indication.Contains(queryParam.KeyWord))
.ProjectTo<TrialPaymentPriceDTO>(_mapper.ConfigurationProvider);
return await trialQueryable2.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, string.IsNullOrEmpty(queryParam.SortField) ? "CreateTime" : queryParam.SortField, queryParam.Asc);
#endregion
}
}
}
@@ -0,0 +1,152 @@
using AutoMapper;
using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using System.Linq.Expressions;
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 TrialRevenuesPriceService : BaseService, ITrialRevenuesPriceService
{
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<TrialRevenuesPrice> _trialRevenuesPriceRepository;
private readonly IRepository<CRO> _croRepository;
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IRepository<TrialRevenuesPriceVerification> _trialRevenuesPriceVerificationRepository;
public TrialRevenuesPriceService(IRepository<Trial> trialRepository, IRepository<TrialRevenuesPrice> trialCostRepository, IRepository<CRO> croCompanyRepository, IRepository<Dictionary> dictionaryRepository, IRepository<TrialRevenuesPriceVerification> trialRevenuesPriceVerificationRepository, IMapper mapper)
{
_trialRepository = trialRepository;
_trialRevenuesPriceRepository = trialCostRepository;
_croRepository = croCompanyRepository;
_dictionaryRepository = dictionaryRepository;
_trialRevenuesPriceVerificationRepository = trialRevenuesPriceVerificationRepository;
}
public async Task<IResponseOutput> AddOrUpdateTrialRevenuesPrice(TrialRevenuesPriceDTO model)
{
var count = model.Timepoint +
model.TimepointIn24H +
model.TimepointIn48H +
model.Adjudication +
model.AdjudicationIn24H +
model.AdjudicationIn48H +
model.Downtime +
model.Global +
model.Training;
if (count <= 0)
{
return ResponseOutput.NotOk("Please add meaningful data");
}
var trialExistedItem = await _trialRevenuesPriceRepository.FirstOrDefaultAsync(u => u.TrialId == model.TrialId);
if (trialExistedItem == null)//insert
{
var trialCost = _mapper.Map<TrialRevenuesPrice>(model);
await _trialRevenuesPriceRepository.AddAsync(trialCost);
var success = await _trialRevenuesPriceRepository.SaveChangesAsync();
return ResponseOutput.Result(success, trialCost.Id.ToString());
}
else//update
{
var trialRevenuesPrice = (await _trialRevenuesPriceRepository.AsQueryable().FirstOrDefaultAsync(u => u.TrialId == model.TrialId)).IfNullThrowException();
await _trialRevenuesPriceRepository.UpdateAsync(_mapper.Map(model, trialRevenuesPrice));
// 完善价格的 将对应的列设置为true 变更为有价格了
var aaa = await _trialRevenuesPriceVerificationRepository.UpdateFromQueryAsync(t => t.TrialId == model.TrialId, u => new TrialRevenuesPriceVerification()
{
//有价格 则设置为true 否则 该列不变
Timepoint = model.Timepoint > 0 || u.Timepoint,
TimepointIn24H = model.TimepointIn24H > 0 || u.TimepointIn24H,
TimepointIn48H = model.TimepointIn48H > 0 || u.TimepointIn48H,
Adjudication = model.Adjudication > 0 || u.Adjudication,
AdjudicationIn24H =
model.AdjudicationIn24H > 0 || u.AdjudicationIn24H,
AdjudicationIn48H =
model.AdjudicationIn48H > 0 || u.AdjudicationIn48H,
Global = model.Global > 0 || u.Global,
Downtime = model.Downtime > 0 || u.Downtime,
Training = model.Training > 0 || u.Training,
RefresherTraining = model.RefresherTraining > 0 || u.RefresherTraining,
});
//删除所有有价格的记录 为true 表示有价格或者不需要价格 缺价格的为false
await _trialRevenuesPriceVerificationRepository.DeleteFromQueryAsync(t => t.TrialId == model.TrialId &&
t.Timepoint&&
t.TimepointIn24H&&
t.TimepointIn48H &&
t.Adjudication &&
t.AdjudicationIn24H &&
t.AdjudicationIn48H &&
t.Global &&
t.Training &&t.RefresherTraining);
var success = await _trialRevenuesPriceRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
}
[NonDynamicMethod]
public async Task<bool> DeleteTrialCost(Guid id)
{
return await _trialRevenuesPriceRepository.DeleteFromQueryAsync(u => u.Id == id);
}
/// <summary>
/// 获取项目收入费用信息列表[New]
/// </summary>
[HttpPost]
public async Task<PageOutput<TrialRevenuesPriceDetialDTO>> GetTrialRevenuesPriceList(TrialRevenuesPriceQueryDTO queryParam)
{
var trialQueryable = from trial in _trialRepository.AsQueryable()
.Where(u => u.TrialCode.Contains(queryParam.KeyWord)|| u.Indication.Contains(queryParam.KeyWord))
.WhereIf(queryParam.CroId != null, o => o.CROId == queryParam.CroId)
join cro in _croRepository.AsQueryable() on trial.CROId equals cro.Id into CRO
from croInfo in CRO.DefaultIfEmpty()
join dic in _dictionaryRepository.AsQueryable() on trial.ReviewModeId equals dic.Id into dict
from dic in dict.DefaultIfEmpty()
join trialCost in _trialRevenuesPriceRepository.AsQueryable()
on trial.Id equals trialCost.TrialId into trialInfo
from trialCostItem in trialInfo.DefaultIfEmpty()
select new TrialRevenuesPriceDetialDTO
{
Id = trialCostItem == null ? Guid.Empty : trialCostItem.Id,
TrialId = trial.Id,
TrialCode = trial.TrialCode,
Indication = trial.Indication,
Cro = croInfo == null ? string.Empty : croInfo.CROName,
ReviewMode = dic == null ? string.Empty : dic.Value,
Timepoint = trialCostItem == null ? 0 : trialCostItem.Timepoint,
TimepointIn24H = trialCostItem == null ? 0 : trialCostItem.TimepointIn24H,
TimepointIn48H = trialCostItem == null ? 0 : trialCostItem.TimepointIn48H,
Adjudication = trialCostItem == null ? 0 : trialCostItem.Adjudication,
AdjudicationIn24H = trialCostItem == null ? 0 : trialCostItem.AdjudicationIn24H,
AdjudicationIn48H = trialCostItem == null ? 0 : trialCostItem.AdjudicationIn48H,
Downtime = trialCostItem == null ? 0 : trialCostItem.Downtime,
Global = trialCostItem == null ? 0 : trialCostItem.Global,
Training = trialCostItem == null ? 0 : trialCostItem.Training,
RefresherTraining= trialCostItem == null ? 0 : trialCostItem.RefresherTraining,
Expedited = trial.Expedited
};
return await trialQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, "TrialCode", queryParam.Asc);
}
}
}
@@ -0,0 +1,197 @@
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Domain.Models;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Contracts;
namespace IRaCIS.Core.Application.Services
{
/// <summary>
/// Financial---项目收入价格验证
/// </summary>
[ ApiExplorerSettings(GroupName = "Financial")]
public class TrialRevenuesPriceVerificationService : BaseService, ITrialRevenuesPriceVerificationService
{
private readonly IRepository<TrialRevenuesPriceVerification> _trialRevenuesPriceVerificationRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<Doctor> _doctorRepository;
private readonly IRepository<Payment> _paymentRepository;
public TrialRevenuesPriceVerificationService(IRepository<TrialRevenuesPriceVerification> trialRevenuesPriceVerificationRepository,
IRepository<Trial> trialRepository,IRepository<Doctor> doctorRepository,IRepository<Payment> paymentRepository)
{
_trialRevenuesPriceVerificationRepository = trialRevenuesPriceVerificationRepository;
_trialRepository = trialRepository;
_doctorRepository = doctorRepository;
_paymentRepository = paymentRepository;
}
[HttpPost]
public async Task<AnalysisVerifyResultDTO> GetAnalysisVerifyList(RevenusVerifyQueryDTO param)
{
AnalysisVerifyResultDTO result=new AnalysisVerifyResultDTO();
result.RevenuesVerifyList = await GetRevenuesVerifyList(param);
var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1);
var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1);
eDate = eDate.AddMonths(1).AddSeconds(-1);
Expression<Func<Payment, bool>> paymentLambda = x => x.YearMonthDate >= bDate && x.YearMonthDate <= eDate&&!x.IsLock;
var query = from payment in _paymentRepository.Where(paymentLambda)
join doctor in _doctorRepository.AsQueryable() on payment.DoctorId equals doctor.Id
select new AnalysisNeedLockDTO()
{
YearMonth = payment.YearMonth,
ReviewerCode = doctor.ReviewerCode,
ReviewerName = doctor.LastName + " / " + doctor.FirstName,
ReviewerNameCN = doctor.ChineseName
};
result.MonthVerifyResult = (await query.ToListAsync()).GroupBy(t => t.YearMonth).Select(g => new MonthlyResult
{
YearMonth = g.Key,
ReviewerNameList = g.Select(t => t.ReviewerName).ToList(),
ReviewerNameCNList = g.Select(t => t.ReviewerNameCN).ToList(),
ReviewerCodeList = g.Select(t => t.ReviewerCode).ToList()
}).OrderBy(t=>t.YearMonth).ToList();
return result;
}
[HttpPost]
public async Task<List<RevenusVerifyDTO>> GetRevenuesVerifyList(RevenusVerifyQueryDTO param)
{
var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1);
var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1);
Expression<Func<TrialRevenuesPriceVerification, bool>> trialRevenuesPriceVerificationLambda = x => x.WorkLoadDate >= bDate && x.WorkLoadDate <= eDate;
var query = (from trialVerify in _trialRevenuesPriceVerificationRepository.Where(trialRevenuesPriceVerificationLambda)
join trail in _trialRepository.AsQueryable() on trialVerify.TrialId equals trail.Id
select new RevenusVerifyDTO
{
TrialCode = trail.TrialCode,
Timepoint = trialVerify.Timepoint,
TimepointIn24H = trialVerify.TimepointIn24H,
TimepointIn48H = trialVerify.TimepointIn48H,
Adjudication = trialVerify.Adjudication,
AdjudicationIn24H = trialVerify.AdjudicationIn24H,
AdjudicationIn48H = trialVerify.AdjudicationIn48H,
Global = trialVerify.Global,
Downtime = trialVerify.Downtime,
Training = trialVerify.Training
}).Distinct();
return await query.ToListAsync();
}
//废弃
[Obsolete]
public async Task<List<RevenusVerifyDTO>> GetRevenuesVerifyResultList(RevenusVerifyQueryDTO param)
{
var bDate = new DateTime(param.BeginDate.Year, param.BeginDate.Month, 1);
var eDate = new DateTime(param.EndDate.Year, param.EndDate.Month, 1);
Expression<Func<TrialRevenuesPriceVerification, bool>> trialRevenuesPriceVerificationLambda = x => x.WorkLoadDate >= bDate && x.WorkLoadDate <= eDate;
var query = (from trialVerify in _trialRevenuesPriceVerificationRepository.Where(trialRevenuesPriceVerificationLambda)
join trail in _trialRepository.AsQueryable() on trialVerify.TrialId equals trail.Id
select new RevenusVerifyDTO
{
TrialCode = trail.TrialCode,
Timepoint = trialVerify.Timepoint,
TimepointIn24H = trialVerify.TimepointIn24H,
TimepointIn48H = trialVerify.TimepointIn48H,
Adjudication = trialVerify.Adjudication,
AdjudicationIn24H = trialVerify.AdjudicationIn24H,
AdjudicationIn48H = trialVerify.AdjudicationIn48H,
Global = trialVerify.Global,
Downtime = trialVerify.Downtime,
Training = trialVerify.Training
}).Distinct();
return await query.ToListAsync();
#region old
//query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll()
// join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id
// join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id
// select new RevenusVerifyDTO()
// {
// ReviewerCode = reviewer.Code,
// TrialCode = trail.Code,
// YearMonth = trialVerify.YearMonth
// };
////0是Detail 1是按照项目 2是按照人 3按照月份
//if (param.StatType == 0)
//{
// query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll()
// join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id
// join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id
// select new RevenusVerifyDTO()
// {
// ReviewerCode = reviewer.Code,
// TrialCode = trail.Code,
// YearMonth = trialVerify.YearMonth
// };
//}
//else if (param.StatType == 1)
//{
// query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll()
// join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id
// select new RevenusVerifyDTO()
// {
// ReviewerCode = "",
// TrialCode = trail.Code,
// YearMonth = ""
// }).Distinct();
//}
//else if (param.StatType == 2)
//{
// query = (from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll()
// join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id
// join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id
// select new RevenusVerifyDTO()
// {
// ReviewerCode = reviewer.Code,
// TrialCode = trail.Code,
// YearMonth = ""
// }).Distinct();
//}
//else
//{
// query = from trialVerify in _trialRevenuesPriceVerificationRepository.GetAll()
// join trail in _trialRepository.GetAll() on trialVerify.TrialId equals trail.Id
// join reviewer in _doctorRepository.GetAll() on trialVerify.ReviewerId equals reviewer.Id
// select new RevenusVerifyDTO()
// {
// ReviewerCode = reviewer.Code,
// TrialCode = trail.Code,
// YearMonth = trialVerify.YearMonth
// };
//}
#endregion
}
}
}
@@ -0,0 +1,62 @@
using AutoMapper;
using AutoMapper.QueryableExtensions;
using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Domain.Share;
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 VolumeRewardService : BaseService, IVolumeRewardService
{
private readonly IRepository<VolumeReward> _volumeRewardRepository;
public VolumeRewardService(IRepository<VolumeReward> volumeRewardRepository,IMapper mapper)
{
_volumeRewardRepository = volumeRewardRepository;
}
/// <summary>
/// 批量添加或更新奖励费用单价
/// </summary>
[NonDynamicMethod]
public async Task<IResponseOutput> AddOrUpdateVolumeRewardPriceList(IEnumerable<AwardPriceCommand> addOrUpdateModel)
{
await _volumeRewardRepository.DeleteFromQueryAsync(t => t.Id != Guid.Empty);
var temp = _mapper.Map<List<VolumeReward>>(addOrUpdateModel);
await _volumeRewardRepository.AddRangeAsync(temp);
var success = await _volumeRewardRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取所有奖励单价列表-用于计算时,一次性获取所有
/// </summary>
[NonDynamicMethod]
public async Task<List<AwardPriceCalculateDTO>> GetVolumeRewardPriceList()
{
return await _volumeRewardRepository.ProjectTo<AwardPriceCalculateDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.Min).ToListAsync();
}
/// <summary>
/// 分页获取奖励单价列表
/// </summary>
[HttpPost]
public async Task<PageOutput<AwardPriceDTO>> GetVolumeRewardPriceList(AwardPriceQueryDTO queryParam)
{
var awardPriceQueryable = _volumeRewardRepository.ProjectTo<AwardPriceDTO>(_mapper.ConfigurationProvider);
return await awardPriceQueryable.ToPagedListAsync(queryParam.PageIndex, queryParam.PageSize, "Min");
}
}
}
@@ -0,0 +1,62 @@
using AutoMapper;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Contracts.Pay;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.Application.Service
{
public class FinancialConfig : Profile
{
public FinancialConfig()
{
CreateMap<PaymentAdjustmentCommand, PaymentAdjustment>()
.ForMember(t => t.YearMonthDate, u => u.MapFrom(t => t.YearMonth))
.ForMember(t => t.YearMonth, u => u.MapFrom(t => t.YearMonth.ToString("yyyy-MM")));
CreateMap<TrialPaymentPriceCommand, TrialPaymentPrice>();
CreateMap<ReviewerPayInfoCommand, ReviewerPayInformation>();
CreateMap<RankPriceCommand, RankPrice>();
CreateMap<AwardPriceCommand, VolumeReward>();
CreateMap<PaymentCommand, Payment>();
CreateMap<PaymentDetailCommand, PaymentDetail>();
CreateMap<ExchangeRateCommand, ExchangeRate>();
CreateMap<AwardPriceCommand, VolumeReward>();
CreateMap<TrialRevenuesPriceDTO, TrialRevenuesPrice>();
CreateMap<TrialSOWPathDTO, TrialPaymentPrice>();
CreateMap<RankPrice, RankPriceDTO>();
CreateMap<VolumeReward, AwardPriceDTO>();
CreateMap<RankPrice, RankDic>();
CreateMap<ExchangeRate, ExchangeRateCommand>();
CreateMap<Payment, CalculateNeededDTO>();
CreateMap<VolumeReward, AwardPriceCalculateDTO>();
CreateMap<PaymentDetail, PaymentDetailDTO>();
CreateMap<TrialPaymentPrice, TrialSOWPathDTO>();
CreateMap<TrialPaymentPrice, TrialPaymentPriceDTO>()
.ForMember(t => t.TrialCode, u => u.MapFrom(t => t.Trial.Code))
.ForMember(t => t.ReviewMode, u => u.MapFrom(t => t.Trial.ReviewMode.Value))
.ForMember(t => t.Cro, u => u.MapFrom(t => t.Trial.CRO.CROName))
.ForMember(t => t.Indication, u => u.MapFrom(t => t.Trial.Indication))
.ForMember(t => t.Expedited, u => u.MapFrom(t => t.Trial.Expedited))
.ForMember(t => t.DoctorsNames, u => u.MapFrom(t => string.Join(',', t.Trial.EnrollList.Select(t => t.Doctor.ChineseName))))
;
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public sealed class DicomArchiveResult
{
public int ReceivedFileCount { get; set; }
public ICollection<string> ErrorFiles { get; set; }
public ICollection<DicomStudyBasicDTO> ArchivedDicomStudies { get; set; }
public Guid ReuploadNewStudyId { get; set; } = Guid.Empty;
public DicomArchiveResult()
{
ReceivedFileCount = 0;
ErrorFiles = new List<string>();
ArchivedDicomStudies = new List<DicomStudyBasicDTO>();
}
}
}
@@ -0,0 +1,58 @@
namespace IRaCIS.Core.Application.Contracts
{
public class DicomInstanceDTO
{
public Guid Id { get; set;}
public Guid StudyId { get; set; }
public Guid SeriesId { get; set; }
public string StudyInstanceUid { get; set; } = string.Empty;
public string SeriesInstanceUid { get; set; } = string.Empty;
public string SopInstanceUid { get; set; } = string.Empty;
public int InstanceNumber { get; set; }
public DateTime InstanceTime { get; set; }
public bool CPIStatus { get; set; }
public int ImageRows { get; set; }
public int ImageColumns { get; set; }
public int SliceLocation { get; set; }
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
//public Guid CreateUserId { get; set; }
//public DateTime CreateTime { get; set; }
//public Guid UpdateUserId { get; set; }
//public DateTime UpdateTime { get; set; }
}
public class DicomTrialSiteSubjectInfo
{
public string TrialSiteCode { get; set; } = string.Empty;
public string SiteCode { get; set; } = string.Empty;
public string SiteName { get; set; } = string.Empty;
public string SubjectCode { get; set; } = string.Empty;
public int? SubjectAge { get; set; }
public string SubjectSex { get; set; } = string.Empty;
public string TrialCode { get; set; } = string.Empty;
public string ResearchProgramNo { get; set; } = string.Empty;
public string TrialIndication { get; set; } = string.Empty;
public decimal VisitNum { get; set; }
public string SVUPDES { get; set; } = string.Empty;
public string VisitName { get; set; } = string.Empty;
public string Sponsor { get; set; } = string.Empty;
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
//public string SubjectName => LastName + " / " + FirstName;
//public string FirstName { get; set; } = string.Empty;
//public string LastName { get; set; } = string.Empty;
//public bool IsDoubleReview { get; set; }
}
}
@@ -0,0 +1,34 @@
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class DicomSeriesDTO
{
public Guid Id { get; set; }
public Guid StudyId { get; set; }
public string StudyInstanceUid { get; set; } = String.Empty;
public string SeriesInstanceUid { get; set; } = String.Empty;
public int SeriesNumber { get; set; }
public DateTime SeriesTime { get; set; }
public string Modality { get; set; } = String.Empty;
public string Description { get; set; }=String.Empty;
public int InstanceCount { get; set; }
public string SliceThickness { get; set; } = String.Empty;
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
public Guid CreateUserId { get; set; }
public DateTime CreateTime { get; set; }
public Guid UpdateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public List<Guid> InstanceList { get; set; } = new List<Guid>();
}
public class DicomSeriesWithLabelDTO : DicomSeriesDTO
{
public bool HasLabel { get; set; } = false;
public bool KeySeries { get; set; } = false;
}
}
@@ -0,0 +1,91 @@
namespace IRaCIS.Core.Application.Contracts
{
public class DicomStudyBasicDTO
{
public Guid Id { get; set; }
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
public string StudyCode { get; set; } = string.Empty;
public DateTime StudyTime { get; set; }
}
public class DicomStudyDTO
{
public Guid Id { get; set; }
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
public string StudyCode { get; set; } = string.Empty;
public int Status { get; set; } = 1;
public string StudyInstanceUid { get; set; } = string.Empty;
public DateTime StudyTime { get; set; }
public string Modalities { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public int SeriesCount { get; set; } = 0;
public int InstanceCount { get; set; } = 0;
public bool SoftDelete { get; set; } = false;
public string InstitutionName { get; set; } = string.Empty;
public string PatientId { get; set; } = string.Empty;
public string PatientName { get; set; } = string.Empty;
public string PatientAge { get; set; } = string.Empty;
public string PatientSex { get; set; } = string.Empty;
public Guid UpdateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public Guid CreateUserId { get; set; }
public DateTime CreateTime { get; set; }
}
public class RelationVisitDTO
{
public string VisitName { get; set; } = string.Empty;
public string TpCode { get; set; } = string.Empty;
public Guid StudyId { get; set; }
}
public class RelationStudyDTO
{
public string VisitName { get; set; } = string.Empty;
public string StudyCode { get; set; } = string.Empty;
public Guid StudyId { get; set; }
public int SeriesCount { get; set; }
public string Modalities { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
public class UploadViewInitDto
{
public Guid SubjectVisitId { get; set; }
public Guid SubjectId { get; set; }
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
//public string SubjectName { get; set; }
public string SubjectCode { get; set; } = string.Empty;
public string TrialSiteCode { get; set; } = string.Empty;
public decimal VisitNum { get; set; }
public string VisitName { get; set; } = string.Empty;
}
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class ImageLabelDTO
{
public Guid Id { get; set; } = Guid.Empty;
public string TpCode { get; set; } = string.Empty;
public Guid StudyId { get; set; } = Guid.Empty;
public Guid SeriesId { get; set; } = Guid.Empty;
public Guid InstanceId { get; set; } = Guid.Empty;
public string LabelValue { get; set; } = string.Empty;
}
public class ImageLabelInfo
{
public Guid StudyId { get; set; } = Guid.Empty;
public Guid SeriesId { get; set; } = Guid.Empty;
public Guid InstanceId { get; set; } = Guid.Empty;
public string LabelValue { get; set; } = string.Empty;
}
public class ImageLabelCommand
{
public string TpCode { get; set; } = string.Empty;
public List<ImageLabelInfo> ImageLabelList { get; set; } = new List<ImageLabelInfo>();
}
}
@@ -0,0 +1,23 @@
using System;
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class ImageShareCommand
{
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid? StudyId { get; set; }
public DateTime? ExpireTime { get; set; }
public string Password { get; set; } = string.Empty;
}
public class ResourceInfo
{
public Guid StudyId { get; set; }
public string Token { get; set; } = string.Empty;
}
}
@@ -0,0 +1,30 @@
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class StudyDTFDTO
{
public Guid Id { get; set; }
public Guid StudyId { get; set; }
public string FileName { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public Guid CreateUserId { get; set; }
public string UserName { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public DateTime CreateTime { get; set; }
}
public class StudyDTFAddOrUpdateCommand
{
public Guid? Id { get; set; }
public Guid StudyId { get; set; }
public string FileName { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
}
}
@@ -0,0 +1,46 @@
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class StudyReviewerDTO
{
public Guid Id { get; set; }
public Guid StudyId { get; set; }
public Guid ReviewerId { get; set; }
}
public class StudyDistributeInfo
{
public Guid StudyId { get; set; }
public int Status { get; set; }
//public int ReviewerCount { get; set; }
}
public class StudyReviewerCommand
{
public List<StudyDistributeInfo> StudyList { get; set; } = new List<StudyDistributeInfo>();
//public List<Guid> StudyIdList { get; set; }
public Guid ReviewerId { get; set; }
//public int WorkloadType { get; set; }
public Guid TrialId { get; set; }
//public bool IsDoubleReview { get; set; }
}
public class StudyReviewerEditCommand
{
public Guid TrialId { get; set; }
public Guid StudyId { get; set; }
public bool IsDoubleReview { get; set; }
public Guid? ReviewerId1 { get; set; }
public Guid? ReviewerId2 { get; set; }
public Guid? ReviewerIdForAD { get; set; }
}
public class ReviewerDistributionDTO
{
public Guid ReviewerId { get; set; }
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string ReviewerCode { get; set; } = string.Empty;
}
}
@@ -0,0 +1,27 @@
using System;
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{
public class StudyStatusDetailDTO
{
public Guid Id { get; set; }
public Guid StudyId { get; set; }
public int Status { get; set; }
public string OptUserName { get; set; }=string.Empty;
public DateTime OptTime { get; set; }
public string Note { get; set; } = string.Empty;
}
public class StudyStatusDetailCommand
{
public Guid StudyId { get; set; }
public int Status { get; set; }
public DateTime? DeadlineTime { get; set; }
public string Note { get; set; } = string.Empty;
//QA不通过的时候传递参数
public string QAComment { get; set; } = string.Empty;
}
}
@@ -0,0 +1,61 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2022-03-03 15:28:20
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel
{
/// <summary> SystemAnonymizationView 列表视图模型 </summary>
public class SystemAnonymizationView: SystemAnonymizationAddOrEdit
{
public Guid CreateUserId { get; set; }
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
public DateTime CreateTime { get; set; }
}
///<summary>SystemAnonymizationQuery 列表查询参数模型</summary>
public class SystemAnonymizationQuery:PageInput
{
public string Group { get; set; } = string.Empty;
public bool? IsAdd { get; set; }
public string Element { get; set; } = string.Empty;
public string TagDescription { get; set; } = string.Empty;
public string ValueRepresentation { get; set; } = string.Empty;
}
///<summary> SystemAnonymizationAddOrEdit 列表查询参数模型</summary>
public class SystemAnonymizationAddOrEdit
{
public Guid? Id { get; set; }
public string Group { get; set; } = String.Empty;
public string Element { get; set; } = String.Empty;
public string TagDescription { get; set; } = String.Empty;
public string TagDescriptionCN { get; set; } = String.Empty;
public string ReplaceValue { get; set; } = String.Empty;
public string ValueRepresentation { get; set; } = String.Empty;
public bool IsAdd { get; set; }
public bool IsEnable { get; set; }
public bool IsFixed { get; set; }
}
}
@@ -0,0 +1,109 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Contracts
{
public class UnionStudyBaseModel
{
public Guid TrialId { get; set; }
public Guid SiteId { get; set; }
public Guid SubjectId { get; set; }
public Guid SubjectVisitId { get; set; }
public string SubjectCode { get; set; }
public string VisitName { get; set; } = string.Empty;
public decimal VisitNum { get; set; }
public string TrialSiteCode { get; set; } = string.Empty;
public string TrialSiteAliasName { get; set; } = string.Empty;
public string Uploader { get; set; } = string.Empty;
public DateTime UploadTime { get; set; }
public string StudyCode => IsDicom ? DicomStudyCode : "NST" + NoneDicomCode.ToString("D5");
[JsonIgnore]
public string DicomStudyCode { get; set; } = string.Empty;
[JsonIgnore]
public int NoneDicomCode { get; set; }
public bool IsDicom { get; set; }
}
public class UnionStudyMonitorModel : UnionStudyBaseModel
{
public Guid StudyId { get; set; }
public DateTime UploadStartTime { get; set; }
public DateTime UploadFinishedTime { get; set; }
public decimal FileSize { get; set; }
public string IP { get; set; }
public bool IsDicomReUpload { get; set; }
public bool IsDicom { get; set; }
public int FileCount { get; set; }
}
public class UnionStudyViewModel:UnionStudyBaseModel
{
public Guid Id { get; set; }
public int? Count { get; set; }
public string Modalities { get; set; } = string.Empty;
public string Bodypart { get; set; } = string.Empty;
public DateTime? StudyTime { get; set; }
}
public class StudyQuery:PageInput
{
[NotDefault]
public Guid TrialId { get; set; }
public Guid? SubjectId { get; set; }
public Guid? SiteId { get; set; }
public Guid? SubjectVisitId { get; set; }
public string SubjectInfo { get; set; } = String.Empty;
public string VisitPlanInfo { get; set; } = String.Empty;
}
}
@@ -0,0 +1,447 @@
using Dicom;
using Dicom.Imaging.Codec;
using EasyCaching.Core;
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Share;
using Microsoft.Extensions.Hosting;
using System.Text;
using IRaCIS.Core.Application.Contracts;
namespace IRaCIS.Core.Application.Services
{
public class DicomArchiveService : IDicomArchiveService
{
private readonly IRepository<DicomStudy> _studyRepository;
private readonly IRepository<DicomSeries> _seriesRepository;
private readonly IRepository<DicomInstance> _instanceRepository;
private readonly IEasyCachingProvider _provider;
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
private static object lockCodeGenerate = new object();
public DicomArchiveService(IRepository<DicomStudy> studyRepository,
IRepository<DicomSeries> seriesRepository,
IRepository<DicomInstance> instanceRepository,
IHostEnvironment hostEnvironment,
DicomFileStoreHelper dicomFileStoreHelper,
IEasyCachingProvider provider)
{
_dicomFileStoreHelper = dicomFileStoreHelper;
_studyRepository = studyRepository;
_seriesRepository = seriesRepository;
_instanceRepository = instanceRepository;
_provider = provider;
}
public async Task<bool> DicomDBDataSaveChange()
{
var success = await _studyRepository.SaveChangesAsync();
return success;
}
public async Task<Guid> ArchiveDicomStreamAsync(Stream dicomStream,
DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList)
{
DicomFile dicomFile = await DicomFile.OpenAsync(dicomStream, Encoding.Default);
DicomDataset dataset = dicomFile.Dataset;
//如果数据库存在该instance 记录 那么就不处理
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
if (instanceUidList.Any(t => t == sopInstanceUid))
{
return IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString());
}
var anonymize_AddFixedFiledList = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_AddFixedFiled).Value;
var anonymize_AddIRCInfoFiled = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_AddIRCInfoFiled).Value;
var anonymize_FixedField = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_FixedField).Value;
var anonymize_IRCInfoField = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_IRCInfoField).Value;
foreach (var item in anonymize_AddFixedFiledList.Union(anonymize_FixedField))
{
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
}
foreach (var item in anonymize_AddIRCInfoFiled.Union(anonymize_IRCInfoField))
{
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
if (dicomTag == DicomTag.ClinicalTrialProtocolID)
{
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialCode);
}
if (dicomTag == DicomTag.ClinicalTrialSiteID)
{
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialSiteCode);
}
if (dicomTag == DicomTag.ClinicalTrialSubjectID)
{
dataset.AddOrUpdate(dicomTag, addtionalInfo.SubjectCode);
}
if (dicomTag == DicomTag.ClinicalTrialTimePointID)
{
dataset.AddOrUpdate(dicomTag, addtionalInfo.VisitNum.ToString());
}
if (dicomTag == DicomTag.PatientID)
{
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialCode+"_"+ addtionalInfo.SubjectCode);
}
}
#region
////按照配置文件 匿名化
//foreach (var anonymizeItem in SystemConfig.AnonymizeTagList)
//{
// if (anonymizeItem.Enable)
// {
// ushort group = Convert.ToUInt16(anonymizeItem.Group, 16);
// ushort element = Convert.ToUInt16(anonymizeItem.Element, 16);
// dataset.AddOrUpdate(new DicomTag(group, element), anonymizeItem.ReplaceValue);
// }
//}
//if (AppSettings.AddClinicalInfo) //是否需要写入临床信息
//{
// //Dicom 文件中写入临床信息
// dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, addtionalInfo.TrialCode); //Trial
// dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolName, addtionalInfo.TrialIndication); //indication
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSponsorName, addtionalInfo.Sponsor);//sponsor
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, addtionalInfo.SiteCode); //SiteId
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteName, addtionalInfo.SiteName);//SiteName
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, addtionalInfo.SubjectCode + " " + addtionalInfo.SubjectSex);//SubjectId
// dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, addtionalInfo.VisitNum.ToString()); // TimePoint
// dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointDescription, addtionalInfo.VisitName + " " + addtionalInfo.SVUPDES);
//}
//DicomStudy dicomStudy = null;
//DicomSeries dicomSeries = null;
//DicomInstance dicomInstance = null;
//lock (lockTest)
//{
// dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd);
// dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
// dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries);
// if (isStudyNeedAdd) _studyRepository.Add(dicomStudy);
// if (isSeriesNeedAdd) _seriesRepository.Add(dicomSeries);
// _instanceRepository.Add(dicomInstance);
//}
#endregion
DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd);
DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries);
if (isStudyNeedAdd) await _studyRepository.AddAsync(dicomStudy);
if (isSeriesNeedAdd) await _seriesRepository.AddAsync(dicomSeries);
await _instanceRepository.AddAsync(dicomInstance);
string filePath = _dicomFileStoreHelper.CreateInstanceFilePath(dicomStudy, dicomSeries.Id, dicomInstance.Id);
var samplesPerPixel = dataset.GetSingleValueOrDefault(DicomTag.SamplesPerPixel, string.Empty);
var photometricInterpretation = dataset.GetSingleValueOrDefault(DicomTag.PhotometricInterpretation, string.Empty);
if (samplesPerPixel == "1" && (photometricInterpretation.ToUpper() == "MONOCHROME2" || photometricInterpretation.ToUpper() == "MONOCHROME1"))//MONOCHROME2
{
if (dataset.InternalTransferSyntax.IsEncapsulated)
{
await dicomFile.SaveAsync(filePath);
}
else
{
await dicomFile.Clone(DicomTransferSyntax.JPEGLSLossless).SaveAsync(filePath);
}
}
else
{
if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath);
else await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(filePath); //RLELossless
}
return dicomInstance.StudyId;
}
private DicomStudy CreateDicomStudy(DicomDataset dataset, DicomTrialSiteSubjectInfo addtionalInfo, out bool isStudyNeedAdd)
{
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString());
// 每个线程都查询数据库最大的,和缓存中最大的,取最大值为基数生成Code
//var id = Thread.CurrentThread.ManagedThreadId.ToString("00");
//虽然每个文件都会进来,但是只要查询过,就会跟踪,不会再次查询数据库 这里线程并发会有问题,得加锁,不然生成Code 出错
DicomStudy dicomStudy = _studyRepository.ImageFind(studyId, typeof(DicomStudy));
if (dicomStudy != null)
{
isStudyNeedAdd = false;
return dicomStudy;
}
//_logger.LogWarning($"Thread {id} ,studyUid{studyInstanceUid} 生成StudyId{studyId}");
isStudyNeedAdd = true;
dicomStudy = new DicomStudy
{
Id = studyId,
StudyInstanceUid = studyInstanceUid,
StudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, DateTime.Now).TimeOfDay),//dataset.GetDateTime(DicomTag.StudyDate, DicomTag.StudyTime),
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
//需要特殊处理
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
SiteId = addtionalInfo.SiteId,
TrialId = addtionalInfo.TrialId,
SubjectId = addtionalInfo.SubjectId,
SubjectVisitId = addtionalInfo.SubjectVisitId,
//IsDoubleReview = addtionalInfo.IsDoubleReview,
SeriesCount = 0,
InstanceCount = 0
};
if (dicomStudy.PatientBirthDate.Length == 8)
{
dicomStudy.PatientBirthDate = $"{dicomStudy.PatientBirthDate[0]}{dicomStudy.PatientBirthDate[1]}{dicomStudy.PatientBirthDate[2]}{dicomStudy.PatientBirthDate[3]}-{dicomStudy.PatientBirthDate[4]}{dicomStudy.PatientBirthDate[5]}-{dicomStudy.PatientBirthDate[6]}{dicomStudy.PatientBirthDate[7]}";
}
lock (lockCodeGenerate)
{
//查询数据库获取最大的Code 没有记录则为0
var dbStudyCodeIntMax = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.Code).DefaultIfEmpty().Max();
//获取缓存中的值 并发的时候,需要记录,已被占用的值 这样其他线程在此占用的最大的值上递增
var cacheMaxCodeInt = _provider.Get<int>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}").Value;
int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1;
dicomStudy.Code = currentNextCodeInt;
dicomStudy.StudyCode = "ST" + currentNextCodeInt.ToString("D5");
_provider.Set<int>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}", dicomStudy.Code, TimeSpan.FromMinutes(30));
}
#region Setting Code old
//var studyCode = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.StudyCode).OrderByDescending(c => c).FirstOrDefault();
//var cacheMaxCode = _provider.Get<string>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}").Value;
//if (studyCode == null && string.IsNullOrEmpty(cacheMaxCode))
//{
// dicomStudy.StudyCode = "ST" + 1.ToString().PadLeft(5, '0');
// _logger.LogWarning($"Thread {id} DB{studyCode} 生成{ dicomStudy.StudyCode}");
//}
//else
//{
// int dbNum = 0;
// int cacheNum = 0;
// if (studyCode != null)
// {
// int.TryParse(studyCode.Substring(studyCode.Length - 5, 5), out dbNum);
// }
// if (!string.IsNullOrEmpty(cacheMaxCode))
// {
// int.TryParse(cacheMaxCode.Substring(cacheMaxCode.Length - 5, 5), out cacheNum);
// }
// dbNum = cacheNum > dbNum ? cacheNum : dbNum;
// dicomStudy.StudyCode = "ST" + (++dbNum).ToString().PadLeft(5, '0');
// _logger.LogWarning($" Thread {id} DB{studyCode} cache:{cacheNum} 生成{ dicomStudy.StudyCode}");
//}
//_provider.Set<string>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}", dicomStudy.StudyCode, TimeSpan.FromMinutes(30));
#endregion
return dicomStudy;
}
private DicomSeries CreateDicomSeries(DicomDataset dataset, DicomStudy dicomStudy, out bool isSeriesNeedAdd)
{
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
Guid seriesId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, seriesInstanceUid, dicomStudy.TrialId.ToString());
//有几个序列会查询几次
DicomSeries dicomSeries = _seriesRepository.ImageFind(seriesId, typeof(DicomSeries));
if (dicomSeries != null)
{
isSeriesNeedAdd = false;
return dicomSeries;
}
else
{
//var id = Thread.CurrentThread.ManagedThreadId.ToString("00");
isSeriesNeedAdd = true;
dicomSeries = new DicomSeries
{
Id = seriesId,
StudyId = dicomStudy.Id,
StudyInstanceUid = dicomStudy.StudyInstanceUid,
SeriesInstanceUid = seriesInstanceUid,
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay), // dataset.GetDateTime(DicomTag.SeriesDate, DicomTag.SeriesTime),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
SiteId = dicomStudy.SiteId,
TrialId = dicomStudy.TrialId,
SubjectId = dicomStudy.SubjectId,
SubjectVisitId = dicomStudy.SubjectVisitId,
InstanceCount = 0
};
++dicomStudy.SeriesCount;
//_logger.LogWarning($"线程:{id},sericeId:{seriesId},count:{SeriesDic.Keys.Count}");
return dicomSeries;
}
}
private DicomInstance CreateDicomInstance(DicomDataset dataset, DicomStudy dicomStudy, DicomSeries dicomSeries)
{
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
Guid instanceId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, dicomSeries.SeriesInstanceUid, sopInstanceUid, dicomStudy.TrialId.ToString());
DicomInstance dicomInstance = new DicomInstance
{
Id = instanceId,
StudyId = dicomStudy.Id,
SeriesId = dicomSeries.Id,
SiteId = dicomStudy.SiteId,
TrialId = dicomStudy.TrialId,
SubjectId = dicomStudy.SubjectId,
SubjectVisitId = dicomStudy.SubjectVisitId,
StudyInstanceUid = dicomStudy.StudyInstanceUid,
SeriesInstanceUid = dicomSeries.SeriesInstanceUid,
SopInstanceUid = sopInstanceUid,
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, DateTime.Now).TimeOfDay),
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
CPIStatus = false,
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
};
++dicomStudy.InstanceCount;
++dicomSeries.InstanceCount;
return dicomInstance;
}
}
}
@@ -0,0 +1,81 @@
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.Application
{
public class DicomFileStoreHelper
{
private readonly IWebHostEnvironment _hostEnvironment;
private static string _fileStorePath = string.Empty;
private readonly ILogger<DicomFileStoreHelper> _logger;
public DicomFileStoreHelper(IWebHostEnvironment hostEnvironment, ILogger<DicomFileStoreHelper> logger)
{
_logger = logger;
_hostEnvironment = hostEnvironment;
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
//上传根路径
_fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
}
public string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, string instanceId)
{
return Path.Combine(_fileStorePath, dicomStudy.TrialId.ToString(),
dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.SubjectVisitId.ToString(), StaticData.DicomFolder, dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm");
}
public string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
{
//加入访视层级 和Data
var path = Path.Combine(_fileStorePath, dicomStudy.TrialId.ToString(),
dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.SubjectVisitId.ToString(), StaticData.DicomFolder, dicomStudy.Id.ToString());
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return Path.Combine(path, instanceId.ToString() + ".dcm");
}
public string GetSubjectVisitPath(Guid trialId,Guid siteId,Guid subjectId, Guid subjectVisitId)
{
return Path.Combine(_fileStorePath, trialId.ToString(),
siteId.ToString(), subjectId.ToString(), subjectVisitId.ToString(), StaticData.DicomFolder);
}
//public static string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
//{
// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString());
// if (!Directory.Exists(path)) Directory.CreateDirectory(path);
// return Path.Combine(path, instanceId.ToString() + ".dcm");
//}
//public static string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
//{
// return Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm");
//}
//public static void RemoveStudyDirectory(DicomStudy dicomStudy)
//{
// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString());
// if (Directory.Exists(path)) Directory.Delete(path, true);
//}
}
}
@@ -0,0 +1,37 @@
using FellowOakDicom.Imaging;
using SixLabors.ImageSharp.Formats.Jpeg;
namespace IRaCIS.Core.Application.Dicom
{
public static class DicomRenderingHelper
{
public static Stream RenderPreviewJpeg(string filePath)
{
string jpegPath = filePath + ".preview.jpg";
if (!File.Exists(jpegPath))
{
using (Stream stream = new FileStream(jpegPath, FileMode.Create))
{
DicomImage image = new DicomImage(filePath);
//image.ShowOverlays = false;
//image.Scale = Math.Min(Math.Min(128.0 / image.Width, 128.0 / image.Height), 1.0);
//image.RenderImage().AsClonedBitmap().Save(stream, ImageFormat.Jpeg);
var sharpimage = image.RenderImage().AsSharpImage();
sharpimage.Save(stream, new JpegEncoder());
}
}
return new FileStream(jpegPath, FileMode.Open);
}
public static void RemovePreviewJpeg(string filePath)
{
string jpegPath = filePath + ".preview.jpg";
if (File.Exists(jpegPath)) File.Delete(jpegPath);
}
}
}
@@ -0,0 +1,24 @@

using System.Security.Cryptography;
using System.Text;
namespace IRaCIS.Core.Application.Services
{
static class IdentifierHelper
{
//private static MD5 md5 = new MD5CryptoServiceProvider
//
private static MD5 md5 = MD5.Create();
private static object lockObj =new object();
public static Guid CreateGuid(params string[] parts)
{
lock (lockObj)
{
return new Guid(md5.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(parts))));
}
}
}
}
@@ -0,0 +1,133 @@
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using IRaCIS.Core.Application.Auth;
namespace IRaCIS.Core.Application.Services
{
[AllowAnonymous, ApiExplorerSettings(GroupName = "Image")]
public class ImageShareService : BaseService, IImageShareService
{
private readonly IRepository<ImageShare> _imageShareRepository;
private readonly IRepository<DicomStudy> _studyRepository;
private readonly IConfiguration _configuration;
private readonly ITokenService _tokenService;
public ImageShareService(IRepository<ImageShare> imageShareRepository, IRepository<DicomStudy> studyRepository, IConfiguration configuration, ITokenService tokenService)
{
_imageShareRepository = imageShareRepository;
_studyRepository = studyRepository;
_configuration = configuration;
_tokenService = tokenService;
}
[HttpPost]
public async Task<IResponseOutput> CreateImageShare(ImageShareCommand imageShareCommand)
{
if (imageShareCommand.StudyId == null)
{
#region 访线
//var subjectVisit1 = _subjectVisitRepository.FirstOrDefault(t =>
// t.TrialId == imageShareCommand.TrialId && t.SubjectId == imageShareCommand.SubjectId &&
// t.VisitNum == 1);
//if (subjectVisit1 == null)
//{
// return ResponseOutput.NotOk("当前无影像数据,无法分享!");
//}
//imageShareCommand.StudyId =
// _studyRepository.GetAll().First(t => t.SubjectVisitId == subjectVisit1.Id&&t.Status != (int)StudyStatus.Abandon).Id;
#endregion
var studyIds = await _studyRepository.AsQueryable()
.Where(t => t.TrialId == imageShareCommand.TrialId && t.SubjectId == imageShareCommand.SubjectId &&
t.SiteId == imageShareCommand.SiteId)
.Select(u => u.Id).ToListAsync();
if (!studyIds.Any())
{
return ResponseOutput.NotOk("There is no image in the current study and cannot be shared! ");
}
imageShareCommand.StudyId = studyIds.First();
}
//验证码 4位
int verificationPassWord = new Random().Next(1000, 10000);
imageShareCommand.Password = verificationPassWord.ToString();
//配置文件读取过期时间
var days = int.Parse(_configuration.GetSection("imageShare:ExpireDays").Value);
imageShareCommand.ExpireTime = DateTime.Now.AddDays(days);
var imageShare = _mapper.Map<ImageShare>(imageShareCommand);
await _imageShareRepository.AddAsync(imageShare);
var success = await _imageShareRepository.SaveChangesAsync();
return ResponseOutput.Result(success, new { ResourceId = imageShare.Id, Password = verificationPassWord.ToString() });
}
[HttpGet, Route("{resourceId:guid}/{password}")]
public async Task<IResponseOutput> VerifyShareImage(Guid resourceId, string password)
{
var pWord = password.Trim();
var imageShare = await _imageShareRepository.FirstOrDefaultAsync(t => t.Id == resourceId);
if (imageShare == null)
{
return ResponseOutput.NotOk("The resource does not exist! ");
}
if (pWord != imageShare.Password.Trim())
{
return ResponseOutput.NotOk("Shared password error!");
}
if (DateTime.Now > imageShare.ExpireTime)
{
return ResponseOutput.NotOk("Resource sharing has expired!");
}
var resource = new ResourceInfo()
{
StudyId = imageShare.StudyId,
Token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
{
Id = Guid.Empty,
IsReviewer = false,
IsAdmin = false,
RealName = "Share001",
UserName = "Share001",
Sex = 0,
//UserType = "ShareType",
UserTypeEnum = UserTypeEnum.ShareImage,
Code = "ShareCode001",
}))
};
return ResponseOutput.Ok(resource);
}
}
}
@@ -0,0 +1,109 @@
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Dicom;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.Application.Services
{
[ApiExplorerSettings(GroupName = "Image")]
[AllowAnonymous]
public class InstanceService : BaseService, IInstanceService
{
private readonly IRepository<DicomInstance> _instanceRepository;
private readonly IRepository<DicomStudy> _studyRepository;
private readonly IRepository<KeyInstance> _keyInstanceRepository;
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
public InstanceService(IRepository<DicomInstance> instanceRepository, IRepository<DicomStudy> studyRepository,
IRepository<KeyInstance> keyInstanceRepository, DicomFileStoreHelper dicomFileStoreHelper)
{
_dicomFileStoreHelper = dicomFileStoreHelper;
_instanceRepository = instanceRepository;
_studyRepository = studyRepository;
_keyInstanceRepository = keyInstanceRepository;
}
/// <summary> 指定资源Id,获取Dicom序列所属的实例信息列表 </summary>
/// <param name="seriesId"> Dicom序列的Id </param>
[HttpGet("{seriesId:guid}")]
public async Task<IEnumerable<DicomInstanceDTO>> List(Guid seriesId)
{
return await _instanceRepository.Where(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber).
ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.ProjectTo<DicomInstanceDTO>(_mapper.ConfigurationProvider).ToListAsync();
}
/// <summary> 指定资源Id,获取Dicom序列所属的实例Id列表 </summary>
/// <param name="seriesId"> Dicom序列的Id </param>
/// <param name="tpCode"></param>
/// <param name="key"></param>
[HttpGet, Route("{seriesId:guid}/{tpCode?}/{key?}")]
public IEnumerable<Guid> List(Guid seriesId, string tpCode, bool? key)
{
if (key != null && key.HasValue && key.Value)
{
return _keyInstanceRepository.Where(s => s.TpCode == tpCode).Select(t => t.InstanceId).Distinct();
}
else
return _instanceRepository.Where(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber).Select(t => t.Id);
}
[AllowAnonymous]
[HttpGet, Route("{instanceId:guid}")]
public async Task<FileContentResult> Preview(Guid instanceId)
{
var path = string.Empty;
DicomInstance dicomInstance = await _instanceRepository.FirstOrDefaultAsync(s => s.Id == instanceId).IfNullThrowException();
DicomStudy dicomStudy = await _studyRepository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId).IfNullThrowException();
path = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString());
using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path))
{
var bytes = new byte[sw.Length];
sw.Read(bytes, 0, bytes.Length);
sw.Close();
return new FileContentResult(bytes, "image/jpeg");
}
}
[AllowAnonymous]
[HttpGet, Route("{instanceId:guid}")]
public async Task<FileContentResult> Content(Guid instanceId)
{
var filePath = string.Empty;
DicomInstance dicomInstance = await _instanceRepository.FirstOrDefaultAsync(s => s.Id == instanceId).IfNullThrowException();
DicomStudy dicomStudy = await _studyRepository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId).IfNullThrowException();
if (dicomInstance.Anonymize) //被匿名化
{
filePath = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id + ".Anonymize");
}
else filePath = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString());
using (var sw = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bytes = new byte[sw.Length];
sw.Read(bytes, 0, bytes.Length);
sw.Close();
return new FileContentResult(bytes, "application/octet-stream");
}
}
}
}
@@ -0,0 +1,24 @@
namespace IRaCIS.Core.Application.Contracts.Dicom
{
public interface IDicomArchiveService
{
Task<Guid> ArchiveDicomStreamAsync(Stream dicomStream, DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList);
//ICollection<DicomStudyDTO> GetArchivedStudyList(List<Guid> archivedStudyIds);
Task<bool> DicomDBDataSaveChange();
//[EasyCachingAble(Expiration = 6000)]
//IEnumerable<DicomSeriesDTO> GetSeriesList(Guid studyId);
//IEnumerable<DicomSeriesWithLabelDTO> GetSeriesWithLabelList(Guid studyId,string tpCode);
////[EasyCachingAble(Expiration = 6000)]
//string GetSeriesPreview(Guid seriesId);
}
}

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