468 lines
19 KiB
468 lines
19 KiB
using BrilliantSightClient.Model.Entity.ApiEntity; |
|
using BrilliantSightClient.Model.Extension; |
|
using BrilliantSightClient.Model.GradeLevel.Entity; |
|
using BrilliantSightClient.Model.GradeLevel.Entity.DatabaseEntity; |
|
using BrilliantSightClient.Model.GradeLevel.Entity.Enum; |
|
using BrilliantSightClient.Model.GradeLevel.Exceptions; |
|
using BrilliantSightClient.Model.GradeLevel.Helper; |
|
using BrilliantSightClient.Model.GradeResult.Entity; |
|
using BrilliantSightClient.Model.GradeResult.Entity.Enums; |
|
using BrilliantSightClient.Model.Helper; |
|
using Newtonsoft.Json; |
|
using Newtonsoft.Json.Linq; |
|
|
|
namespace BrilliantSightClient.Model.GradeLevel; |
|
|
|
public class GradeLevelCalculator |
|
{ |
|
AlgorithmResultEntity _diamondResult; |
|
|
|
public bool IsInitialized = false; |
|
|
|
private JToken _diamondData; |
|
GradeLevelMst _masterLevel; |
|
|
|
private List<GradeLevelSet> _gradeLevelCutSets; |
|
private List<GradeLevelSet> _gradeLevelSymSets; |
|
|
|
public List<GradeLevelSet> GradeLevelCutSets |
|
{ |
|
get => _gradeLevelCutSets; |
|
} |
|
|
|
public List<GradeLevelSet> GradeLevelSymSets |
|
{ |
|
get => _gradeLevelSymSets; |
|
} |
|
|
|
private bool CutIsMultiDimensional = false; |
|
private string CutMultiDimensionalSign = string.Empty; |
|
private bool SymIsMultiDimensional = false; |
|
private string SymMultiDimensionalSign = string.Empty; |
|
|
|
private List<GradeLevelDataSet> _gradeLevelDataSets; |
|
|
|
private List<GradeLevelTreeSet> _gradeLevelCutTreeSets; |
|
private List<GradeLevelTreeSet> _gradeLevelSymTreeSets; |
|
|
|
private List<GradeLevelSetDtl> _gradeLevelSetDtls; |
|
|
|
private GradeLevelTotalSet _gradeLevelCutTotalSet; |
|
private GradeLevelTotalSet _gradeLevelSymTotalSet; |
|
|
|
|
|
public GradeLevelCalculator(AlgorithmResultEntity entity) |
|
{ |
|
_diamondResult = entity; |
|
_diamondData = JToken.Parse(JsonConvert.SerializeObject(entity.Measurements)); |
|
var masterSql = $"select * from GRADE_LEVEL_MST where NAME = '{entity.Standard}' and (RUNMODE = {Common.RunMode} or RUNMODE = -1) and SHAPE = {EntityHelper.GetValueFromName<DiamondShape>(entity.Shape)} and CROWN = '{entity.CrownType.Replace("P","")}' and PAVILION = '{entity.PavType.Replace("P","")}'" ; |
|
var masterLevel = DataBaseHelper.ExecuteQuery<GradeLevelMst>(masterSql); |
|
if (masterLevel.Count == 0) |
|
return; |
|
|
|
_masterLevel = masterLevel.First(); |
|
|
|
var setsSql = $"select * from GRADE_LEVEL_SET where MST_SIGN = '{_masterLevel.Sign}'"; |
|
var levelSets = DataBaseHelper.ExecuteQuery<GradeLevelSet>(setsSql); |
|
if (levelSets.Count == 0) |
|
return; |
|
_gradeLevelCutSets = levelSets.FindAll(x => x.Set_Type == GradeType.Cut.GetValue()); |
|
_gradeLevelSymSets = levelSets.FindAll(x => x.Set_Type == GradeType.Sym.GetValue()); |
|
|
|
var dataSetSql = $"select * from GRADE_LEVEL_DATA_SET where MST_SIGN = '{_masterLevel.Sign}'"; |
|
_gradeLevelDataSets = DataBaseHelper.ExecuteQuery<GradeLevelDataSet>(dataSetSql); |
|
|
|
var treeSetSql = $"select * from GRADE_LEVEL_TREE_SET where MST_SIGN = '{_masterLevel.Sign}'"; |
|
var treeSets = DataBaseHelper.ExecuteQuery<GradeLevelTreeSet>(treeSetSql); |
|
_gradeLevelCutTreeSets = treeSets.FindAll(x => x.NodeType - 1 == GradeType.Cut.GetValue()); |
|
_gradeLevelSymTreeSets = treeSets.FindAll(x => x.NodeType - 1 == GradeType.Sym.GetValue()); |
|
CutIsMultiDimensional = _gradeLevelCutTreeSets.Count() > 1; |
|
SymIsMultiDimensional = _gradeLevelSymTreeSets.Count() > 1; |
|
|
|
var setDtlSql = $"select * from GRADE_LEVEL_SET_DTL where MST_SIGN = '{_masterLevel.Sign}'"; |
|
_gradeLevelSetDtls = DataBaseHelper.ExecuteQuery<GradeLevelSetDtl>(setDtlSql); |
|
|
|
var totalSetSql = $"select * from GRADE_LEVEL_TOTAL_SET where MST_SIGN = '{_masterLevel.Sign}'"; |
|
var totalSets = DataBaseHelper.ExecuteQuery<GradeLevelTotalSet>(totalSetSql); |
|
_gradeLevelCutTotalSet = totalSets.FindAll(x => x.Set_Type == GradeType.Cut.GetValue()).First(); |
|
_gradeLevelSymTotalSet = totalSets.FindAll(x => x.Set_Type == GradeType.Sym.GetValue()).First(); |
|
IsInitialized = true; |
|
} |
|
|
|
public GradeLevelSet? GetCutGradeLevelSet(string key, DataInfo dataInfo) |
|
{ |
|
if (IsInitialized == false) return null; |
|
if("GIRDLE_VALLEY".Equals(key))key = "GIRDLE"; |
|
GradeLevelDataSet? dataSet = _gradeLevelDataSets.FirstOrDefault(x => x.KName.Equals(key)); |
|
if (dataSet == null) return null; |
|
//检查是否多维度 |
|
if (CutIsMultiDimensional) |
|
{ |
|
//多维度 |
|
List<GradeLevelTreeSet> cutTree = _gradeLevelCutTreeSets.FindAll(x => x.IsTop == 0); |
|
if(cutTree.Count <= 0) return null; |
|
GradeLevelDataSet? dimensionKey = _gradeLevelDataSets.FirstOrDefault(x => cutTree.First().DimensionSign == x.Sign); |
|
if (dimensionKey == null) return null; |
|
CutMultiDimensionalSign = string.IsNullOrWhiteSpace(CutMultiDimensionalSign)?DimensionTreeSign(dimensionKey, cutTree):CutMultiDimensionalSign; |
|
if ("1".Equals(CutMultiDimensionalSign) || "-1".Equals(CutMultiDimensionalSign)) |
|
{ |
|
return _gradeLevelCutSets.OrderByDescending(set => set.Short).FirstOrDefault(); |
|
} |
|
|
|
return GetFinalCutGrade(CutMultiDimensionalSign, key, dataInfo); |
|
} |
|
else |
|
{ |
|
//单维度 |
|
return GetFinalCutGrade(_gradeLevelCutTreeSets.First().Sign, key, dataInfo); |
|
} |
|
|
|
} |
|
|
|
public GradeLevelSet? GetCutTotalGradeLevelSet(List<DataInfo> dataInfos) |
|
{ |
|
if (IsInitialized == false) return null; |
|
return CalculateTotalGrade(dataInfos, _gradeLevelCutTotalSet, _gradeLevelCutSets); |
|
} |
|
|
|
public GradeLevelSet? GetSymGradeLevelSet(string key, DataInfo dataInfo) |
|
{ |
|
if (IsInitialized == false) return null; |
|
if("GIRDLE_VALLEY".Equals(key))key = "GIRDLE"; |
|
GradeLevelDataSet? dataSet = _gradeLevelDataSets.FirstOrDefault(x => x.KName.Equals(key)); |
|
if (dataSet == null) return null; |
|
double value = string.IsNullOrWhiteSpace(dataInfo.Dev) ? dataInfo.Avg.ToDouble() : dataInfo.Dev.ToDouble(); |
|
// 检查是否多维度 |
|
if (SymIsMultiDimensional) |
|
{ |
|
// 多维度 |
|
List<GradeLevelTreeSet> symTree = _gradeLevelSymTreeSets.FindAll(x => x.IsTop == 0); |
|
if (symTree.Count <= 0) return null; |
|
|
|
GradeLevelDataSet? dimensionKey = _gradeLevelDataSets.FirstOrDefault(x => symTree.First().DimensionSign == x.Sign); |
|
if (dimensionKey == null) return null; |
|
|
|
SymMultiDimensionalSign = string.IsNullOrWhiteSpace(SymMultiDimensionalSign)?DimensionTreeSign(dimensionKey, symTree):SymMultiDimensionalSign; |
|
if ("1".Equals(SymMultiDimensionalSign) || "-1".Equals(SymMultiDimensionalSign)) |
|
{ |
|
return _gradeLevelSymSets.OrderByDescending(set => set.Short).FirstOrDefault(); |
|
} |
|
|
|
return GetFinalSymGrade(SymMultiDimensionalSign, key, value); |
|
} |
|
else |
|
{ |
|
// 单维度 |
|
return GetFinalSymGrade(_gradeLevelSymTreeSets.First().Sign, key, value); |
|
} |
|
|
|
} |
|
|
|
public GradeLevelSet GetSymTotalGradeLevelSet(List<DataInfo> dataInfos) |
|
{ |
|
if (IsInitialized == false) return null; |
|
return CalculateTotalGrade(dataInfos, _gradeLevelSymTotalSet, _gradeLevelSymSets); |
|
} |
|
|
|
private string DimensionTreeSign(GradeLevelDataSet dimensionKey, List<GradeLevelTreeSet> cutTree) |
|
{ |
|
string dimensionTreeSign = string.Empty; |
|
try |
|
{ |
|
// 从JToken中获取对应路径的值 |
|
JToken? dimensionValueToken = _diamondData.SelectToken(dimensionKey.KName); |
|
if (dimensionValueToken == null) |
|
return string.Empty; |
|
|
|
// 转换为double并进行计算 |
|
if (double.TryParse(dimensionValueToken.ToString(), out double dimensionValue)) |
|
{ |
|
// 乘以100并四舍五入取整 |
|
int roundedValue = (int)Math.Round(dimensionValue*100, MidpointRounding.AwayFromZero); |
|
|
|
// 循环查找有效树 |
|
int currentRoundedValue = roundedValue; |
|
while (true) |
|
{ |
|
// 获取所有维度值并排序 |
|
var dimensionValues = cutTree |
|
.Where(x => !string.IsNullOrEmpty(x.DimensionValue)) |
|
.Select(x => |
|
{ |
|
if (int.TryParse(x.DimensionValue, out int value)) |
|
return new { Value = value, Sign = x.Sign }; |
|
return null; |
|
}) |
|
.Where(x => x != null) |
|
.OrderBy(x => x.Value) |
|
.ToList(); |
|
|
|
if (!dimensionValues.Any()) break; // 无维度值时退出 |
|
|
|
// 判断当前roundedValue对应的树 |
|
var matchedDimension = dimensionValues.FirstOrDefault(x => x.Value == currentRoundedValue); |
|
if (matchedDimension != null) |
|
{ |
|
dimensionTreeSign = matchedDimension.Sign; |
|
|
|
// 检查当前树是否有有效定级配置 |
|
if (HasValidGradeConfig(dimensionTreeSign)) |
|
{ |
|
return dimensionTreeSign; |
|
} |
|
} |
|
else if (currentRoundedValue > dimensionValues.Max(x => x.Value)) |
|
{ |
|
dimensionTreeSign = "1"; |
|
if (HasValidGradeConfig(dimensionTreeSign)) |
|
{ |
|
return dimensionTreeSign; |
|
} |
|
break; // 最大树无效时不再查找 |
|
} |
|
else if (currentRoundedValue < dimensionValues.Min(x => x.Value)) |
|
{ |
|
dimensionTreeSign = "-1"; |
|
if (HasValidGradeConfig(dimensionTreeSign)) |
|
{ |
|
return dimensionTreeSign; |
|
} |
|
break; // 最小树无效时不再查找 |
|
} |
|
|
|
// 未找到有效树时,尝试下一个树(DimensionValue+1) |
|
currentRoundedValue++; |
|
if (currentRoundedValue > dimensionValues.Max(x => x.Value)) |
|
{ |
|
break; // 超出最大维度值时退出 |
|
} |
|
} |
|
} |
|
} |
|
catch |
|
{ |
|
// 处理异常,返回空白 |
|
dimensionTreeSign = string.Empty; |
|
} |
|
|
|
return dimensionTreeSign; |
|
} |
|
|
|
// 检查树是否有有效定级配置 |
|
private bool HasValidGradeConfig(string treeSign) |
|
{ |
|
var validConfigs = _gradeLevelSetDtls |
|
.Where(dtl => dtl.Tree_Sign == treeSign) |
|
.Where(dtl => |
|
!(dtl.Max_Value == double.MaxValue && dtl.Min_Value == double.MinValue) && |
|
!(dtl.Max_Value == 0 && dtl.Min_Value == 0) |
|
) |
|
.ToList(); |
|
|
|
return validConfigs.Any(); |
|
} |
|
|
|
public GradeLevelSet? GetFinalCutGrade(string treeSign, string key, DataInfo dataInfo) |
|
{ |
|
if (IsInitialized == false) return null; |
|
// 通过TreeSign和Key关联获取子集 |
|
var dataSet = _gradeLevelDataSets.FirstOrDefault(ds => ds.KName == key); |
|
if (dataSet == null) return null; |
|
|
|
var filteredDtls = _gradeLevelSetDtls |
|
.Where(dtl => dtl.Tree_Sign == treeSign && dtl.DataSet_Sign == dataSet.Sign) |
|
.ToList(); |
|
|
|
if (!filteredDtls.Any()) return null; |
|
|
|
// 查找最大值和最小值对应的区间 |
|
List<GradeLevelSetDtl> maxValDtls = new List<GradeLevelSetDtl>(); |
|
List<GradeLevelSetDtl> minValDtls = new List<GradeLevelSetDtl>(); |
|
if (dataInfo.Max.ToDouble() == 0 && dataInfo.Min.ToDouble() == 0) |
|
{ |
|
maxValDtls = filteredDtls |
|
.Where(dtl => dataInfo.Avg.ToDouble() >= dtl.Min_Value && dataInfo.Avg.ToDouble() <= dtl.Max_Value) |
|
.ToList(); |
|
minValDtls = filteredDtls |
|
.Where(dtl => dataInfo.Avg.ToDouble() >= dtl.Min_Value && dataInfo.Avg.ToDouble() <= dtl.Max_Value) |
|
.ToList(); |
|
} |
|
else |
|
{ |
|
maxValDtls = filteredDtls |
|
.Where(dtl => dataInfo.Max.ToDouble() >= dtl.Min_Value && dataInfo.Max.ToDouble() <= dtl.Max_Value) |
|
.ToList(); |
|
minValDtls = filteredDtls |
|
.Where(dtl => dataInfo.Min.ToDouble() >= dtl.Min_Value && dataInfo.Min.ToDouble() <= dtl.Max_Value) |
|
.ToList(); |
|
} |
|
// 获取对应的GradeLevelSet集合 |
|
var associatedLevelSets = _gradeLevelCutSets |
|
.Where(ls => filteredDtls.Any(dtl => dtl.Level_Sign == ls.Sign)) |
|
.ToList(); |
|
|
|
// 处理最大值的情况 |
|
GradeLevelSet? maxLevel = null; |
|
if (maxValDtls.Any()) |
|
{ |
|
// 若有多个区间,取最差的(Short值最大) |
|
if (maxValDtls.Count > 1) |
|
{ |
|
maxLevel = associatedLevelSets |
|
.Where(ls => maxValDtls.Any(dtl => dtl.Level_Sign == ls.Sign)) |
|
.OrderBy(ls => ls.Short) |
|
.FirstOrDefault(); |
|
} |
|
else |
|
{ |
|
maxLevel = associatedLevelSets |
|
.FirstOrDefault(ls => ls.Sign == maxValDtls.First().Level_Sign); |
|
} |
|
} |
|
|
|
// 处理最小值的情况 |
|
GradeLevelSet? minLevel = null; |
|
if (minValDtls.Any()) |
|
{ |
|
// 若有多个区间,取最差的(Short值最大) |
|
if (minValDtls.Count > 1) |
|
{ |
|
minLevel = associatedLevelSets |
|
.Where(ls => minValDtls.Any(dtl => dtl.Level_Sign == ls.Sign)) |
|
.OrderBy(ls => ls.Short) |
|
.FirstOrDefault(); |
|
} |
|
else |
|
{ |
|
minLevel = associatedLevelSets |
|
.FirstOrDefault(ls => ls.Sign == minValDtls.First().Level_Sign); |
|
} |
|
} |
|
|
|
// 若最大值和最小值都找到对应的区间,返回较差的一个 |
|
if (maxLevel != null && minLevel != null) |
|
{ |
|
return maxLevel.Short > minLevel.Short ? maxLevel : minLevel; |
|
} |
|
|
|
// 若只有一个找到区间,返回该区间对应的级别 |
|
if (maxLevel != null) return maxLevel; |
|
if (minLevel != null) return minLevel; |
|
|
|
// 若都没找到,返回子集中最差的级别 |
|
return associatedLevelSets.OrderBy(ls => ls.Short).FirstOrDefault(); |
|
} |
|
private GradeLevelSet? GetFinalSymGrade(string treeSign, string key, double devVal) |
|
{ |
|
// 通过TreeSign和Key关联获取子集 |
|
var dataSet = _gradeLevelDataSets.FirstOrDefault(ds => ds.KName == key); |
|
if (dataSet == null) return null; |
|
|
|
var filteredDtls = _gradeLevelSetDtls |
|
.Where(dtl => dtl.Tree_Sign == treeSign && dtl.DataSet_Sign == dataSet.Sign) |
|
.ToList(); |
|
|
|
if (!filteredDtls.Any()) return null; |
|
|
|
// 查找偏差值对应的区间 |
|
var devValDtls = filteredDtls |
|
.Where(dtl => devVal >= dtl.Min_Value && devVal <= dtl.Max_Value) |
|
.ToList(); |
|
|
|
// 获取对应的GradeLevelSet集合 |
|
var associatedLevelSets = _gradeLevelSymSets |
|
.Where(ls => filteredDtls.Any(dtl => dtl.Level_Sign == ls.Sign)) |
|
.ToList(); |
|
|
|
// 处理偏差值的情况 |
|
GradeLevelSet? devLevel = null; |
|
if (devValDtls.Any()) |
|
{ |
|
// 若有多个区间,取最差的(Short值最大) |
|
if (devValDtls.Count > 1) |
|
{ |
|
devLevel = associatedLevelSets |
|
.Where(ls => devValDtls.Any(dtl => dtl.Level_Sign == ls.Sign)) |
|
.OrderBy(ls => ls.Short) |
|
.FirstOrDefault(); |
|
} |
|
else |
|
{ |
|
devLevel = associatedLevelSets |
|
.FirstOrDefault(ls => ls.Sign == devValDtls.First().Level_Sign); |
|
} |
|
} |
|
|
|
// 若找到对应的区间,返回该区间对应的级别 |
|
if (devLevel != null) return devLevel; |
|
|
|
// 若没找到,返回子集中最差的级别 |
|
return associatedLevelSets.OrderByDescending(ls => ls.Short).FirstOrDefault(); |
|
} |
|
|
|
private GradeLevelSet CalculateTotalGrade(List<DataInfo> dataInfos, GradeLevelTotalSet totalSet, List<GradeLevelSet> levelSets) |
|
{ |
|
// 解析参与评级的数据签名 |
|
var dataSigns = totalSet.DataSigns.Split(',', StringSplitOptions.RemoveEmptyEntries); |
|
|
|
// 找出所有参与评级的项目对应的评级 |
|
var gradeLevels = new List<GradeLevelSet>(); |
|
|
|
foreach (var dataSign in dataSigns) |
|
{ |
|
var dataSet = _gradeLevelDataSets.FirstOrDefault(ds => ds.Sign == dataSign); |
|
if (dataSet == null) continue; |
|
|
|
var dataInfo = dataInfos.FirstOrDefault(di => di.TestItemId == dataSet.KName); |
|
if (dataInfo == null) continue; |
|
|
|
GradeLevelSet? gradeLevel = null; |
|
|
|
if (totalSet.Set_Type == GradeType.Cut.GetValue()) |
|
{ |
|
// 切工评级 |
|
gradeLevel = GetCutGradeLevelSet(dataSet.KName, dataInfo); |
|
} |
|
else if (totalSet.Set_Type == GradeType.Sym.GetValue()) |
|
{ |
|
// 对称评级 |
|
gradeLevel = GetSymGradeLevelSet(dataSet.KName, dataInfo); |
|
} |
|
|
|
if (gradeLevel != null) |
|
{ |
|
gradeLevels.Add(gradeLevel); |
|
} |
|
} |
|
|
|
// 若没有找到任何评级,返回默认最差评级 |
|
if (!gradeLevels.Any()) |
|
{ |
|
return levelSets.OrderByDescending(ls => ls.Short).FirstOrDefault() |
|
?? throw new NotGradeSetException("无法计算总评级,没有找到有效的评级数据"); |
|
} |
|
|
|
// 根据统计方式聚合评级 |
|
switch (totalSet.Statistics) |
|
{ |
|
case 0: // 最大值(最差) |
|
return gradeLevels.OrderBy(ls => ls.Short).First(); |
|
|
|
case 1: // 最小值(最好) |
|
return gradeLevels.OrderByDescending(ls => ls.Short).First(); |
|
|
|
case 2: // 平均值 |
|
// 计算平均Short值 |
|
double averageShort = gradeLevels.Average(ls => ls.Short); |
|
|
|
// 找到最接近平均值的等级 |
|
return levelSets |
|
.OrderBy(ls => Math.Abs(ls.Short - averageShort)) |
|
.FirstOrDefault() |
|
?? throw new NotGradeSetException("无法计算平均评级,没有找到匹配的等级"); |
|
|
|
default: |
|
throw new NotSupportedException($"不支持的统计方式: {totalSet.Statistics}"); |
|
} |
|
} |
|
} |