Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -46,7 +46,7 @@ public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, ISt
|
||||
else
|
||||
{
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message)
|
||||
: (exception.InnerException?.Message )), ApiResponseCodeEnum.ProgramException));
|
||||
: (exception.Message + "Inner ExceptionMsg:" + exception.InnerException?.Message)), ApiResponseCodeEnum.ProgramException));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,9 @@ namespace IRaCIS.Core.Application.Helper
|
||||
// 重置流位置
|
||||
memoryStream.Position = 0;
|
||||
|
||||
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
|
||||
var relativePath= await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", true);
|
||||
|
||||
dic.Add("DICOMDIR" , relativePath.Split('/').Last());
|
||||
}
|
||||
|
||||
//清理临时文件
|
||||
|
||||
@@ -143,9 +143,8 @@ public enum ObjectStoreUse
|
||||
|
||||
public interface IOSSService
|
||||
{
|
||||
public void SetImmediateArchiveRule(string prefix,
|
||||
StorageClass targetStorageClass,
|
||||
string ruleId = "immediate-archive");
|
||||
public Task SetImmediateArchiveRule(string prefix, string ruleId = "immediate-archive", bool isDelete = false);
|
||||
public Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100);
|
||||
|
||||
|
||||
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
||||
@@ -161,7 +160,7 @@ public interface IOSSService
|
||||
|
||||
public Task DeleteFromPrefix(string prefix, bool isCache = false);
|
||||
|
||||
public Task DeleteObjects(List<string> objectKeys);
|
||||
public Task DeleteObjects(List<string> objectKeys, bool isCache = false);
|
||||
|
||||
List<string> GetRootFolderNames();
|
||||
|
||||
@@ -190,183 +189,517 @@ public class OSSService : IOSSService
|
||||
|
||||
/// <summary>
|
||||
/// 将指定前缀下的所有现有文件立即转为目标存储类型
|
||||
/// 核心:Days = 0 表示对所有存量文件立即生效
|
||||
/// </summary>
|
||||
/// <param name="prefix">要转换的文件前缀,如 "project-a/logs/"</param>
|
||||
/// <param name="targetStorageClass">目标存储类型</param>
|
||||
/// <param name="ruleId">规则ID,默认为"immediate-archive"</param>
|
||||
public void SetImmediateArchiveRule(string prefix,
|
||||
StorageClass targetStorageClass,
|
||||
string ruleId = "immediate-archive")
|
||||
/// <param name="isDelete">默认是添加/更新 </param>
|
||||
public async Task SetImmediateArchiveRule(string prefix, string ruleId = "immediate-archive", bool isDelete = false)
|
||||
{
|
||||
|
||||
BackBatchGetToken();
|
||||
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
try
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
// 1. 先获取现有的所有生命周期规则(避免覆盖)
|
||||
var existingRules = new List<Aliyun.OSS.LifecycleRule>();
|
||||
|
||||
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
try
|
||||
{
|
||||
var existingRuleList = _ossClient.GetBucketLifecycle(aliConfig.BucketName);
|
||||
if (existingRuleList != null)
|
||||
// 1. 先获取现有的所有生命周期规则(避免覆盖)
|
||||
var existingRules = new List<Aliyun.OSS.LifecycleRule>();
|
||||
try
|
||||
{
|
||||
existingRules.AddRange(existingRuleList);
|
||||
Console.WriteLine($"找到 {existingRules.Count} 条现有规则");
|
||||
var existingRuleList = _ossClient.GetBucketLifecycle(aliConfig.BucketName);
|
||||
if (existingRuleList != null)
|
||||
{
|
||||
existingRules.AddRange(existingRuleList);
|
||||
Console.WriteLine($"找到 {existingRules.Count} 条现有规则");
|
||||
}
|
||||
}
|
||||
catch (OssException ex) when (ex.ErrorCode == "NoSuchLifecycle")
|
||||
{
|
||||
// 如果没有生命周期规则,继续创建新规则
|
||||
Console.WriteLine("当前Bucket无生命周期规则,将创建新规则");
|
||||
}
|
||||
|
||||
// 2. 创建立即生效的转换规则
|
||||
|
||||
ruleId = $"{ruleId}_{prefix}";
|
||||
var immediateRule = new Aliyun.OSS.LifecycleRule
|
||||
{
|
||||
ID = ruleId,
|
||||
Prefix = prefix,
|
||||
Status = RuleStatus.Enabled,
|
||||
Transitions = new Aliyun.OSS.LifecycleRule.LifeCycleTransition[]
|
||||
{
|
||||
new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
{
|
||||
|
||||
LifeCycleExpiration =
|
||||
{
|
||||
Days = 1
|
||||
},
|
||||
StorageClass = StorageClass.IA
|
||||
},
|
||||
new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
{
|
||||
|
||||
LifeCycleExpiration =
|
||||
{
|
||||
Days = 30 //最后一次修改时间
|
||||
},
|
||||
StorageClass = StorageClass.Archive
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 3. 移除同名的旧规则(如果存在)
|
||||
existingRules.RemoveAll(r => r.ID == ruleId);
|
||||
|
||||
// 4. 添加新规则到规则列表
|
||||
if (isDelete == false)
|
||||
{
|
||||
existingRules.Add(immediateRule);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
var request = new SetBucketLifecycleRequest(aliConfig.BucketName)
|
||||
{
|
||||
LifecycleRules = existingRules
|
||||
};
|
||||
|
||||
|
||||
_ossClient.SetBucketLifecycle(request);
|
||||
|
||||
|
||||
}
|
||||
catch (OssException ex)
|
||||
{
|
||||
Log.Logger.Error($"❌ 设置失败 [错误码: {ex.ErrorCode}] 详细: {ex.Message}");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"❌ 发生未知错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
// 1. 获取现有的生命周期配置(避免覆盖)
|
||||
LifecycleConfiguration existingConfig = null;
|
||||
|
||||
var getRequest = new GetLifecycleConfigurationRequest { BucketName = awsConfig.BucketName };
|
||||
var response = await amazonS3Client.GetLifecycleConfigurationAsync(getRequest);
|
||||
existingConfig = response.Configuration;
|
||||
Console.WriteLine($"找到 {existingConfig?.Rules?.Count ?? 0} 条现有规则");
|
||||
|
||||
// 2. 生成唯一的规则ID
|
||||
ruleId = $"{ruleId}_{prefix.Replace('/', '_').Trim('_')}";
|
||||
|
||||
// 3. 创建新的生命周期规则
|
||||
var immediateRule = new Amazon.S3.Model.LifecycleRule
|
||||
{
|
||||
Id = ruleId,
|
||||
Filter = new LifecycleFilter
|
||||
{
|
||||
// 使用前缀筛选对象
|
||||
LifecycleFilterPredicate = new LifecyclePrefixPredicate { Prefix = prefix }
|
||||
},
|
||||
Status = LifecycleRuleStatus.Enabled,
|
||||
// 定义多个转换阶段
|
||||
Transitions = new List<LifecycleTransition>
|
||||
{
|
||||
// 1天后转为低频访问 (Standard-IA)
|
||||
//new LifecycleTransition
|
||||
//{
|
||||
// Days = 1, //Days' in Transition action must be greater than or equal to 30 for storageClass 'STANDARD_IA'"
|
||||
// StorageClass = S3StorageClass.StandardInfrequentAccess // 对应S3 Standard-IA
|
||||
//},
|
||||
// 30天后转为归档 (Glacier Instant Retrieval)
|
||||
new LifecycleTransition
|
||||
{
|
||||
Days = 30, //创建时间
|
||||
StorageClass = S3StorageClass.GlacierInstantRetrieval // 对应归档(即时检索)
|
||||
}
|
||||
// 如果需要更深的归档,可以继续添加:
|
||||
// new LifecycleTransition { Days = 90, StorageClass = S3StorageClass.GlacierFlexibleRetrieval },
|
||||
// new LifecycleTransition { Days = 180, StorageClass = S3StorageClass.DeepArchive }
|
||||
}
|
||||
// 注意:S3的生命周期规则不支持设置“立即生效(Days=0)”。
|
||||
// 如果要对存量文件立即生效,需要配合其他方法(如批量修改存储类型)。
|
||||
};
|
||||
|
||||
// 4. 更新规则列表(移除同名旧规则,添加新规则)
|
||||
var existingRules = existingConfig.Rules ?? new List<Amazon.S3.Model.LifecycleRule>();
|
||||
existingRules.RemoveAll(r => r.Id == ruleId);
|
||||
|
||||
if (isDelete == false)
|
||||
{
|
||||
existingRules.Add(immediateRule);
|
||||
|
||||
}
|
||||
|
||||
// 5. 提交新的生命周期配置
|
||||
var putRequest = new PutLifecycleConfigurationRequest
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Configuration = new LifecycleConfiguration { Rules = existingRules }
|
||||
};
|
||||
|
||||
await amazonS3Client.PutLifecycleConfigurationAsync(putRequest);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
|
||||
/// 解冻指定前缀下的所有归档/冷归档文件
|
||||
/// </summary>
|
||||
/// <param name="prefix">要解冻的文件前缀</param>
|
||||
/// <param name="restoreDays">解冻后文件保持可读的天数(默认3天)</param>
|
||||
/// <param name="restoreTier">解冻优先级(仅AWS有效)</param>
|
||||
/// <param name="batchSize">批量处理大小(默认100)</param>
|
||||
public async Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
var client = new OssClient(
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
|
||||
AliyunOSSTempToken.AccessKeyId,
|
||||
AliyunOSSTempToken.AccessKeySecret,
|
||||
AliyunOSSTempToken.SecurityToken
|
||||
);
|
||||
|
||||
var bucketName = aliConfig.BucketName;
|
||||
int totalRestored = 0;
|
||||
int totalSkipped = 0;
|
||||
int totalFailed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"开始解冻阿里云OSS文件,前缀: {prefix}");
|
||||
|
||||
var allObjects = new List<OssObjectSummary>();
|
||||
|
||||
// 1. 分页列举文件
|
||||
string nextMarker = null;
|
||||
ObjectListing result = null;
|
||||
|
||||
do
|
||||
{
|
||||
var listRequest = new Aliyun.OSS.ListObjectsRequest(bucketName)
|
||||
{
|
||||
Prefix = prefix,
|
||||
Marker = nextMarker,
|
||||
MaxKeys = batchSize
|
||||
};
|
||||
|
||||
result = client.ListObjects(listRequest);
|
||||
|
||||
allObjects.AddRange(result.ObjectSummaries);
|
||||
|
||||
|
||||
|
||||
nextMarker = result.NextMarker;
|
||||
|
||||
} while (result.IsTruncated);
|
||||
|
||||
// 2️⃣ 并行解冻(控制并发)
|
||||
Parallel.ForEach(
|
||||
allObjects,
|
||||
new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
|
||||
},
|
||||
obj =>
|
||||
{
|
||||
// 只处理归档
|
||||
if (obj.StorageClass != StorageClass.Archive.ToString())
|
||||
{
|
||||
Interlocked.Increment(ref totalSkipped);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var restoreRequest = new Aliyun.OSS.RestoreObjectRequest(bucketName, obj.Key)
|
||||
{
|
||||
Days = restoreDays
|
||||
};
|
||||
|
||||
client.RestoreObject(restoreRequest);
|
||||
|
||||
Interlocked.Increment(ref totalRestored);
|
||||
Console.WriteLine($"✅ 提交解冻: {obj.Key}");
|
||||
}
|
||||
catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
|
||||
{
|
||||
// 已在解冻中,算成功
|
||||
Interlocked.Increment(ref totalSkipped);
|
||||
Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Interlocked.Increment(ref totalFailed);
|
||||
Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 3. 输出统计结果
|
||||
Console.WriteLine("\n================ 解冻完成 ================");
|
||||
Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");
|
||||
Console.WriteLine($"成功解冻: {totalRestored} 个");
|
||||
Console.WriteLine($"跳过文件: {totalSkipped} 个 (非归档类型)");
|
||||
Console.WriteLine($"解冻失败: {totalFailed} 个");
|
||||
|
||||
if (totalRestored > 0)
|
||||
{
|
||||
Console.WriteLine($"\n📋 解冻说明:");
|
||||
Console.WriteLine($" • 解冻任务已提交,文件将在后台处理");
|
||||
Console.WriteLine($" • 解冻完成后,文件将保持可读状态 {restoreDays} 天");
|
||||
Console.WriteLine($" • 归档文件约需1分钟,冷归档需数小时");
|
||||
}
|
||||
}
|
||||
catch (OssException ex) when (ex.ErrorCode == "NoSuchLifecycle")
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果没有生命周期规则,继续创建新规则
|
||||
Console.WriteLine("当前Bucket无生命周期规则,将创建新规则");
|
||||
Log.Logger.Error($"❌ 阿里云解冻操作失败: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
var credentials = new SessionAWSCredentials(
|
||||
AWSTempToken.AccessKeyId,
|
||||
AWSTempToken.SecretAccessKey,
|
||||
AWSTempToken.SessionToken
|
||||
);
|
||||
|
||||
// 2. 创建立即生效的转换规则
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region),
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
using var client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var bucketName = awsConfig.BucketName;
|
||||
int totalRestored = 0;
|
||||
int totalSkipped = 0;
|
||||
int totalFailed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"开始解冻AWS S3文件,前缀: {prefix}");
|
||||
|
||||
var allObjects = new List<S3Object>();
|
||||
|
||||
// 1. 分页列举文件
|
||||
string continuationToken = null;
|
||||
ListObjectsV2Response response = null;
|
||||
|
||||
do
|
||||
{
|
||||
var listRequest = new ListObjectsV2Request
|
||||
{
|
||||
BucketName = bucketName,
|
||||
Prefix = prefix,
|
||||
ContinuationToken = continuationToken,
|
||||
MaxKeys = batchSize
|
||||
};
|
||||
|
||||
response = await client.ListObjectsV2Async(listRequest);
|
||||
|
||||
allObjects.AddRange(response.S3Objects);
|
||||
|
||||
|
||||
continuationToken = response.NextContinuationToken;
|
||||
|
||||
} while (response.IsTruncated == true);
|
||||
|
||||
// 2️⃣ 并行解冻(控制并发)
|
||||
await Parallel.ForEachAsync(
|
||||
allObjects,
|
||||
new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
|
||||
},
|
||||
async (obj, ct) =>
|
||||
{
|
||||
// 只处理归档
|
||||
if (obj.StorageClass != S3StorageClass.Glacier)
|
||||
{
|
||||
Interlocked.Increment(ref totalSkipped);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var restoreRequest = new Amazon.S3.Model.RestoreObjectRequest
|
||||
{
|
||||
BucketName = bucketName,
|
||||
Key = obj.Key,
|
||||
Days = restoreDays,
|
||||
|
||||
};
|
||||
|
||||
await client.RestoreObjectAsync(restoreRequest);
|
||||
|
||||
Interlocked.Increment(ref totalRestored);
|
||||
Console.WriteLine($"✅ 提交解冻: {obj.Key}");
|
||||
}
|
||||
catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
|
||||
{
|
||||
// 已在解冻中,算成功
|
||||
Interlocked.Increment(ref totalSkipped);
|
||||
Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Interlocked.Increment(ref totalFailed);
|
||||
Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 3. 输出统计结果
|
||||
Console.WriteLine("\n================ 解冻完成 ================");
|
||||
Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");
|
||||
Console.WriteLine($"成功解冻: {totalRestored} 个");
|
||||
Console.WriteLine($"跳过文件: {totalSkipped} 个 (非归档类型)");
|
||||
Console.WriteLine($"解冻失败: {totalFailed} 个");
|
||||
|
||||
if (totalRestored > 0)
|
||||
{
|
||||
Console.WriteLine($"\n📋 AWS解冻说明:");
|
||||
Console.WriteLine($" • 解冻任务已提交到Glacier服务");
|
||||
Console.WriteLine($" • 标准解冻: 3-5小时 (Glacier Flexible Retrieval)");
|
||||
Console.WriteLine($" • 加急解冻: 1-5分钟 (额外收费)");
|
||||
Console.WriteLine($" • 解冻后文件可读 {restoreDays} 天");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"❌ AWS解冻操作失败: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 坑方法,会清空之前的规则
|
||||
/// </summary>
|
||||
/// <param name="prefix"></param>
|
||||
/// <param name="ruleId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task SetLifecycle(string prefix, string ruleId = "immediate-archive")
|
||||
{
|
||||
BackBatchGetToken();
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
ruleId = $"{ruleId}_{prefix}";
|
||||
var immediateRule = new Aliyun.OSS.LifecycleRule
|
||||
var rule = new Aliyun.OSS.LifecycleRule
|
||||
{
|
||||
ID = ruleId,
|
||||
Prefix = prefix,
|
||||
Status = RuleStatus.Enabled,
|
||||
Transitions = new Aliyun.OSS.LifecycleRule.LifeCycleTransition[]
|
||||
{
|
||||
{
|
||||
new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
{
|
||||
|
||||
|
||||
LifeCycleExpiration =
|
||||
{
|
||||
Days = 1
|
||||
},
|
||||
StorageClass = targetStorageClass
|
||||
StorageClass = StorageClass.IA
|
||||
},
|
||||
new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
{
|
||||
|
||||
LifeCycleExpiration =
|
||||
{
|
||||
Days = 30
|
||||
},
|
||||
StorageClass = StorageClass.Archive
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 3. 移除同名的旧规则(如果存在)
|
||||
existingRules.RemoveAll(r => r.ID == ruleId);
|
||||
|
||||
// 4. 添加新规则到规则列表
|
||||
existingRules.Add(immediateRule);
|
||||
|
||||
|
||||
var request = new SetBucketLifecycleRequest(aliConfig.BucketName)
|
||||
{
|
||||
LifecycleRules= existingRules
|
||||
};
|
||||
|
||||
//会清空之前历史的规则,不能用。。。
|
||||
var request = new SetBucketLifecycleRequest(aliConfig.BucketName);
|
||||
request.AddLifecycleRule(rule);
|
||||
|
||||
_ossClient.SetBucketLifecycle(request);
|
||||
|
||||
Console.WriteLine("✅ 立即归档规则设置成功!");
|
||||
Console.WriteLine($" 规则ID: {ruleId}");
|
||||
Console.WriteLine($" 前缀: {prefix}");
|
||||
Console.WriteLine($" 目标存储类型: {targetStorageClass}");
|
||||
Console.WriteLine($" 生效时间: 将在下次生命周期扫描时生效(通常24小时内)");
|
||||
}
|
||||
catch (OssException ex)
|
||||
{
|
||||
Console.WriteLine($"❌ 设置失败 [错误码: {ex.ErrorCode}]");
|
||||
Console.WriteLine($" 详细: {ex.Message}");
|
||||
|
||||
// 处理特定错误
|
||||
if (ex.ErrorCode == "InvalidArgument")
|
||||
{
|
||||
Console.WriteLine(" 可能原因:存储类型不支持或参数格式错误");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
Console.WriteLine($"❌ 发生未知错误: {ex.Message}");
|
||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public async Task SetLifecycle(string lifecycle)
|
||||
//{
|
||||
|
||||
|
||||
// if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
// {
|
||||
// var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
// var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
|
||||
// var rule = new Aliyun.OSS.LifecycleRule
|
||||
// {
|
||||
// ID = "ArchiveOldFiles",
|
||||
// Prefix = "", // 全 bucket 生效
|
||||
// Status = RuleStatus.Enabled
|
||||
// };
|
||||
|
||||
// // 30 天转低频
|
||||
// rule.Transitions.Add(new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
// {
|
||||
// Days = 30,
|
||||
// StorageClass = StorageClass.IA
|
||||
// });
|
||||
|
||||
// // 180 天转归档
|
||||
// rule.Transitions.Add(new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
// {
|
||||
// Days = 180,
|
||||
// StorageClass = StorageClass.Archive
|
||||
// });
|
||||
|
||||
// // 365 天转冷归档
|
||||
// rule.Transitions.Add(new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
// {
|
||||
// Days = 365,
|
||||
// StorageClass = StorageClass.ColdArchive
|
||||
// });
|
||||
|
||||
// // 730 天转深度归档
|
||||
// rule.Transitions.Add(new Aliyun.OSS.LifecycleRule.LifeCycleTransition
|
||||
// {
|
||||
// Days = 730,
|
||||
// StorageClass = StorageClass.DeepColdArchive
|
||||
// });
|
||||
|
||||
// var request = new SetBucketLifecycleRequest(aliConfig.BucketName);
|
||||
// request.AddLifecycleRule(rule);
|
||||
|
||||
// _ossClient.SetBucketLifecycle(request);
|
||||
|
||||
|
||||
// }
|
||||
// else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
// {
|
||||
// var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
// var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
|
||||
|
||||
// //提供awsEndPoint(域名)进行访问配置
|
||||
// var clientConfig = new AmazonS3Config
|
||||
// {
|
||||
// RegionEndpoint = RegionEndpoint.USEast1,
|
||||
// UseHttp = true,
|
||||
// };
|
||||
|
||||
// var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||
/// </summary>
|
||||
@@ -432,8 +765,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -558,8 +891,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -633,8 +966,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -705,7 +1038,7 @@ public class OSSService : IOSSService
|
||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
|
||||
.WithSSL(minIOConfig.UseSSL)
|
||||
.Build();
|
||||
|
||||
|
||||
var pipe = new System.IO.Pipelines.Pipe();
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
@@ -839,8 +1172,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -1213,8 +1546,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -1228,7 +1561,7 @@ public class OSSService : IOSSService
|
||||
|
||||
var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);
|
||||
|
||||
if (listObjectsResponse.S3Objects.Count > 0)
|
||||
if (listObjectsResponse.S3Objects?.Count > 0)
|
||||
{
|
||||
// 准备删除请求
|
||||
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
|
||||
@@ -1258,7 +1591,7 @@ public class OSSService : IOSSService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteObjects(List<string> objectKeys)
|
||||
public async Task DeleteObjects(List<string> objectKeys, bool isCache = false)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
@@ -1268,9 +1601,23 @@ public class OSSService : IOSSService
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
var bucketName = string.Empty;
|
||||
|
||||
if (isCache)
|
||||
{
|
||||
Uri uri = new Uri(aliConfig.ViewEndpoint);
|
||||
string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
|
||||
string[] parts = host.Split('.');
|
||||
bucketName = parts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
bucketName = aliConfig.BucketName;
|
||||
}
|
||||
|
||||
if (objectKeys.Count > 0)
|
||||
{
|
||||
var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, objectKeys, false));
|
||||
var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, objectKeys, false));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1306,8 +1653,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
@@ -1381,8 +1728,8 @@ public class OSSService : IOSSService
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
||||
//,UseHttp = true,
|
||||
};
|
||||
|
||||
var request = new Amazon.S3.Model.GetObjectMetadataRequest
|
||||
@@ -1466,9 +1813,16 @@ public class OSSService : IOSSService
|
||||
{
|
||||
var awsOptions = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
|
||||
// 创建 STS 客户端(考虑使用 RegionEndpoint)
|
||||
var stsConfig = new AmazonSecurityTokenServiceConfig
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsOptions.Region)
|
||||
};
|
||||
|
||||
//aws 临时凭证
|
||||
// 创建 STS 客户端
|
||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
|
||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey, stsConfig);
|
||||
|
||||
// 使用 AssumeRole 请求临时凭证
|
||||
var assumeRoleRequest = new AssumeRoleRequest
|
||||
|
||||
@@ -15740,14 +15740,23 @@
|
||||
利用DocX 库 处理word国际化模板
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Helper.OSSService.SetImmediateArchiveRule(System.String,Aliyun.OSS.StorageClass,System.String)">
|
||||
<member name="M:IRaCIS.Core.Application.Helper.OSSService.SetImmediateArchiveRule(System.String,System.String,System.Boolean)">
|
||||
<summary>
|
||||
将指定前缀下的所有现有文件立即转为目标存储类型
|
||||
核心:Days = 0 表示对所有存量文件立即生效
|
||||
</summary>
|
||||
<param name="prefix">要转换的文件前缀,如 "project-a/logs/"</param>
|
||||
<param name="targetStorageClass">目标存储类型</param>
|
||||
<param name="ruleId">规则ID,默认为"immediate-archive"</param>
|
||||
<param name="isDelete">默认是添加/更新 </param>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "M:IRaCIS.Core.Application.Helper.OSSService.RestoreFilesByPrefixAsync(System.String,System.Int32,System.Int32)" -->
|
||||
<member name="M:IRaCIS.Core.Application.Helper.OSSService.SetLifecycle(System.String,System.String)">
|
||||
<summary>
|
||||
坑方法,会清空之前的规则
|
||||
</summary>
|
||||
<param name="prefix"></param>
|
||||
<param name="ruleId"></param>
|
||||
<returns></returns>
|
||||
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Helper.OSSService.UploadToOSSAsync(System.IO.Stream,System.String,System.String,System.Boolean)">
|
||||
<summary>
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace IRaCIS.Core.Application.ViewModel
|
||||
public new List<UserTypeEnum> CopyUserTypeList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList();
|
||||
|
||||
public List<CriterionType>? SysCriterionTypeList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +128,7 @@ namespace IRaCIS.Core.Application.ViewModel
|
||||
{
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public Guid TrialReadingCriterionId { get; set; }
|
||||
public CriterionType CriterionType { get; set; }
|
||||
|
||||
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
IsPublish = true,
|
||||
IsDeleted = false,
|
||||
},false,true);
|
||||
}, false, true);
|
||||
await _trialDocumentRepository.SaveChangesAsync();
|
||||
Console.WriteLine("开始 发布项目文档");
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
// 从新作用域解析服务
|
||||
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||
await mediator.Publish(new ImageQCRecurringEvent { TrialId= Guid.Parse("08de2254-5d7d-581a-0242-0a0001000000") });
|
||||
await mediator.Publish(new ImageQCRecurringEvent { TrialId = Guid.Parse("08de2254-5d7d-581a-0242-0a0001000000") });
|
||||
}
|
||||
});
|
||||
return ResponseOutput.Result(true);
|
||||
@@ -171,7 +171,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
.WhereIf(inQuery.UserTypeId != null, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
|
||||
.WhereIf(inQuery.IsPublish != null, t => t.IsPublish == inQuery.IsPublish)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.FileTypeCode), t => t.FileType.Code== inQuery.FileTypeCode)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.FileTypeCode), t => t.FileType.Code == inQuery.FileTypeCode)
|
||||
.ProjectTo<TrialDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, isEn_Us = _userInfo.IsEn_Us });
|
||||
|
||||
return await trialDocumentQueryable.ToPagedListAsync(inQuery);
|
||||
@@ -180,7 +180,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<TrialSignDocView>> GetTrialSignDocumentList(TrialDocQuery inQuery)
|
||||
{
|
||||
var trialDocQueryable = from trialDoc in _trialDocumentRepository.Where(t=>t.IsPublish)
|
||||
var trialDocQueryable = from trialDoc in _trialDocumentRepository.Where(t => t.IsPublish)
|
||||
.WhereIf(inQuery.TrialId != null, t => t.TrialId == inQuery.TrialId)
|
||||
.Where(t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
#region 统一用户修改
|
||||
|
||||
var systemDocQuery =
|
||||
from sysDoc in _systemDocumentRepository.Where(t=>t.IsPublish).Where(t => t.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
from sysDoc in _systemDocumentRepository.Where(t => t.IsPublish).Where(t => t.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
//外部人员 只签署 外部需要签署的
|
||||
.WhereIf(isInternal == false, t => t.DocUserSignType == DocUserSignType.InnerAndOuter)
|
||||
from trialUser in _trialIdentityUserRepository.AsQueryable(false)
|
||||
@@ -392,7 +392,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
|
||||
//项目文档查询
|
||||
var trialDocQuery =
|
||||
from trialDoc in _trialDocumentRepository.Where(t=>t.IsPublish).Where(t => t.TrialId == inQuery.TrialId).Where(t => t.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
from trialDoc in _trialDocumentRepository.Where(t => t.IsPublish).Where(t => t.TrialId == inQuery.TrialId).Where(t => t.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
from trialUser in _trialIdentityUserRepository.AsQueryable(false).Where(t => t.TrialId == inQuery.TrialId && t.IdentityUserId == _userInfo.IdentityUserId
|
||||
&& t.TrialUserRoleList.Any(t => trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == t.UserRole.UserTypeId)))
|
||||
|
||||
@@ -582,7 +582,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
#endregion
|
||||
|
||||
|
||||
var needSignTrialDocCount = await _trialDocumentRepository.AsQueryable(true).Where(t=>t.IsPublish)
|
||||
var needSignTrialDocCount = await _trialDocumentRepository.AsQueryable(true).Where(t => t.IsPublish)
|
||||
.Where(t => t.TrialId == inQuery.TrialId && t.Trial.TrialStatusStr != StaticData.TrialState.TrialStopped)
|
||||
.Where(t => t.Trial.TrialIdentityUserList.Any(t => t.IdentityUserId == _userInfo.IdentityUserId && t.TrialUserRoleList.Any(t => t.UserRole.UserTypeId == _userInfo.UserTypeId)))
|
||||
.Where(t => t.IsDeleted == false && !t.TrialDocConfirmedUserList.Any(t => t.ConfirmUserId == _userInfo.IdentityUserId && t.ConfirmTime != null) && t.NeedConfirmedUserTypeList.Any(u => u.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
@@ -713,7 +713,8 @@ namespace IRaCIS.Core.Application.Services
|
||||
.WhereIf(inQuery.BeginCreateTime != null, t => t.CreateTime >= inQuery.BeginCreateTime)
|
||||
.WhereIf(inQuery.EndCreateTime != null, t => t.CreateTime <= inQuery.EndCreateTime)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.UserName), t => t.UserName.Contains(inQuery.UserName))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted);
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
|
||||
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.EA, t => t.ConfirmTime != null);
|
||||
|
||||
var result = await unionQuery.ToPagedListAsync(inQuery);
|
||||
|
||||
@@ -945,7 +946,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
var isEA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.EA;
|
||||
|
||||
//EA 但是没有在进行的培训记录查看权限,那么返回空数据
|
||||
if (isEA && !_auditRecordRepository.Any(t => t.IsViewTrainingRecord && t.AuditState == AuditState.Ongoing && t.AuditRecordIdentityUserList.Any(c=>c.IdentityUserId==_userInfo.IdentityUserId)))
|
||||
if (isEA && !_auditRecordRepository.Any(t => t.IsViewTrainingRecord && t.AuditState == AuditState.Ongoing && t.AuditRecordIdentityUserList.Any(c => c.IdentityUserId == _userInfo.IdentityUserId)))
|
||||
{
|
||||
return ResponseOutput.Ok(new PageOutput<UnionDocumentWithConfirmInfoView>());
|
||||
}
|
||||
@@ -1113,7 +1114,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
|
||||
_mapper.Map(addOrEditTrialDocument, document);
|
||||
document.UpdateTime = DateTime.Now;
|
||||
|
||||
|
||||
#region 不区分路径了
|
||||
|
||||
//if (document.FileTypeId != addOrEditTrialDocument.FileTypeId)
|
||||
|
||||
@@ -773,10 +773,12 @@ namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
var subjectId = generateEmailCommand.SubjectId;
|
||||
var businessScenarioEnum = generateEmailCommand.BusinessScenarioEnum;
|
||||
var trialReadingCriterionId = generateEmailCommand.TrialReadingCriterionId;
|
||||
var criterionType = generateEmailCommand.CriterionType;
|
||||
|
||||
|
||||
var trialConfig = await _subjectRepository.Where(t => t.Id == subjectId).Select(t => new { t.Trial.IsEnrollementQualificationConfirm, t.Trial.IsPDProgressView }).FirstNotNullAsync();
|
||||
|
||||
var trialConfig = await _subjectRepository.Where(t => t.Id == subjectId).Select(t => new { t.Trial.IsEnrollementQualificationConfirm, t.Trial.IsPDProgressView, t.TrialId }).FirstNotNullAsync();
|
||||
var trialReadingCriterionId = _readingQuestionCriterionTrialRepository.Where(t => t.CriterionType == criterionType && t.TrialId == trialConfig.TrialId).Select(t => t.Id).FirstOrDefault();
|
||||
|
||||
//找到入组确认 或者Pd 进展 已生成任务的 访视
|
||||
var subjectVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId & t.CheckState == CheckStateEnum.CVPassed && (t.IsEnrollmentConfirm == true || t.PDState == PDStateEnum.PDProgress)).ToListAsync();
|
||||
@@ -1671,10 +1673,10 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
||||
{
|
||||
//await SyncSystemEmainCofigDocListAsync(inQuery.TrialId);
|
||||
|
||||
var trialConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.IsEnrollementQualificationConfirm, t.IsPDProgressView }).First();
|
||||
var trialConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.IsEnrollementQualificationConfirm, t.IsPDProgressView, TrialCriterionTypeList = t.TrialReadingCriterionList.Where(t => t.IsSigned).Select(t => t.CriterionType).ToList() }).First();
|
||||
|
||||
var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||
.WhereIf(inQuery.EmailTopic.IsNotNullOrEmpty(), t => t.EmailTopic.Contains(inQuery.EmailTopic)||t.EmailTopicCN.Contains(inQuery.EmailTopic))
|
||||
.WhereIf(inQuery.EmailTopic.IsNotNullOrEmpty(), t => t.EmailTopic.Contains(inQuery.EmailTopic) || t.EmailTopicCN.Contains(inQuery.EmailTopic))
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == false, t => t.IsDistinguishCriteria == false)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == true, t => t.IsDistinguishCriteria == true)
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeList.Any(c => c == inQuery.CriterionTypeEnum))
|
||||
@@ -1692,6 +1694,7 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
||||
var orderQuery = inQuery.Asc ? trialEmailNoticeConfigQueryable.OrderBy(sortField) : trialEmailNoticeConfigQueryable.OrderBy(sortField + " desc");
|
||||
var list = await orderQuery.ToListAsync();
|
||||
|
||||
|
||||
return ResponseOutput.Ok(list, trialConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public string Bodypart { get; set; } = string.Empty;
|
||||
|
||||
public string BodyPartForEditOther { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? StudyTime { get; set; }
|
||||
|
||||
|
||||
|
||||
@@ -1192,7 +1192,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
|
||||
if (isSucess)
|
||||
{
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1632,11 +1632,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
{
|
||||
if (isTaskStudy)
|
||||
{
|
||||
await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new TaskStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new TaskStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" });
|
||||
}
|
||||
else
|
||||
{
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2310,7 +2310,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
|
||||
if (isSucess)
|
||||
{
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic["DICOMDIR"]}" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +382,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
|
||||
Id = t.Id,
|
||||
|
||||
Bodypart = t.BodyPartExamined,
|
||||
Bodypart = t.BodyPartForEdit,
|
||||
BodyPartForEditOther = t.BodyPartForEditOther,
|
||||
|
||||
Modalities = t.Modalities,
|
||||
|
||||
@@ -433,6 +434,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
Id = t.Id,
|
||||
|
||||
Bodypart = t.BodyPart,
|
||||
BodyPartForEditOther=t.BodyPartForEditOther,
|
||||
|
||||
Modalities = t.Modality,
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using IRaCIS.Application.Contracts;
|
||||
using Aliyun.OSS;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
@@ -32,7 +33,7 @@ namespace IRaCIS.Core.Application
|
||||
IRepository<ClinicalDataTrialSet> _clinicalDataTrialSetRepository,
|
||||
IRepository<ReadingCriterionPage> _readingCriterionPageRepository,
|
||||
IRepository<SystemCriterionKeyFile> _systemCriterionKeyFileRepository,
|
||||
IOSSService oSSService,
|
||||
IOSSService _oSSService,
|
||||
IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
|
||||
IOrganInfoService _iOrganInfoService,
|
||||
IRepository<TrialBodyPart> _trialBodyPartRepository,
|
||||
@@ -331,22 +332,22 @@ namespace IRaCIS.Core.Application
|
||||
public async Task SynchronizeKeyFile(Guid TrialReadingCriterionId)
|
||||
{
|
||||
var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == TrialReadingCriterionId).AsNoTracking().FirstOrDefaultAsync();
|
||||
if (trialCriterion != null && trialCriterion.ReadingQuestionCriterionSystemId!=null)
|
||||
if (trialCriterion != null && trialCriterion.ReadingQuestionCriterionSystemId != null)
|
||||
{
|
||||
var systemCriterionKeyFile = await _systemCriterionKeyFileRepository.Where(x => x.SystemCriterionId == trialCriterion.ReadingQuestionCriterionSystemId).ToListAsync();
|
||||
|
||||
List<TrialCriterionKeyFile> trialCriterionKeyFiles= new List<TrialCriterionKeyFile>();
|
||||
List<TrialCriterionKeyFile> trialCriterionKeyFiles = new List<TrialCriterionKeyFile>();
|
||||
|
||||
foreach (var item in systemCriterionKeyFile)
|
||||
foreach (var item in systemCriterionKeyFile)
|
||||
{
|
||||
|
||||
var path= await oSSService.UploadToOSSAsync(item.FilePath, $"{trialCriterion.TrialId}/ReadingModule/{trialCriterion.CriterionName}", true,true);
|
||||
var path = await _oSSService.UploadToOSSAsync(item.FilePath, $"{trialCriterion.TrialId}/ReadingModule/{trialCriterion.CriterionName}", true, true);
|
||||
|
||||
trialCriterionKeyFiles.Add(new TrialCriterionKeyFile
|
||||
{
|
||||
TrialCriterionId= TrialReadingCriterionId,
|
||||
FileName= item.FileName,
|
||||
FilePath= path
|
||||
TrialCriterionId = TrialReadingCriterionId,
|
||||
FileName = item.FileName,
|
||||
FilePath = path
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1325,6 +1326,18 @@ namespace IRaCIS.Core.Application
|
||||
|
||||
await _trialRepository.BatchUpdateNoTrackingAsync(u => u.Id == trialId, s => new Trial { TrialFinishedTime = DateTime.Now });
|
||||
|
||||
|
||||
if (_readingQuestionCriterionTrialRepository.Any(t => t.IsSigned && t.ImageUploadEnum != ReadingImageUpload.None))
|
||||
{
|
||||
await _oSSService.SetImmediateArchiveRule($"{trial.Id}/Image/");
|
||||
await _oSSService.SetImmediateArchiveRule($"{trial.Id}/TaskImage/");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
await _oSSService.SetImmediateArchiveRule($"{trial.Id}/Image/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await _fusionCache.SetAsync(CacheKeys.Trial(trial.Id.ToString()), trialStatusStr, TimeSpan.FromDays(7));
|
||||
@@ -1546,7 +1559,7 @@ namespace IRaCIS.Core.Application
|
||||
[AllowAnonymous]
|
||||
public async Task<TrialConfigInfo> GetTrialExtralConfig(Guid trialId)
|
||||
{
|
||||
var extralObj = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.TrialExtraConfigJsonStr,t.IsExternalViewTrialChart, t.TrialObjectNameList, t.CollectImagesEnum, t.IsIQCAutoNextTask }).FirstOrDefault();
|
||||
var extralObj = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.TrialExtraConfigJsonStr, t.IsExternalViewTrialChart, t.TrialObjectNameList, t.CollectImagesEnum, t.IsIQCAutoNextTask }).FirstOrDefault();
|
||||
|
||||
var extralConfig = JsonConvert.DeserializeObject<TrialExtraConfig>(extralObj?.TrialExtraConfigJsonStr) ?? new TrialExtraConfig();
|
||||
|
||||
|
||||
@@ -338,6 +338,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
trial.DeclarationTypes = $"|{string.Join('|', updateModel.DeclarationTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
|
||||
trial.AttendedReviewerTypes = $"|{string.Join('|', updateModel.AttendedReviewerTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
|
||||
|
||||
trial.EmailFromName = $"{_systemEmailConfig.FromName}-{trial.TrialCode}";
|
||||
trial.UpdateTime = DateTime.Now;
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using IRaCIS.Core.Domain;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infra.EFCore.Context;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.Encryption;
|
||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
||||
@@ -75,12 +76,45 @@ namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
public static int IntValue = 100;
|
||||
|
||||
|
||||
[AllowAnonymous]
|
||||
|
||||
public async Task<IResponseOutput> CreatNewDBStruct()
|
||||
{
|
||||
var factory = new IRaCISDBContextFactory();
|
||||
|
||||
using var db = factory.CreateDbContext(Array.Empty<string>());
|
||||
|
||||
// ⚠️ 临时用,确认是测试库
|
||||
// db.Database.EnsureDeleted();
|
||||
|
||||
db.Database.EnsureCreated();
|
||||
|
||||
Console.WriteLine("数据库结构已创建完成");
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
|
||||
public async Task<IResponseOutput> DeleteCacheDIR()
|
||||
{
|
||||
var list= _dicomStudyRepository.Where(t => t.StudyDIRPath!="").Select(t => t.StudyDIRPath).ToList();
|
||||
|
||||
|
||||
await _IOSSService.DeleteObjects(list.Select(t => t.TrimStart('/')).ToList(),true);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput> TestOSS(StorageClass storageClass)
|
||||
{
|
||||
if (storageClass == StorageClass.IA || storageClass == StorageClass.Archive || storageClass == StorageClass.ColdArchive || storageClass == StorageClass.DeepColdArchive)
|
||||
{
|
||||
_IOSSService.SetImmediateArchiveRule($"Test-Archive/Archive{(int)storageClass}", storageClass);
|
||||
await _IOSSService.SetImmediateArchiveRule($"Test-Archive/Archive{(int)storageClass}/");
|
||||
|
||||
//await _IOSSService.RestoreFilesByPrefixAsync($"Test-Archive/Archive{(int)storageClass}/");
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user