using IRaCIS.Core.Infrastructure.ExpressionExtend; using IRaCIS.Application.Interfaces; using IRaCIS.Application.Contracts; using IRaCIS.Core.Infra.EFCore; using IRaCIS.Core.Application.Filter; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Application.MediatR.CommandAndQueries; using Magicodes.ExporterAndImporter.Core; using Magicodes.ExporterAndImporter.Excel; using Magicodes.ExporterAndImporter.Excel.AspNetCore; using IRaCIS.Core.Application.Service.Inspection.Interface; using Newtonsoft.Json; namespace IRaCIS.Application.Services { [ApiExplorerSettings(GroupName = "Trial")] public class VisitPlanService : BaseService, IVisitPlanService { private readonly IRepository _visitStageRepository; private readonly IRepository _trialRepository; private readonly IRepository _subjectVisitRepository; private readonly IRepository _influnceStatRepository; private readonly IRepository _influnceRepository; private readonly IInspectionService _inspectionService; public VisitPlanService(IRepository visitStageRepository,IRepository trialRepository, IRepository subjectVisitRepository, IRepository influnceStatRepository, IRepository visitPlanInfluenceStudy, IInspectionService inspectionService) { _visitStageRepository = visitStageRepository; _trialRepository = trialRepository; this._subjectVisitRepository = subjectVisitRepository; this._influnceStatRepository = influnceStatRepository; this._influnceRepository = visitPlanInfluenceStudy; this._inspectionService = inspectionService; } ///暂时不用 /// 获取项目访视计划 public async Task> GetTrialVisitStageList(VisitPlanQueryDTO param) { var visitStageQuery = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == param.TrialId) .WhereIf(!string.IsNullOrWhiteSpace(param.Keyword), t => t.VisitName.Contains(param.Keyword)) .ProjectTo(_mapper.ConfigurationProvider); return await visitStageQuery.ToPagedListAsync(param.PageIndex, param.PageSize, "CreateTime", param.Asc); } /// 根据项目Id,获取项目访视计划(不分页)[New] [HttpGet("{trialId:guid}")] public async Task GetVisitStageList(Guid trialId) { var query = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == trialId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); var list = await query.ToListAsync(); var trial = await _repository.FirstOrDefaultAsync(t => t.Id == trialId).IfNullThrowException(); return new VisitPlanView() { VisitPlanList = list, TimePointsPerPatient = trial.TimePointsPerPatient, VisitPlanConfirmed = trial.VisitPlanConfirmed, IsHaveFirstGiveMedicineDate = trial.IsHaveFirstGiveMedicineDate, //SubjectHasAdded = _subjectVisitRepository.Any(t => t.TrialId == trialId) }; } /// /// 获取访视计划下拉框列表 /// /// /// [HttpGet("{trialId:guid}")] public async Task> GetTrialVisitStageSelect(Guid trialId) { var query = _visitStageRepository.Where(u => u.TrialId == trialId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); var list = await query.ToListAsync(); return list; } /// 添加或更新访视计划某项[New] [HttpPost] [UnitOfWork] public async Task> AddOrUpdateVisitStage(VisitPlanCommand visitPlan) { DateTime createtime = DateTime.Now; List datas = new List(); if (!await _trialRepository.Where(t => t.Id == visitPlan.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing)) { return ResponseOutput.NotOk(" only in Initializing or Ongoing State can operate "); } var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId,ignoreQueryFilters:true) .Select(t => new { t.Id, t.VisitNum, t.VisitDay }).OrderBy(t => t.VisitNum).ToListAsync(); //更新的时候,需要排除自己 if (visitPlan.Id != null) { visitPlanList = visitPlanList.Where(t => t.Id != visitPlan.Id).ToList(); } if (visitPlanList.Any(t => t.VisitNum < visitPlan.VisitNum)) { //比当前 visitNum小的 visitDay的最大值 还小 不允许添加 if (visitPlan.VisitDay <= visitPlanList.Where(t => t.VisitNum < visitPlan.VisitNum).Select(t => t.VisitDay).Max()) { return ResponseOutput.NotOk("For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum."); } } if (visitPlanList.Any(t => t.VisitNum > visitPlan.VisitNum)) { if (visitPlan.VisitDay >= visitPlanList.Where(t => t.VisitNum > visitPlan.VisitNum).Select(t => t.VisitDay).Min()) { return ResponseOutput.NotOk("For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum."); } } if (visitPlan.Id == Guid.Empty || visitPlan.Id == null)//add { if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum), true)) { return ResponseOutput.NotOk("A visit with the same VisitName/VisitNum already existed in the current visit plan."); } if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine, true) && visitPlan.IsBaseLine) { return ResponseOutput.NotOk("A visit already is baseline in the current visit plan."); } //已添加受试者 都不存在该新增的计划名称 那么该项目所有受试者都增加一个访视记录 if (!await _subjectVisitRepository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId)) { var subjectSVS = await _subjectVisitRepository.Where(t => t.TrialId == visitPlan.TrialId).Select(t => new { t.SubjectId, t.SiteId,t.IsFinalVisit }).Distinct().ToListAsync(); var subjects = subjectSVS.Select(t => new { t.SubjectId, t.SiteId }).Distinct().ToList(); foreach (var subject in subjects) { var svItem = _mapper.Map(visitPlan); svItem.SiteId = subject.SiteId; svItem.SubjectId = subject.SubjectId; svItem.Id = Guid.NewGuid(); //设置了末次访视,那么加访视计划的时候,设置为不可用 if (subjectSVS.Any(t => t.SubjectId == svItem.SubjectId && t.IsFinalVisit)) { svItem.VisitExecuted = VisitExecutedEnum.Unavailable; } //datas.Add(new DataInspection() //{ // SubjectVisitId = svItem.Id, // SubjectVisitName = svItem.VisitName, // BlindName = visitPlan.BlindName, // Identification = "Add|Visit|Info|Visit-Image Upload", // SiteId = svItem.SiteId, // TrialId = svItem.TrialId, // SubjectId = svItem.SubjectId, // IsSign = false, // CreateTime = createtime, // JsonDetail = JsonConvert.SerializeObject(svItem) //}); await _repository.AddAsync(svItem); } } var visitPlanItem = _mapper.Map(visitPlan); visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3"); var result = await _repository.AddAsync(visitPlanItem); visitPlan.Id = result.Id; //datas.Add(new DataInspection() //{ // BlindName = visitPlan.BlindName, // Identification = "Add|Visit|Info|Visit-Image Upload", // TrialId = visitPlan.TrialId, // IsSign = false, // CreateTime = createtime.AddSeconds(1), // VisitStageId = result.Id, // JsonDetail = JsonConvert.SerializeObject(visitPlan) //}); //更新项目访视计划状态为未确认 await _trialRepository.BatchUpdateAsync(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false }); await _repository.SaveChangesAsync(); //return ResponseOutput.Ok(result.Id.ToString()); } else//update { if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id,true)) { return ResponseOutput.NotOk("A visit with the same VisitName/VisitNum already existed in the current visit plan."); } if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id,true) && visitPlan.IsBaseLine) { return ResponseOutput.NotOk("A visit already is baseline in the current visit plan."); } var stage = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id,true); if (stage == null) return ResponseOutput.NotOk("None"); //修改是否是基线 if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine) { if (await _repository.Where(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit)) { return ResponseOutput.NotOk("有CRC已经为基线上传了影像数据,不允许修改基线"); } } _mapper.Map(visitPlan, stage); stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); //更新项目访视计划状态为未确认 //await _trialRepository.UpdateFromQueryAsync(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false }); await _repository.SaveChangesAsync(); //return ResponseOutput.Ok(); } await _inspectionService.AddListInspectionRecordAsync(datas); return ResponseOutput.Ok(visitPlan.Id.Value.ToString()); } /// 删除项目计划某一项[New] [HttpDelete("{id:guid}/{trialId:guid}")] [TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)] [TypeFilter(typeof(TrialResourceFilter))] public async Task DeleteVisitStage(Guid id) { var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id); if (visitPlan == null) return Null404NotFound(visitPlan); if (await _repository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed)) { return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed."); } var list = await _subjectVisitRepository.Where(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName).ToListAsync(); List datas = new List(); var createtime = DateTime.Now.AddSeconds(1); list.ForEach(x => { datas.Add(new DataInspection() { BlindName = x.BlindName, IsSign = false, SiteId = x.SiteId, SubjectId = x.SubjectId, SubjectVisitId = x.Id, CreateTime = createtime, SubjectVisitName = x.VisitName, TrialId = x.TrialId, JsonDetail = JsonConvert.SerializeObject(x), Identification = "Delete|Visit|Data|Visit-Image Upload" }); }); await _inspectionService.AddListInspectionRecordAsync(datas); await _repository.BatchDeleteAsync(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName); var result = await _visitStageRepository.BatchDeleteAsync(u => u.Id == id); return ResponseOutput.Result(result); } [UnitOfWork] [HttpPost("{trialId:guid}")] [TrialAudit(AuditType.TrialAudit, AuditOptType.ConfirmTrialVisitPlan)] public async Task ConfirmTrialVisitPlan(Guid trialId) { if (!await _trialRepository.AnyAsync(t => t.Id == trialId &&( t.TrialStatusStr==StaticData.TrialInitializing || t.TrialStatusStr == StaticData.TrialOngoing))) { return ResponseOutput.NotOk("仅仅在项目初始化或者进行中时,才允许修改确认"); } if (!await _visitStageRepository.AnyAsync(t => t.TrialId == trialId && t.IsBaseLine)) { return ResponseOutput.NotOk("没有基线,不允许确认"); } if (!await _trialRepository.AnyAsync(t => t.Id == trialId && t.IsTrialBasicLogicConfirmed && t.IsTrialProcessConfirmed && t.IsTrialUrgentConfirmed)) { return ResponseOutput.NotOk("项目配置未确认,不允许确认访视计划"); } var svList = await _visitStageRepository.Where(t => t.TrialId == trialId).Select(u => new { u.VisitDay, u.IsBaseLine }).ToListAsync(); if (svList.Min(t => t.VisitDay) != svList.Where(t => t.IsBaseLine).FirstOrDefault()?.VisitDay) { return ResponseOutput.NotOk("基线VisitDay 不是最小的, 不允许确认"); } List datas = new List(); var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed&&x.TrialId== trialId).ToListAsync(); //更新项目访视计划状态为已确认 await _trialRepository.BatchUpdateAsync(u => u.Id == trialId, t => new Trial() { VisitPlanConfirmed = true }); //找到访视计划修改的Item var changedList = await _visitStageRepository.Where(t => t.TrialId == trialId && t.IsConfirmed == false) .Select(t => new { t.Trial.IsHaveFirstGiveMedicineDate, t.Id, t.VisitName, t.TrialId, t.VisitWindowLeft, t.VisitWindowRight, t.VisitDay, t.VisitNum, t.IsBaseLine }).ToListAsync(); var createtime = DateTime.Now.AddSeconds(1); changedList.ForEach(x => { datas.Add(new DataInspection() { IsSign = false, CreateTime = createtime, //SubjectVisitName = x.VisitName, VisitStageId = x.Id, TrialId = x.TrialId, JsonDetail = JsonConvert.SerializeObject(x), Identification = "Confirm|Visit Plan Template|Data|Trial Setting-Visit Plan" }); }); //访视计划 整体状态变更为 确认 await _visitStageRepository.BatchUpdateAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true ,IsHaveFirstConfirmed = true}); var stat = new VisitPlanInfluenceStat() { TrialId = trialId }; foreach (var changedItem in changedList) { //找到该项目 访视已经执行,并且配置了有首次给药日期 并且更新后超窗的访视,要把超窗之前的值也要查询出来 var qcPassedVisitList = await _repository.Where(t => t.TrialId == trialId && t.VisitExecuted == VisitExecutedEnum.Executed && t.AuditState == AuditStateEnum.QCPassed && t.Trial.IsHaveFirstGiveMedicineDate == true && t.VisitStageId == changedItem.Id && t.Subject.FirstGiveMedicineTime != null ).Select(k => new { SubjectVisitId = k.Id, SelfWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowLeft), SelfWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowRight + 1).AddSeconds(-1), NowWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft), NowWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight + 1).AddSeconds(-1), NoneDicomStudyList = k.NoneDicomStudyList //之前是查询调整之后超窗的 现在调整前超窗 调整后 没超窗的也要记录 //.Where(study => study.ImageDate k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) .Select(t => new { NoneDicomStudyId = t.Id, t.Modality, StudyTime = t.ImageDate }), DicomStudyList = k.StudyList //.Where(study => study.StudyTime k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) .Select(t => new { StudyId = t.Id, Modality = t.Modalities, t.StudyTime }) }).ToListAsync(); foreach (var visit in qcPassedVisitList) { //找到本身没有超窗的数据 修改后超窗的 visit.DicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => { stat.InconsistentCount++; stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() { IsOverWindowNowNotOverWindow = false, Modality = t.Modality, SubjectVisitId = visit.SubjectVisitId, StudyId = t.StudyId, IsDicomStudy = true, StudyTime = t.StudyTime, TrialId = trialId, HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") }); }); visit.NoneDicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => { stat.InconsistentCount++; stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() { IsOverWindowNowNotOverWindow = false, Modality = t.Modality, SubjectVisitId = visit.SubjectVisitId, StudyId = t.NoneDicomStudyId, IsDicomStudy = false, StudyTime = t.StudyTime, TrialId = trialId, HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") }); }); //本身超窗 修改后没超窗的 visit.DicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => { stat.InconsistentCount++; stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() { IsOverWindowNowNotOverWindow = true, Modality = t.Modality, SubjectVisitId = visit.SubjectVisitId, StudyId = t.StudyId, IsDicomStudy = true, StudyTime = t.StudyTime, TrialId = trialId, HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") }); }); visit.NoneDicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => { stat.InconsistentCount++; stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() { IsOverWindowNowNotOverWindow = true, Modality = t.Modality, SubjectVisitId = visit.SubjectVisitId, StudyId = t.NoneDicomStudyId, IsDicomStudy = false, StudyTime = t.StudyTime, TrialId = trialId, HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") }); }); } var list = await _subjectVisitRepository.Where(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id).ToListAsync(); list.ForEach(x => { datas.Add(new DataInspection() { BlindName = x.BlindName, IsSign = false, SiteId = x.SiteId, SubjectId = x.SubjectId, SubjectVisitId = x.Id, CreateTime = createtime, SubjectVisitName = x.VisitName, TrialId = x.TrialId, JsonDetail = JsonConvert.SerializeObject(new { IsBaseLine = changedItem.IsBaseLine, VisitName = changedItem.VisitName, VisitNum = changedItem.VisitNum, VisitDay = changedItem.VisitDay, VisitWindowLeft = changedItem.VisitWindowLeft, VisitWindowRight = changedItem.VisitWindowRight }), Identification = "Edit|Visit|Info|Visit-Image Upload" }); }); //变更某一访视计划Item 受试者访视相关字段 await _repository.BatchUpdateAsync(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id, k => new SubjectVisit() { IsBaseLine = changedItem.IsBaseLine, VisitName = changedItem.VisitName, VisitNum = changedItem.VisitNum, VisitDay = changedItem.VisitDay, VisitWindowLeft = changedItem.VisitWindowLeft, VisitWindowRight = changedItem.VisitWindowRight }); } var subjectsids = _repository.GetQueryable().Where(x => x.TrialId == trialId).Select(x => new { x.Code, x.SiteId, x.Id, x.IsEnrollment, x.IsUrgent }); List subjectVisits = new List(); addvisitStages.ForEach(x => { subjectsids.ForEach(y => { var guid = new Guid(); // 新增受试者 datas.Add(new DataInspection() { BlindName = x.BlindName, IsSign = false, SiteId = y.SiteId, SubjectId = y.Id, SubjectVisitId = guid, CreateTime = createtime.AddMilliseconds(200), SubjectVisitName = x.VisitName, TrialId = x.TrialId, Identification = "Add|Visit|Info|Visit-Image Upload", JsonDetail = JsonConvert.SerializeObject(new { IsBaseLine = x.IsBaseLine, VisitName = x.VisitName, VisitNum = x.VisitNum, VisitDay = x.VisitDay, VisitExecuted=false, BlindName=x.BlindName, VisitWindowLeft = x.VisitWindowLeft, VisitWindowRight = x.VisitWindowRight, IsEnrollment=y.IsEnrollment, IsUrgent=y.IsUrgent, }), }); // 初始化受试者 datas.Add(new DataInspection() { SiteId = y.SiteId, SubjectId = y.Id, SubjectVisitId = guid, TrialId = x.TrialId, SubjectCode = y.Code, BlindName = x.BlindName, SubjectVisitName = x.VisitName, IsSign = false, CreateTime = createtime.AddMilliseconds(500), Identification = "Init|Visit|Status|Visit-Image Upload", JsonDetail = JsonConvert.SerializeObject(new { BlindName = x.BlindName, VisitName = x.VisitName, SubmitState = "", AuditState = "", IsBaseLine = x.IsBaseLine, IsEnrollment = y.IsEnrollment, IsUrgent = y.IsUrgent, }) }); subjectVisits.Add(new SubjectVisit() { SiteId = y.SiteId, SubjectId = y.Id, Id = guid, BlindName=x.BlindName, IsBaseLine=x.IsBaseLine, IsCheckBack=x.IsBaseLine, IsUrgent=y.IsUrgent, }); }); }); await _inspectionService.AddListInspectionRecordAsync(datas); await _repository.AddAsync(stat); await _repository.AddRangeAsync(subjectVisits); await _repository.SaveChangesAsync(); return ResponseOutput.Ok(); } [HttpGet("{trialId:guid}")] public async Task> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository _influnceStatRepository) { var list = await _influnceStatRepository.Where(t => t.TrialId == trialId).ProjectTo(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToListAsync(); return list; } [HttpGet("{visitPlanInfluenceStatId:guid}")] public async Task DownloadInflunceStudyList(Guid visitPlanInfluenceStatId) { var list = _influnceRepository.Where(t => t.VisitPlanInfluenceStatId == visitPlanInfluenceStatId) .ProjectTo(_mapper.ConfigurationProvider).ToList(); IExporter exporter = new ExcelExporter(); var result = await exporter.ExportAsByteArray(list); return new XlsxFileResult(bytes: result, fileDownloadName: $"检查导出_{DateTime.Now.ToString("yyyy-MM-dd:hh:mm:ss")}.xlsx"); } } }