407 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			407 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
using IRaCIS.Application.Interfaces;
 | 
						||
using IRaCIS.Core.Application.Contracts;
 | 
						||
using Microsoft.AspNetCore.Mvc;
 | 
						||
using IRaCIS.Core.Infra.EFCore;
 | 
						||
using Microsoft.AspNetCore.Hosting;
 | 
						||
using Microsoft.AspNetCore.Http;
 | 
						||
using IRaCIS.Core.Domain.Share;
 | 
						||
using EasyCaching.Core;
 | 
						||
using IRaCIS.Core.Application.Filter;
 | 
						||
using IRaCIS.Core.Infrastructure;
 | 
						||
 | 
						||
namespace IRaCIS.Core.Application
 | 
						||
{
 | 
						||
    [ApiExplorerSettings(GroupName = "Trial")]
 | 
						||
    public class TrialConfigService : BaseService, ITrialConfigService
 | 
						||
    {
 | 
						||
        private readonly IRepository<Trial> _trialRepository;
 | 
						||
        private readonly IEasyCachingProvider _provider;
 | 
						||
 | 
						||
        public TrialConfigService(IRepository<Trial> trialRepository,
 | 
						||
            IEasyCachingProvider provider
 | 
						||
            )
 | 
						||
        {
 | 
						||
            _trialRepository = trialRepository;
 | 
						||
            this._provider = provider;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取签名文本
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="signCode"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpGet("{signCode}")]
 | 
						||
        public async Task<IResponseOutput> GetSignText(string signCode)
 | 
						||
        {
 | 
						||
            var signRawText = await _repository.Where<SystemBasicData>(t => t.Code == signCode).Select(t => new { t.Code, t.Value, t.Id, ParentValue = t.Parent.Value, ParentValueCN = t.Parent.ValueCN }).FirstOrDefaultAsync();
 | 
						||
 | 
						||
            if (signRawText == null)
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk("未在系统中找到该签名场景的数据");
 | 
						||
            }
 | 
						||
 | 
						||
            return ResponseOutput.Ok(new
 | 
						||
            {
 | 
						||
                SignCodeId = signRawText.Id,
 | 
						||
                SignCode = signRawText.Code,
 | 
						||
                SignText = signRawText.ParentValue.Replace("xxx", signRawText.Value),
 | 
						||
                SignTextCN = signRawText.ParentValueCN.Replace("xxx", signRawText.Value)
 | 
						||
            });
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 签名认证 +
 | 
						||
        /// </summary>  
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPost]
 | 
						||
        public async Task<IResponseOutput> VerifySignature(SignDTO signDTO)
 | 
						||
        {
 | 
						||
 | 
						||
            var user = await _repository.FirstOrDefaultAsync<User>(u => u.UserName == signDTO.UserName && u.Password == signDTO.PassWord);
 | 
						||
            if (user == null)
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk("password error");
 | 
						||
            }
 | 
						||
            else if (user.Status == UserStateEnum.Disable)
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk("The user has been disabled!");
 | 
						||
            }
 | 
						||
 | 
						||
            //if (signDTO.IsAddSignData)
 | 
						||
            //{
 | 
						||
            // 记录签名信息
 | 
						||
            var add = await _repository.AddAsync(_mapper.Map<TrialSign>(signDTO));
 | 
						||
 | 
						||
            await _repository.SaveChangesAsync();
 | 
						||
 | 
						||
            return ResponseOutput.Ok(add.Id);
 | 
						||
            //}
 | 
						||
 | 
						||
            //return ResponseOutput.Ok();
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 业务接口操作成功后, 让签署数据生效
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="signId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut("{signId:guid}")]
 | 
						||
        [Obsolete]
 | 
						||
        public async Task<IResponseOutput> MakeSignEffective(Guid signId)
 | 
						||
        {
 | 
						||
            var success = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
 | 
						||
 | 
						||
            return ResponseOutput.Result(success);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 签名确认   包括项目的三组配置 +  QC问题确认     后修改状态  (适用于不会回退的,项目废除、状态修改, 存在回退 不在这里弄,提供单独接口修改状态)
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<IResponseOutput> TrialConfigSignatureConfirm(SignConfirmDTO signConfirmDTO)
 | 
						||
        {
 | 
						||
 | 
						||
            if (!await _trialRepository.AnyAsync(t => t.Id == signConfirmDTO.TrialId && (t.TrialStatusStr == StaticData.TrialInitializing|| t.TrialStatusStr == StaticData.TrialOngoing)))
 | 
						||
            {
 | 
						||
                throw new BusinessValidationFailedException("项目不在Initializing/Ongoing,不允许确认配置");
 | 
						||
            }
 | 
						||
 | 
						||
            if (signConfirmDTO.SignCode == ((int)SignEnum.TrialLogicConfim).ToString())
 | 
						||
            {
 | 
						||
                await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialBasicLogicConfirmed = true });
 | 
						||
            }
 | 
						||
            else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialProcessConfim).ToString())
 | 
						||
            {
 | 
						||
                await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialProcessConfirmed = true });
 | 
						||
            }
 | 
						||
            else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialUrgentConfim).ToString())
 | 
						||
            {
 | 
						||
                await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialUrgentConfirmed = true });
 | 
						||
            }
 | 
						||
 | 
						||
            else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
 | 
						||
            {
 | 
						||
 | 
						||
                var trialConfig = (await _trialRepository
 | 
						||
                    .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
 | 
						||
                    .FirstOrDefaultAsync(t => t.TrialId == signConfirmDTO.TrialId))
 | 
						||
                    .IfNullThrowException();
 | 
						||
 | 
						||
              
 | 
						||
 | 
						||
 | 
						||
                var showOrderList = await _repository.Where<TrialQCQuestion>(t => t.TrialId == signConfirmDTO.TrialId).Select(t => 
 | 
						||
                new { t.ShowOrder , ParentShowOrder=(int?) t.ParentQCQuestion.ShowOrder} ).ToListAsync();
 | 
						||
 | 
						||
                if (trialConfig.QCProcessEnum ==
 | 
						||
                    TrialQCProcess.DoubleAudit || trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
 | 
						||
                {
 | 
						||
                    if (showOrderList.Count == 0)
 | 
						||
                    {
 | 
						||
                        throw new BusinessValidationFailedException("请先添加影像质控审核问题,再确认");
 | 
						||
                    }
 | 
						||
                }
 | 
						||
 | 
						||
                if (showOrderList.Count() != showOrderList.Select(t=>t.ShowOrder).Distinct().Count())
 | 
						||
                {
 | 
						||
                    throw new BusinessValidationFailedException("QC问题显示序号不允许重复");
 | 
						||
                }
 | 
						||
 | 
						||
                if (showOrderList.Where(t=>t.ParentShowOrder != null).Any(t => t.ParentShowOrder > t.ShowOrder))
 | 
						||
                {
 | 
						||
                    throw new BusinessValidationFailedException("父问题的序号要比子问题序号小,请确认");
 | 
						||
                }
 | 
						||
 | 
						||
                await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = DateTime.Now, QCQuestionConfirmedUserId = _userInfo.Id, IsQCQuestionConfirmed = true });
 | 
						||
            }
 | 
						||
 | 
						||
            
 | 
						||
 | 
						||
            return ResponseOutput.Ok();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 配置 基础逻辑信息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialConfig"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut]
 | 
						||
        public async Task<IResponseOutput> ConfigTrialBasicInfo(BasicTrialConfig trialConfig)
 | 
						||
        {
 | 
						||
            if (!await _trialRepository.Where(t => t.Id == trialConfig.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing))
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk(" only in  Initializing  or Ongoing  State  can operate ");
 | 
						||
            }
 | 
						||
 | 
						||
            var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId);
 | 
						||
 | 
						||
            if (trialInfo == null) return Null404NotFound(trialInfo);
 | 
						||
 | 
						||
            _mapper.Map(trialConfig, trialInfo);
 | 
						||
 | 
						||
            return ResponseOutput.Ok(await _repository.SaveChangesAsync());
 | 
						||
        }
 | 
						||
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<IResponseOutput> IfTrialCanOngoing(Guid trialId)
 | 
						||
        {
 | 
						||
            var canOPt = await _trialRepository.AnyAsync(trial =>
 | 
						||
                trial.Id == trialId && trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed &&
 | 
						||
                trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed);
 | 
						||
            return ResponseOutput.Ok(canOPt, msg: canOPt?"": "项目 基础配置、流程配置、加急配置 、访视计划,有未确认项");
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 更新项目状态
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialId"></param>
 | 
						||
        /// <param name="trialStatusStr"></param>
 | 
						||
        /// <param name="reason"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut("{trialId:guid}/{trialStatusStr}/{reason?}")]
 | 
						||
        [UnitOfWork]
 | 
						||
        public async Task<IResponseOutput> UpdateTrialState(Guid trialId,  string trialStatusStr, string? reason)
 | 
						||
        {
 | 
						||
 | 
						||
            var trial = (await _trialRepository.Where(t => t.Id == trialId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
 | 
						||
 | 
						||
            if (trialStatusStr == StaticData.TrialOngoing)
 | 
						||
            {
 | 
						||
                if (trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed && trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed)
 | 
						||
                {
 | 
						||
 | 
						||
                }
 | 
						||
                else
 | 
						||
                {
 | 
						||
                    return ResponseOutput.NotOk("项目 基础配置、流程配置、加急配置 、访视计划,有未确认项");
 | 
						||
                }
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
            trial.TrialStateChangeList.Add(new TrialStateChange() { OriginState = trial.TrialStatusStr, NowState = trialStatusStr, Reason = reason ?? String.Empty, TrialId = trialId });
 | 
						||
 | 
						||
            trial.TrialStatusStr = trialStatusStr;
 | 
						||
 | 
						||
 | 
						||
            //Paused、 添加工总量  算医生读片中
 | 
						||
            if (trialStatusStr.Contains(StaticData.TrialCompleted))
 | 
						||
            {
 | 
						||
                await _repository.BatchUpdateAsync<Enroll>(u => u.TrialId == trialId, e => new Enroll
 | 
						||
                {
 | 
						||
                    EnrollStatus = (int)EnrollStatus.Finished
 | 
						||
                });
 | 
						||
 | 
						||
                await _trialRepository.BatchUpdateNoTrackingAsync(u => u.Id == trialId, s => new Trial { TrialFinishedTime = DateTime.UtcNow.AddHours(8) });
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
            await _provider.SetAsync(trialId.ToString(), trialStatusStr, TimeSpan.FromDays(7));
 | 
						||
 | 
						||
            await _repository.SaveChangesAsync();
 | 
						||
 | 
						||
 | 
						||
            //var success = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
 | 
						||
 | 
						||
 | 
						||
            return ResponseOutput.Ok();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 项目状态 变更历史  
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<List<TrialStateChangeDTO>> GetTrialStateChangeList(Guid trialId)
 | 
						||
        {
 | 
						||
            return await _repository.Where<TrialStateChange>(t => t.TrialId == trialId).ProjectTo<TrialStateChangeDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 废除项目
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialId"></param>
 | 
						||
        /// <param name="isAbandon"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut("{trialId:guid}/{isAbandon:bool}")]
 | 
						||
        public async Task<IResponseOutput> AbandonTrial(Guid trialId, /*Guid? signId,*/ bool isAbandon)
 | 
						||
        {
 | 
						||
            await _trialRepository.UpdatePartialNowNoQueryAsync(trialId, u => new Trial() { IsDeleted = isAbandon });
 | 
						||
 | 
						||
            
 | 
						||
 | 
						||
 | 
						||
            return ResponseOutput.Ok();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取 配置的所有信息  没有分多个接口  
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<TrialConfigDTO> GetTrialConfigInfo(Guid trialId)
 | 
						||
        {
 | 
						||
            return await _trialRepository.Where(t => t.Id == trialId).ProjectTo<TrialConfigDTO>(_mapper.ConfigurationProvider)
 | 
						||
                .FirstOrDefaultAsync().IfNullThrowException();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
       
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 配置流程
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialConfig"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut]
 | 
						||
        public async Task<IResponseOutput> ConfigTrialProcessInfo(TrialProcessConfig trialConfig)
 | 
						||
        {
 | 
						||
            if (!await _trialRepository.Where(t => t.Id == trialConfig.TrialId).IgnoreQueryFilters().AnyAsync(t =>  t.TrialStatusStr == StaticData.TrialInitializing))
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk(" only in  Initializing   State  can operate ");
 | 
						||
            }
 | 
						||
 | 
						||
            var trialInfo = await _trialRepository.Where(t => t.Id == trialConfig.TrialId, true).Include(t => t.TrialDicList.Where(u => u.KeyName == StaticData.Criterion)).FirstOrDefaultAsync();
 | 
						||
 | 
						||
            if (trialInfo == null) return Null404NotFound(trialInfo);
 | 
						||
 | 
						||
            _mapper.Map(trialConfig, trialInfo);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            return ResponseOutput.Ok(await _repository.SaveChangesAsync());
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 配置加急信息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialConfig"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpPut]
 | 
						||
        public async Task<IResponseOutput> ConfigTrialUrgentInfo(TrialUrgentConfig trialConfig)
 | 
						||
        {
 | 
						||
 | 
						||
            if (!await _repository.Where<Trial>(t => t.Id == trialConfig.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing))
 | 
						||
            {
 | 
						||
                return ResponseOutput.NotOk(" only in  Initializing  or Ongoing  State  can operate ");
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId);
 | 
						||
 | 
						||
            if (trialInfo == null) return Null404NotFound(trialInfo);
 | 
						||
 | 
						||
            //项目紧急  当前所有已提交,但未完成的访视,设置为加急。后续提交的访视也设置为加急 ,
 | 
						||
            if (trialConfig.IsUrgent)
 | 
						||
            {
 | 
						||
 | 
						||
                await _repository.BatchUpdateAsync<SubjectVisit>(t => t.TrialId == trialInfo.Id && t.SubmitState == SubmitStateEnum.Submitted && t.ForwardState < ForwardStateEnum.Forwarded,
 | 
						||
                    s => new SubjectVisit() { IsUrgent = trialConfig.IsUrgent });
 | 
						||
            }
 | 
						||
            else //之前设置为加急的访视状态不变。后续提交的访视,为不加急。
 | 
						||
            {
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
            _mapper.Map(trialConfig, trialInfo);
 | 
						||
 | 
						||
            return ResponseOutput.Ok(await _repository.SaveChangesAsync());
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        [Obsolete]
 | 
						||
        [HttpPost("{trialId:guid}/{type}")]
 | 
						||
        public async Task<IResponseOutput> UploadTrialFile(IFormFile file, string type, Guid trialId, [FromServices] IWebHostEnvironment _hostEnvironment)
 | 
						||
        {
 | 
						||
 | 
						||
            var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
 | 
						||
            //上传根路径
 | 
						||
            var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
 | 
						||
 | 
						||
            //文件类型路径处理
 | 
						||
            var uploadFolderPath = Path.Combine(_fileStorePath, trialId.ToString(), type);
 | 
						||
            if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
 | 
						||
 | 
						||
 | 
						||
            var realName = file.FileName;
 | 
						||
            var fileNameEX = Path.GetExtension(realName);
 | 
						||
            var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
 | 
						||
 | 
						||
            var relativePath = $"/{StaticData.TrialDataFolder}/{trialId}/{type}/{trustedFileNameForFileStorage}";
 | 
						||
 | 
						||
            var filePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
 | 
						||
            using (FileStream fs = System.IO.File.Create(filePath))
 | 
						||
            {
 | 
						||
                await file.CopyToAsync(fs);
 | 
						||
                fs.Flush();
 | 
						||
            }
 | 
						||
 | 
						||
            return ResponseOutput.Ok(new
 | 
						||
            {
 | 
						||
                FilePath = relativePath,
 | 
						||
                FullFilePath = relativePath + "?access_token=" + _userInfo.UserToken
 | 
						||
            });
 | 
						||
 | 
						||
        }
 | 
						||
     
 | 
						||
    }
 | 
						||
}
 |