909 lines
38 KiB
C#
909 lines
38 KiB
C#
using IRaCIS.Core.Application.Helper;
|
||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||
using IRaCIS.Core.Domain.Models;
|
||
using IRaCIS.Core.Domain.Share;
|
||
using IRaCIS.Core.Infra.EFCore.Common;
|
||
using IRaCIS.Core.Infrastructure;
|
||
using MassTransit;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using MiniExcelLibs;
|
||
using MiniSoftware;
|
||
using SixLabors.ImageSharp;
|
||
using SixLabors.ImageSharp.PixelFormats;
|
||
using System.Data;
|
||
using System.IO;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
|
||
namespace IRaCIS.Core.Application.Service.ReadingCalculate
|
||
{
|
||
public class GeneralCalculateService(IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
|
||
IRepository<VisitTask> _visitTaskRepository,
|
||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||
ILogger<GeneralCalculateService> _logger,
|
||
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
|
||
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
|
||
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
|
||
IRepository<SubjectVisit> _subjectVisitRepository,
|
||
IOptionsMonitor<ObjectStoreServiceOptions> _options,
|
||
IRepository<TumorAssessment_RECIST1Point1> _tumorAssessmentRepository,
|
||
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
||
IRepository<InspectionFile> _inspectionFileRepository,
|
||
IOSSService _oSSService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IGeneralCalculateService
|
||
{
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 从上传文件中获取Datatable
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task<FileToDataTableDto> GetDataTableFromUpload(IFormFile file,string pathCode,Guid trialId)
|
||
{
|
||
|
||
FileToDataTableDto result=new FileToDataTableDto ();
|
||
|
||
result.DataTable = new DataTable();
|
||
var fileFolder = "Upload\\";
|
||
if (!Directory.Exists(fileFolder))
|
||
{
|
||
Directory.CreateDirectory(fileFolder);
|
||
}
|
||
|
||
var fileName = DateTime.Now.ToString("yyyyMMddHHmmss") +
|
||
Path.GetExtension(file.FileName);
|
||
var filePath = Path.Combine(fileFolder, fileName);
|
||
|
||
var fileStream = new MemoryStream();
|
||
try
|
||
{
|
||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||
{
|
||
file.CopyTo(stream);
|
||
await stream.CopyToAsync(fileStream);
|
||
|
||
result.SheetNames= stream.GetSheetNames();
|
||
stream.Position = 0;
|
||
result.DataTable = stream.QueryAsDataTable(useHeaderRow: false);
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
File.Delete(filePath);
|
||
}
|
||
|
||
|
||
try
|
||
{
|
||
var ossRelativePath = await _oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/"+ pathCode, file.FileName);
|
||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = file.FileName, RelativePath = ossRelativePath, TrialId = trialId });
|
||
}
|
||
catch (Exception)
|
||
{
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
File.Delete(filePath);
|
||
|
||
// 创建一个要删除的行集合
|
||
var rowsToRemove = new System.Collections.Generic.List<DataRow>();
|
||
|
||
// 遍历DataTable的每一行
|
||
foreach (DataRow row in result.DataTable.Rows)
|
||
{
|
||
bool allEmpty = true;
|
||
|
||
// 遍历每一列,检查值
|
||
foreach (var item in row.ItemArray)
|
||
{
|
||
if (item!=null&&!item.ToString().IsNullOrEmpty())
|
||
{
|
||
allEmpty = false;
|
||
break; // 只要有一个不为空,跳出循环
|
||
}
|
||
}
|
||
|
||
// 如果所有列都是空字符串,则添加到待删除的行集合中
|
||
if (allEmpty)
|
||
{
|
||
rowsToRemove.Add(row);
|
||
}
|
||
}
|
||
|
||
// 移除标记为待删除的行
|
||
foreach (var row in rowsToRemove)
|
||
{
|
||
result.DataTable.Rows.Remove(row);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加计算错误日志
|
||
/// </summary>
|
||
/// <param name="inDto"></param>
|
||
/// <param name="lesionName"></param>
|
||
/// <param name="lesionType"></param>
|
||
/// <returns></returns>
|
||
public async Task LogRecord(ReadingCalculateDto inDto, string lesionName, LesionType lesionType)
|
||
{
|
||
// 这里是记录日志 不需要国际化
|
||
var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).Include(x => x.Trial).FirstNotNullAsync();
|
||
var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).Include(x => x.DoctorUser).FirstNotNullAsync();
|
||
|
||
//错误级别日志:项目、标准、受试者、阅片人、任务。输出其它既往新病灶数据:
|
||
|
||
StringBuilder builder = new StringBuilder();
|
||
builder.AppendLine($"");
|
||
builder.AppendLine($"【项目】:【{criterionInfo.Trial.TrialCode}】");
|
||
builder.AppendLine($"【项目Id】:【{criterionInfo.TrialId}】");
|
||
builder.AppendLine($"【标准】:【{criterionInfo.CriterionName}】");
|
||
builder.AppendLine($"【标准Id】:【{criterionInfo.Id}】");
|
||
builder.AppendLine($"【受试者】:【{taskInfo.Subject.ShortName}】");
|
||
builder.AppendLine($"【受试者Id】:【{taskInfo.Subject.Id}】");
|
||
builder.AppendLine($"【阅片人】:【{taskInfo.DoctorUser.FirstName}】");
|
||
builder.AppendLine($"【阅片人Id】:【{taskInfo.DoctorUser.Id}】");
|
||
builder.AppendLine($"【任务】:【{taskInfo.TaskBlindName}】");
|
||
builder.AppendLine($"【任务Id】:【{taskInfo.Id}】");
|
||
builder.AppendLine($"【病灶类型】:【{lesionName}】");
|
||
|
||
var lesionInfo = inDto.QuestionInfo.Where(x => x.LesionType == lesionType).FirstOrDefault();
|
||
if (lesionInfo != null)
|
||
{
|
||
lesionInfo.TableRowInfoList.OrderBy(x => x.RowIndex).ForEach(x =>
|
||
{
|
||
builder.AppendLine(@$"【病灶编号】:【{x.RowIndex.ToString()}】,
|
||
【病灶长径】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.MajorAxis).Select(y => y.Answer).FirstIsNullReturnEmpty()}】,
|
||
【病灶短径】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.ShortAxis).Select(y => y.Answer).FirstIsNullReturnEmpty()}】,
|
||
【病灶状态】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.State).Select(y => y.Answer).FirstIsNullReturnEmpty()}】");
|
||
|
||
});
|
||
}
|
||
|
||
_logger.LogError(builder.ToString());
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取ReadingCalculateDto
|
||
/// </summary>
|
||
/// <param name="visitTaskId"></param>
|
||
/// <returns></returns>
|
||
public async Task<ReadingCalculateDto> GetReadingCalculateDto(Guid visitTaskId)
|
||
{
|
||
var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync();
|
||
|
||
var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTask.TrialReadingCriterionId).FirstNotNullAsync();
|
||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == (visitTask.SourceSubjectVisitId ?? default(Guid))).FirstOrDefaultAsync();
|
||
|
||
var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == visitTask.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync();
|
||
|
||
|
||
var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync();
|
||
|
||
var baseLinetaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId && x.TaskState == TaskState.Effect
|
||
&& x.TrialReadingCriterionId == visitTask.TrialReadingCriterionId
|
||
&& x.ArmEnum == visitTask.ArmEnum).Select(x => x.Id).FirstOrDefaultAsync();
|
||
|
||
List<QuestionInfo> questionInfos = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTask.TrialReadingCriterionId).Select(x => new QuestionInfo()
|
||
{
|
||
LesionType = x.LesionType,
|
||
QuestionId = x.Id,
|
||
QuesionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
|
||
OrderMark = x.OrderMark,
|
||
QuestionType = x.QuestionType,
|
||
ValueType = x.ValueType,
|
||
}).ToListAsync();
|
||
|
||
var questionAnswers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Select(x => new
|
||
{
|
||
x.ReadingQuestionTrialId,
|
||
x.Answer
|
||
}).ToListAsync();
|
||
|
||
var tableQuestion = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x => x.ReadingTableQuestionTrial).Select(x => new TableQuestionInfo()
|
||
{
|
||
Answer = x.Answer,
|
||
AnswerId = x.Id,
|
||
QuestionMark = x.ReadingTableQuestionTrial.QuestionMark,
|
||
TableQuestionId = x.TableQuestionId,
|
||
QuestionId = x.QuestionId,
|
||
QuestionType = x.ReadingQuestionTrial.QuestionType,
|
||
RowIndex = x.RowIndex,
|
||
RowId = x.RowId,
|
||
}).ToListAsync();
|
||
|
||
foreach (var item in questionInfos)
|
||
{
|
||
item.Answer = questionAnswers.Where(y => y.ReadingQuestionTrialId == item.QuestionId).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;
|
||
|
||
|
||
var thisItemRowInfo = rowInfoList.Where(x => x.QuestionId == item.QuestionId).ToList();
|
||
|
||
var thisItemTableQuestions = tableQuestion.Where(x => x.QuestionId == item.QuestionId).ToList();
|
||
|
||
item.TableRowInfoList = thisItemRowInfo.Select(x => new TableRowInfo()
|
||
{
|
||
RowIndex = x.RowIndex,
|
||
MeasureData = x.MeasureData,
|
||
OtherMeasureData = x.OtherMeasureData,
|
||
FristAddTaskNum = x.FristAddTaskNum,
|
||
TableQuestionList = tableQuestion.Where(y => y.QuestionId == item.QuestionId && y.RowId == x.Id).ToList(),
|
||
|
||
}).ToList();
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
ReadingCalculateDto readingData = new ReadingCalculateDto()
|
||
{
|
||
SubjectId = visitTask.SubjectId,
|
||
TaskBlindName = visitTask.TaskBlindName,
|
||
IsConvertedTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => x.IsConvertedTask).FirstOrDefaultAsync(),
|
||
BeforeConvertedTaskId = visitTask.BeforeConvertedTaskId,
|
||
VisitTaskId = visitTaskId,
|
||
SubjectVisitId = visitTask.SourceSubjectVisitId!.Value,
|
||
QuestionInfo = questionInfos,
|
||
CriterionId = visitTask.TrialReadingCriterionId,
|
||
TrialId = visitTask.TrialId,
|
||
IsAnalysisCreate = visitTask.IsAnalysisCreate,
|
||
IsSelfAnalysis = visitTask.IsSelfAnalysis,
|
||
IsBaseLine = subjectVisit!.IsBaseLine,
|
||
DoctorUserId = visitTask.DoctorUserId,
|
||
TrialReadingCriterionId = visitTask.TrialReadingCriterionId,
|
||
BaseLineTaskId = baseLinetaskId,
|
||
ArmEnum = visitTask.ArmEnum,
|
||
VisitName = subjectVisit.VisitName,
|
||
BlindName = subjectVisit.BlindName,
|
||
VisitTaskNum = visitTask.VisitTaskNum,
|
||
DigitPlaces = criterionInfo.DigitPlaces ?? 2,
|
||
};
|
||
|
||
return readingData;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 添加转化任务病灶信息
|
||
/// </summary>
|
||
/// <param name="visitTaskId"></param>
|
||
/// <param name="beforeConvertedTaskId"></param>
|
||
/// <returns></returns>
|
||
public async Task AddConvertedTaskFocus(Guid visitTaskId, Guid beforeConvertedTaskId)
|
||
{
|
||
var originalTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
|
||
|
||
var taskAnswer = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId && x.ReadingQuestionTrial.QuestionType != QuestionType.AdjustReason && x.ReadingQuestionTrial.Type != "calculation").IgnoreAutoIncludes().AsNoTracking().ToListAsync();
|
||
|
||
taskAnswer.ForEach(x =>
|
||
{
|
||
|
||
x.VisitTaskId = visitTaskId;
|
||
|
||
x.Id = NewId.NextGuid();
|
||
});
|
||
|
||
|
||
var tableRowAnswers = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId).AsNoTracking().ProjectTo<CopyTableAnswerRowInfo>(_mapper.ConfigurationProvider).IgnoreAutoIncludes().ToListAsync();
|
||
|
||
tableRowAnswers.ForEach(x =>
|
||
{
|
||
x.VisitTaskId = visitTaskId;
|
||
x.IsCurrentTaskAdd = false;
|
||
x.FristAddTaskId = x.FristAddTaskId == beforeConvertedTaskId ? visitTaskId : x.FristAddTaskId;
|
||
x.Id = NewId.NextGuid();
|
||
});
|
||
|
||
tableRowAnswers.ForEach(x =>
|
||
{
|
||
x.SplitRowId = tableRowAnswers.Where(y => y.OriginalId == x.SplitRowId).Select(y => y.Id).FirstOrDefault();
|
||
x.MergeRowId = tableRowAnswers.Where(y => y.OriginalId == x.MergeRowId).Select(y => y.Id).FirstOrDefault();
|
||
|
||
});
|
||
|
||
var tableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId).IgnoreAutoIncludes().AsNoTracking().ToListAsync();
|
||
|
||
tableAnswer.ForEach(x =>
|
||
{
|
||
x.Id = NewId.NextGuid();
|
||
x.VisitTaskId = visitTaskId;
|
||
x.RowId = tableRowAnswers.Where(y => y.OriginalId == x.RowId).Select(x => x.Id).FirstOrDefault();
|
||
});
|
||
var addrowInfo = _mapper.Map<List<ReadingTableAnswerRowInfo>>(tableRowAnswers);
|
||
switch (originalTask.TrialReadingCriterion.CriterionType)
|
||
{
|
||
case CriterionType.IRECIST1Point1:
|
||
//非靶病灶全部数据复制,不可更改。支持如果状态为:显著增大需要自动改为: 显著增大(iUPD)
|
||
var stateQuestionId = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == originalTask.TrialReadingCriterionId
|
||
&& x.ReadingQuestionTrial.LesionType == LesionType.NonTargetLesions && x.QuestionMark == QuestionMark.State).Select(x => x.Id).FirstOrDefaultAsync();
|
||
|
||
tableAnswer.ForEach(x =>
|
||
{
|
||
if (x.TableQuestionId == stateQuestionId && x.Answer.EqEnum(NoTargetState.Increase))
|
||
{
|
||
x.Answer = NoTargetState.IUPD.GetEnumInt();
|
||
}
|
||
});
|
||
|
||
// 新转换为其它既往新病灶: 状态为消失、疑似、无法评估的新病灶自动转换为:其它既往新病灶,且不可以编辑
|
||
|
||
// 找到新病灶问题
|
||
var newLesionQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == originalTask.TrialReadingCriterionId && x.LesionType == LesionType.NewLesions).FirstOrDefaultAsync();
|
||
|
||
|
||
// 找到其他既往新病灶
|
||
var otherLesionQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == originalTask.TrialReadingCriterionId && x.LesionType == LesionType.OtherPreviousNewLesion).FirstOrDefaultAsync();
|
||
|
||
|
||
|
||
if (newLesionQuestion != null && otherLesionQuestion != null)
|
||
{
|
||
// 找到表格问题
|
||
var newLesionTableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == newLesionQuestion.Id).ToListAsync();
|
||
|
||
// 找到表格问题
|
||
var otherLesionTableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == otherLesionQuestion.Id).ToListAsync();
|
||
|
||
// 找到病灶状态
|
||
var newstateQuestionId = newLesionTableQuestionList.Where(x => x.QuestionMark == QuestionMark.State).Select(x => x.Id).FirstOrDefault();
|
||
|
||
|
||
var stateAnswers = new List<string>() {
|
||
NewLesionState.Loss.GetEnumInt(),
|
||
NewLesionState.Suspected.GetEnumInt(),
|
||
NewLesionState.UnableEvaluate.GetEnumInt()
|
||
};
|
||
|
||
var needRowIds = tableAnswer.Where(x => x.TableQuestionId == newstateQuestionId && stateAnswers.Contains(x.Answer)).Select(x => x.RowId).Distinct().ToList();
|
||
|
||
|
||
|
||
var index = 0;
|
||
|
||
addrowInfo.ForEach(x =>
|
||
{
|
||
|
||
if (needRowIds.Contains(x.Id))
|
||
{
|
||
index++;
|
||
x.RowIndex = index;
|
||
x.RowMark = otherLesionQuestion.OrderMark + x.RowIndex.GetLesionMark();
|
||
var fristAddTaskId = x.FristAddTaskId.Clone();
|
||
x.FromMark = fristAddTaskId == beforeConvertedTaskId ? string.Empty : x.RowMark;
|
||
x.FristAddTaskId = fristAddTaskId == beforeConvertedTaskId ? visitTaskId : fristAddTaskId;
|
||
x.QuestionId = otherLesionQuestion.Id;
|
||
x.OrderMark = otherLesionQuestion.OrderMark;
|
||
x.ReportMark = x.RowMark;
|
||
|
||
}
|
||
|
||
|
||
});
|
||
|
||
|
||
tableAnswer.ForEach(x =>
|
||
{
|
||
if (needRowIds.Contains(x.RowId))
|
||
{
|
||
|
||
var row = addrowInfo.Where(y => y.Id == x.RowId).FirstOrDefault();
|
||
if (row != null)
|
||
{
|
||
x.RowIndex = row.RowIndex;
|
||
}
|
||
|
||
|
||
x.QuestionId = otherLesionQuestion.Id;
|
||
|
||
var newLesionTableQuestion = newLesionTableQuestionList.Where(y => y.Id == x.TableQuestionId).FirstOrDefault();
|
||
if (newLesionTableQuestion != null)
|
||
{
|
||
x.TableQuestionId = otherLesionTableQuestionList.Where(y => y.QuestionMark == newLesionTableQuestion.QuestionMark).Select(x => x.Id).FirstOrDefault();
|
||
|
||
}
|
||
|
||
}
|
||
|
||
});
|
||
}
|
||
|
||
break;
|
||
}
|
||
await _readingTaskQuestionAnswerRepository.AddRangeAsync(taskAnswer);
|
||
await _readingTableAnswerRowInfoRepository.AddRangeAsync(addrowInfo);
|
||
await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswer);
|
||
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取阅片报告任务List
|
||
/// </summary>
|
||
/// <param name="visitTaskId"></param>
|
||
/// <returns></returns>
|
||
public async Task<List<VisitTaskInfo>> GetReadingReportTaskList(Guid visitTaskId)
|
||
{
|
||
var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
|
||
|
||
var isAdditionalQuestionId = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTaskInfo.TrialReadingCriterionId && x.IsAdditional).IgnoreQueryFilters().Select(x => x.Id).ToListAsync();
|
||
|
||
var taskquery = _visitTaskRepository
|
||
.Where(x => (x.SubjectId == visitTaskInfo.SubjectId
|
||
&& (x.TaskState == TaskState.Effect || x.TaskState == TaskState.Freeze)
|
||
&& x.IsAnalysisCreate == visitTaskInfo.IsAnalysisCreate
|
||
&& x.ArmEnum == visitTaskInfo.ArmEnum
|
||
&& x.IsSelfAnalysis == visitTaskInfo.IsSelfAnalysis
|
||
&& x.VisitTaskNum <= visitTaskInfo.VisitTaskNum
|
||
&& x.ArmEnum == visitTaskInfo.ArmEnum
|
||
&& x.TrialReadingCriterionId == visitTaskInfo.TrialReadingCriterionId
|
||
&& x.ReadingCategory == ReadingCategory.Visit && x.ReadingTaskState == ReadingTaskState.HaveSigned) || x.Id == visitTaskId
|
||
);
|
||
if (visitTaskInfo.ReadingTaskState == ReadingTaskState.HaveSigned)
|
||
{
|
||
taskquery = _visitTaskRepository.Where(x => visitTaskInfo.ReportRelatedTaskIdList.Contains(x.Id) || x.Id == visitTaskInfo.Id);
|
||
}
|
||
if (visitTaskInfo.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder)
|
||
{
|
||
taskquery = _visitTaskRepository.Where(x => x.Id == visitTaskInfo.Id);
|
||
}
|
||
|
||
|
||
|
||
var taskInfoList = await taskquery.OrderBy(x => x.VisitTaskNum).Select(x => new VisitTaskInfo()
|
||
{
|
||
BlindName = x.TaskBlindName,
|
||
IsBaseLine = x.SourceSubjectVisit.IsBaseLine,
|
||
VisitTaskId = x.Id,
|
||
TaskState = x.TaskState,
|
||
TaskName = x.TaskName,
|
||
LatestScanDate = x.SourceSubjectVisit != null ? x.SourceSubjectVisit.LatestScanDate : null,
|
||
VisitTaskNum = x.VisitTaskNum,
|
||
IsConvertedTask = x.IsConvertedTask,
|
||
BeforeConvertedTaskId = x.BeforeConvertedTaskId,
|
||
//CrterionDictionaryGroup = x.CrterionDictionaryGroup,
|
||
IsCurrentTask = x.Id == visitTaskId,
|
||
|
||
}).OrderBy(x => x.VisitTaskNum).ThenByDescending(x => x.TaskState).ToListAsync();
|
||
|
||
|
||
taskInfoList.ForEach(x =>
|
||
{
|
||
x.CrterionDictionaryGroup = ReadingCommon.GetCrterionDictionaryGroup(x.IsConvertedTask);
|
||
});
|
||
|
||
var taskIds = taskInfoList.Select(x => x.VisitTaskId).ToList();
|
||
|
||
var isHaveAdditionalTaskIds = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId) && isAdditionalQuestionId.Contains(x.ReadingQuestionTrialId)).Select(x => x.VisitTaskId).Distinct().ToListAsync();
|
||
|
||
taskInfoList.ForEach(x =>
|
||
{
|
||
x.IsHaveAdditionalQuestion = isHaveAdditionalTaskIds.Contains(x.VisitTaskId);
|
||
});
|
||
return taskInfoList;
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 空转为横线
|
||
/// </summary>
|
||
/// <param name="myDictionary"></param>
|
||
/// <returns></returns>
|
||
public Dictionary<string, object> StringEmptyTurnedLine(Dictionary<string, object> myDictionary)
|
||
{
|
||
foreach (var item in myDictionary)
|
||
{
|
||
if (item.Value == null)
|
||
{
|
||
myDictionary[item.Key] = "-";
|
||
}
|
||
else if (item.Value.GetType() == typeof(string))
|
||
{
|
||
if (item.Value.ToString() == string.Empty || item.Value == null)
|
||
{
|
||
myDictionary[item.Key] = "-";
|
||
};
|
||
|
||
}
|
||
else if (item.Value.GetType() == typeof(List<Dictionary<string, object>>))
|
||
{
|
||
var value = item.Value;
|
||
|
||
foreach (var column in value as List<Dictionary<string, object>>)
|
||
{
|
||
foreach (var item2 in column)
|
||
{
|
||
if (item2.Value.ToString() == string.Empty || item.Value == null)
|
||
{
|
||
column[item2.Key] = "-";
|
||
};
|
||
}
|
||
|
||
}
|
||
|
||
myDictionary[item.Key] = value;
|
||
|
||
}
|
||
|
||
}
|
||
return myDictionary;
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取word图片
|
||
/// </summary>
|
||
/// <param name="url"></param>
|
||
/// <param name="savePath"></param>
|
||
/// <param name="width"></param>
|
||
/// <returns></returns>
|
||
public async Task<MiniWordPicture> GetWordPicture(string url, string savePath, int width)
|
||
{
|
||
var resultUrl = await this.FileDownSave(url, savePath);
|
||
|
||
int picWidth = 0;
|
||
int picHeight = 0;
|
||
|
||
|
||
|
||
using (var bitmap = Image<Rgba32>.Load(resultUrl))
|
||
{
|
||
// 获取图片的宽度和高度
|
||
picWidth = bitmap.Width;
|
||
picHeight = bitmap.Height;
|
||
}
|
||
|
||
var height = width * picHeight / picWidth;
|
||
|
||
return new MiniWordPicture()
|
||
{
|
||
Path = resultUrl,
|
||
Height = height,
|
||
Width = width
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取word图片
|
||
/// </summary>
|
||
/// <param name="url"></param>
|
||
/// <param name="savePath"></param>
|
||
/// <param name="width"></param>
|
||
/// <returns></returns>
|
||
public async Task<MiniWordPicture> GetWordPicture(string url, string savePath, int width, int height)
|
||
{
|
||
var resultUrl = await this.FileDownSave(url, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"));
|
||
|
||
return new MiniWordPicture()
|
||
{
|
||
Path = resultUrl,
|
||
Height = height,
|
||
Width = width
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 最大宽高
|
||
/// </summary>
|
||
/// <param name="url"></param>
|
||
/// <param name="savePath"></param>
|
||
/// <param name="width"></param>
|
||
/// <param name="height"></param>
|
||
/// <returns></returns>
|
||
public async Task<MiniWordPicture> GetWordPictureMaxWL(string url, string savePath, int width, int height)
|
||
{
|
||
var resultUrl = await this.FileDownSave(url, savePath);
|
||
|
||
|
||
int picWidth = 0;
|
||
int picHeight = 0;
|
||
using (var bitmap = Image<Rgba32>.Load(resultUrl))
|
||
{
|
||
// 获取图片的宽度和高度
|
||
picWidth = bitmap.Width;
|
||
picHeight = bitmap.Height;
|
||
}
|
||
|
||
if (picWidth / picHeight > width / height)
|
||
{
|
||
height = width * picHeight / picWidth;
|
||
|
||
}
|
||
else
|
||
{
|
||
width = height * picWidth / picHeight;
|
||
|
||
}
|
||
|
||
|
||
return new MiniWordPicture()
|
||
{
|
||
Path = resultUrl,
|
||
Height = height,
|
||
Width = width
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取任务问题答案
|
||
/// </summary>
|
||
/// <param name="answerList">问题答案</param>
|
||
/// <param name="dictionList">字典数据</param>
|
||
/// <param name="unitDictionary">单位字典</param>
|
||
/// <param name="taskId">任务Id</param>
|
||
/// <param name="questionType">任务类型</param>
|
||
/// <returns></returns>
|
||
public string GetTaskanswer(List<ReadingTaskQuestionAnswer>? answerList, List<Dictionary>? dictionList, List<Dictionary>? unitDictionary, Guid taskId, QuestionType questionType)
|
||
{
|
||
var answerData = answerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.QuestionType == questionType);
|
||
if (answerData == null || answerData.Answer == string.Empty)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
var answer = string.Empty;
|
||
if (answerData.ReadingQuestionTrial.QuestionGenre == TableQuestionType.Dictionary)
|
||
{
|
||
answer = dictionList.Where(x => x.Code == answerData.ReadingQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
|
||
}
|
||
else
|
||
{
|
||
answer = answerData.Answer;
|
||
}
|
||
if (answer != "NA" && answerData.ReadingQuestionTrial.Unit != null && answerData.ReadingQuestionTrial.Unit != ValueUnit.none)
|
||
{
|
||
answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
|
||
}
|
||
if (answer != "NA" && answerData.ReadingQuestionTrial.ValueType == ValueOfType.Percentage)
|
||
{
|
||
answer += " %";
|
||
|
||
}
|
||
|
||
return answer;
|
||
}
|
||
|
||
|
||
public void SetPropertyDynamically(object targetObj, string targetPropName, object sourceObj, string prefix)
|
||
{
|
||
// 1. 解析目标属性名(如"CheckInfoStr")
|
||
string basePropName = targetPropName.Replace(prefix, "");
|
||
|
||
// 2. 获取源对象路径(如"VisitOne.CheckInfoStr")
|
||
string sourcePath = $"Visit{prefix}.{basePropName}";
|
||
object sourceValue = GetNestedPropertyValue(sourceObj, sourcePath);
|
||
|
||
// 3. 赋值给目标属性
|
||
PropertyInfo targetProp = targetObj.GetType().GetProperty(prefix+targetPropName);
|
||
if (targetProp != null && sourceValue != null)
|
||
{
|
||
targetProp.SetValue(targetObj, sourceValue);
|
||
}
|
||
}
|
||
|
||
public object GetNestedPropertyValue(object obj, string path)
|
||
{
|
||
foreach (string part in path.Split('.'))
|
||
{
|
||
if (obj == null) return null;
|
||
PropertyInfo prop = obj.GetType().GetProperty(part);
|
||
if (prop == null) return null;
|
||
obj = prop.GetValue(obj);
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取报告No
|
||
/// </summary>
|
||
/// <param name="visitTaskInfo"></param>
|
||
/// <returns></returns>
|
||
public async Task<string> GetReportExportNo(VisitTask visitTaskInfo)
|
||
{
|
||
if (visitTaskInfo.ReportExportDate != null && visitTaskInfo.ReportExportNum != null)
|
||
{
|
||
return visitTaskInfo.ReportExportDate.Value.ToString("yyyyMMdd") + visitTaskInfo.ReportExportNum.ToString().PadLeft(4, '0');
|
||
}
|
||
else
|
||
{
|
||
DateTime today = DateTime.Today;
|
||
|
||
|
||
var reportExportNum = await _visitTaskRepository.Where(x => x.TrialId == visitTaskInfo.TrialId && x.ReportExportDate != null && x.ReportExportDate.Value.Date == today).MaxAsync(x => x.ReportExportNum);
|
||
reportExportNum = reportExportNum == null ? 0 : reportExportNum;
|
||
await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == visitTaskInfo.Id, x => new VisitTask()
|
||
{
|
||
|
||
ReportExportDate = today,
|
||
ReportExportNum = reportExportNum + 1
|
||
});
|
||
|
||
return today.ToString("yyyyMMdd") + (reportExportNum + 1).ToString().PadLeft(4, '0');
|
||
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取并复制文件流
|
||
/// </summary>
|
||
/// <param name="outputFilePath"></param>
|
||
/// <returns></returns>
|
||
public Stream ReadAndReturnStream(string outputFilePath)
|
||
{
|
||
byte[] data;
|
||
|
||
using (Stream stream = new FileStream(outputFilePath, FileMode.Open, FileAccess.Read))
|
||
{
|
||
// 从流中读取数据保存到内存中
|
||
using (MemoryStream memoryStream = new MemoryStream())
|
||
{
|
||
stream.CopyTo(memoryStream);
|
||
data = memoryStream.ToArray();
|
||
}
|
||
}
|
||
|
||
// 返回内存中的数据作为新的流
|
||
return new MemoryStream(data);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下载并保存
|
||
/// </summary>
|
||
/// <param name="url">网络路径</param>
|
||
/// <param name="savePath">保存本地的文件夹</param>
|
||
/// <returns><placeholder>A <see cref="Task"/>
|
||
public async Task<string> FileDownSave(string url, string savePath)
|
||
{
|
||
|
||
|
||
await _oSSService.DownLoadFromOSSAsync(url, savePath);
|
||
|
||
return savePath;
|
||
|
||
//try
|
||
//{
|
||
// HttpClient httpClient = new HttpClient();
|
||
// if (!string.IsNullOrWhiteSpace(url))
|
||
// {
|
||
// string[] strArry = url.Split('/');
|
||
// savePath = savePath + "/" + strArry[strArry.Length - 1];
|
||
// }
|
||
|
||
// var t = httpClient.GetByteArrayAsync(url);
|
||
// t.Wait();
|
||
// Stream responseStream = new MemoryStream(t.Result);
|
||
// Stream stream = new FileStream(savePath, FileMode.Create);
|
||
// byte[] bArr = new byte[1024];
|
||
// int size = responseStream.Read(bArr, 0, bArr.Length);
|
||
// while (size > 0)
|
||
// {
|
||
// stream.Write(bArr, 0, size);
|
||
// size = responseStream.Read(bArr, 0, bArr.Length);
|
||
// }
|
||
|
||
// stream.Close();
|
||
// responseStream.Close();
|
||
|
||
// return savePath;
|
||
//}
|
||
//catch (Exception)
|
||
//{
|
||
|
||
// throw new BusinessValidationFailedException(_localizer["ReadingCalculate_ImageNotExist"]);
|
||
//}
|
||
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取任务表格问题答案
|
||
/// </summary>
|
||
/// <param name="tableAnswerList">表格答案</param>
|
||
/// <param name="dictionList">字典</param>
|
||
/// <param name="unitDictionary">单位字典</param>
|
||
/// <param name="taskId">任务Id</param>
|
||
/// <param name="lesionType">病灶类型</param>
|
||
/// <param name="questionMark">问题标识</param>
|
||
/// <param name="rowIndex">索引</param>
|
||
/// <returns></returns>
|
||
public string GetTaskTableAnswer(List<ReadingTableQuestionAnswer>? tableAnswerList, List<Dictionary>? dictionList, List<Dictionary>? unitDictionary, Guid taskId, LesionType lesionType, QuestionMark questionMark, decimal rowIndex,bool AutoUnit=true)
|
||
{
|
||
var answerData = tableAnswerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.LesionType == lesionType && x.ReadingTableQuestionTrial.QuestionMark == questionMark && x.RowIndex == rowIndex);
|
||
|
||
if (answerData == null || answerData.Answer == string.Empty)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
var answer = string.Empty;
|
||
if (answerData.ReadingTableQuestionTrial.TableQuestionType == TableQuestionType.Dictionary)
|
||
{
|
||
answer = dictionList.Where(x => x.Code == answerData.ReadingTableQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
|
||
|
||
}
|
||
else
|
||
{
|
||
answer = answerData.Answer;
|
||
|
||
}
|
||
if (AutoUnit)
|
||
{
|
||
if (answer != "NA" && answerData.ReadingTableQuestionTrial.Unit != null && answerData.ReadingTableQuestionTrial.Unit != ValueUnit.none)
|
||
{
|
||
answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingTableQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty();
|
||
}
|
||
|
||
if (answer != "NA" && answerData.ReadingTableQuestionTrial.ValueType == ValueOfType.Percentage)
|
||
{
|
||
answer += " %";
|
||
|
||
}
|
||
}
|
||
|
||
|
||
return answer;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取病灶的图片 rowinfoList要带question的信息
|
||
/// </summary>
|
||
/// <param name="rowinfoList"></param>
|
||
/// <param name="lesionType"></param>
|
||
/// <returns></returns>
|
||
public async Task<List<Dictionary<string, object>>> GetLesionPic(List<ReadingTableAnswerRowInfo> rowinfoList, LesionType lesionType, Guid DownLoadGuid)
|
||
{
|
||
var lesionRowinfo = rowinfoList.Where(x => x.PicturePath != string.Empty && x.ReadingQuestionTrial.LesionType == lesionType).OrderBy(x => x.VisitTask.VisitTaskNum).OrderBy(x => x.RowIndex).ToList();
|
||
List<Dictionary<string, object>> lesionImage = new List<Dictionary<string, object>>();
|
||
|
||
|
||
var lesionCount = lesionRowinfo.Select(x => x.VisitTask.VisitTaskNum).Distinct().OrderBy(x => x).ToList();
|
||
|
||
int picNum = 0;
|
||
|
||
foreach (var num in lesionCount)
|
||
{
|
||
var picRowinfo = lesionRowinfo.Where(x => x.VisitTask.VisitTaskNum == num).OrderBy(x => x.RowIndex).ToList();
|
||
var picCount = picRowinfo.Count();
|
||
for (int i = 0; i < Math.Ceiling((double)picCount / 2); i++)
|
||
{
|
||
lesionImage.Add(new Dictionary<string, object>()
|
||
{
|
||
{ "ImageOneMark",getPicNum(true)+ picRowinfo[2*i].VisitTask.TaskName+" "+picRowinfo[2*i].RowMark},
|
||
{ "ImageOneUrl" ,await GetWordPictureMaxWL(_options.CurrentValue.MinIO.ViewEndpoint+picRowinfo[2*i].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290,390) },
|
||
{ "ImageTwoMark",getPicNum(picCount>2*i+1) + (picCount<=2*i+1?string.Empty:picRowinfo[2*i+1].VisitTask.TaskName+" "+picRowinfo[2*i+1].RowMark) },
|
||
{ "ImageTwoUrl", picCount<=2*i+1?string.Empty:await GetWordPictureMaxWL(_options.CurrentValue.MinIO.ViewEndpoint+picRowinfo[2*i+1].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290, 390) },
|
||
|
||
});
|
||
}
|
||
}
|
||
|
||
string getPicNum(bool isHavePic)
|
||
{
|
||
if (isHavePic)
|
||
{
|
||
picNum += 1;
|
||
|
||
return $"图{picNum} ";
|
||
|
||
}
|
||
else
|
||
{
|
||
return string.Empty;
|
||
}
|
||
}
|
||
|
||
return lesionImage;
|
||
|
||
}
|
||
}
|
||
}
|