经过51的三天努力,完成基于JRT的质控核心部分。框架部分已经达到了第一个可生产版本。
可生产包括以下部分:
1.Web开发基础和发布运维基础
2.Linux和WIndows客户端浏览器
3.Linux和WIndows客户端打印导出程序
4.Linux和WIndows初始化程序
5.Linux和WIndows仪器接口程序
6.打印模板设计器
7.菜单权限基础
8.文件服务
9.核心质控验证程序
能够实现的效果有:
模板设计
质控图在线打印预览
质控图打印预览
质控图打印
质控月报的横纵向预览和打印
质控月报复杂的Excel模板导出
环境下载
码表
开发和运维调试端
jrt运维命令
代码生成器和SQL执行器
以前业务脚本基本上是孤岛,提供新api加强业务脚本之间的联系
基本涵盖开发业务系统需要的方方面面,始终坚持业务脚本化、环境简单化、开发高效化的理念。开发基于IRIS数据库,开发完成后然后用M一键生成PostGreSql和人大金仓构造库的SQL脚本用网站执行来在PostGreSql和人大金仓上构建数据库。业务因为不写SQL语句,所有迁移数据库不需要改动任何一行业务代码,为了实现真正的多数据库支持(而不是口号),ORM只支持基础数据类型、不允许使用Datetime类似、比特类型,就没有数据库差异性问题,所以理论是支持所有JDBC的数据库而不需要改业务代码的。
选择质控来验证架构,一是因为质控独立性好,二是质控无论是表关系还是业务复杂性都够了,三是质控的打印足够复杂,既有JS绘图部分,也有表格部分,多方糅合,比较考验基础层。四是质控规则判断和月报数据计算足够复杂来验证框架的可靠性。五是质控我熟,可以很快实现。整体开发下来开发效率比M高很多、执行效率和M不差什么、可以媲美一下Cache的效率了。有了DolerGet之后,关系库在多维业务处理上也不在是那么弱鸡的存在了,最难突破的是思想,有一年多的时间我也觉得关系库永远实现不到我用Cache也业务的效果。
质控图查询与规则判断的核心代码:
import JRT.Core.Dto.HashParam;
import JRT.Core.Dto.OutValue;
import JRT.Core.Util.Convert;
import JRT.Core.Util.TimeParser;
import JRT.Model.Bussiness.Parameters;
import JRT.Model.Entity.*;
import JRTBLLBase.BaseHttpHandler;
import JRTBLLBase.Helper;import java.util.*;/*** 画质控图公共查询逻辑,所有的质控图都通过虚拟M调过来,该类实现规则判断、对接月报累计值计算等等*/
public class QCDrawCommon extends BaseHttpHandler {/*** 质控绘图公共查数据* @param Param* @param Session* @param Output* @return* @throws Exception*/public String QueryQcDrawData(Parameters Param, OutValue Session, OutValue Output) throws Exception {int StartDate= Helper.ValidParam(Param.P0,0);int EndDate=Helper.ValidParam(Param.P1,0);int MachineParameterDR= Convert.ToInt32(Param.P2);int TestCodeDR=Convert.ToInt32(Param.P3);String Level=Param.P4;String QcRule=Param.P5;String PointRange=Param.P6;String MaterialDR=Param.P7;String UseFL=Param.P8;String LotNo=Param.P9;HashParam hs=new HashParam();hs.Add("MachineParameterDR",MachineParameterDR);hs.Add("TestCodeDR",TestCodeDR);List<String> operater=new ArrayList<>();operater.add("=");operater.add("=");hs.Add("TestDate",StartDate);hs.Add("TestDate",EndDate);operater.add(">=");operater.add("<=");//质控物浓度映射HashMap<Integer,BTQCMaterialLevel> matLevMap=new HashMap<>();//存计算的月报数据HashMap<String,HashMap> calMonthData=new HashMap<>();//筛选质控物if(!MaterialDR.isEmpty()){int MaterialDRInt=Convert.ToInt32(MaterialDR);hs.Add("MaterialDR",MaterialDRInt);//质控浓度List<BTQCMaterialLevel> levList=EntityManager().FindByColVal(BTQCMaterialLevel.class,"MaterialDR",Convert.ToInt32(MaterialDR));if(levList!=null&&levList.size()>0){for(BTQCMaterialLevel lev:levList){matLevMap.put(lev.LevelNo,lev);//计算质控规则CalQCRule(StartDate,EndDate,MaterialDRInt,TestCodeDR,lev.LevelNo,PointRange,"");//得到月报的计算数据List<HashMap> monthData=(List<HashMap>)Helper.GetBllMethodData("qc.ashx.ashQCDataCalMonth","CalOneMonthData",StartDate,EndDate,MaterialDRInt,TestCodeDR,lev.LevelNo,PointRange,true);if(monthData!=null&&monthData.size()>0){//按计算键把月报数据存起来for(HashMap one:monthData){String calKey=one.get("CalKey").toString();calMonthData.put(calKey,one);}}}}}//浓度筛选图HashMap levMap=Helper.GetSplitMap(Level,",");//查询仪器、项目、日期范围的所有质控数据List<QCTestResultDto> allData=EntityManager().FindAllSimple(QCTestResultDto.class,hs,"LevelNo asc,TestDate asc,TestTime asc",-1,null,operater);//存处理后的数据List<QCTestResultDto> dealedData=new ArrayList<>();//1:所有质控点 2:去除排除点 6:所有在控点 11:去除平行点 12:仅平行点 4:去除复查点 10:只查最后一点//7:最好点连线 8:最后一点连线 9:只查最好点//辅助判断复查点HashMap redoMap=new HashMap();//最好点的图HashMap<String,QCTestResultDto> bestMap=new HashMap();HashMap<Integer, Boolean> bestRowIDMap=new HashMap();//最后点的图HashMap<String,QCTestResultDto> lastMap=new HashMap();HashMap<Integer, Boolean> lastRowIDMap=new HashMap();//按点类型筛选数据dealedData=FilterDataByPointType(allData,levMap,matLevMap,PointRange);//补全计算值和累计值if(dealedData!=null&&dealedData.size()>0){for(QCTestResultDto one:dealedData){//排除颜色if(one.ExcludeType.equals("2")){one.CurRuleColour="#549cc7";}//平行质控颜色if(one.IsParallel!=null&&one.IsParallel==true){one.CurRuleColour="#8A2BE2";}//计算的键,相同的键算一批String calKey=one.LotNo;//没维护批号的按靶值和SD相同的算if(calKey.isEmpty()){calKey=one.TCX+"-"+one.TCSD;}calKey=one.MaterialDR+"-"+one.TestCodeDR+"-"+one.LevelNo+"-"+calKey;//放入月报计算数据if(calMonthData.containsKey(calKey)){HashMap oneMonthData=calMonthData.get(calKey);one.CalX=oneMonthData.get("CalMean").toString();one.CalSD=oneMonthData.get("CalSD").toString();one.CalCV=oneMonthData.get("CalCV").toString();one.AccMean=oneMonthData.get("AccMean").toString();one.AccSD=oneMonthData.get("AccSD").toString();one.AccCV=oneMonthData.get("AccCV").toString();}}}return Helper.Object2Json(dealedData);}/*** 计算质控规则* @param startDate 开始日期* @param endDate 结束日期* @param materialDR 质控物* @param testCodeDR 项目浓度* @param levelNo 浓度* @param fPointType 点类型* @param useFL 是否使用浮动* @throws Exception*/public void CalQCRule(int startDate,int endDate,int materialDR, int testCodeDR, int levelNo, String fPointType,String useFL) throws Exception{//从前12天数据开始查询,最大到12x规则int qryStartDate=Helper.AddDays(startDate,-12);HashParam hs=new HashParam();hs.Add("MaterialDR",materialDR);hs.Add("TestCodeDR",testCodeDR);hs.Add("LevelNo",levelNo);hs.Add("TestDate",qryStartDate);hs.Add("TestDate",endDate);List<String> operater=new ArrayList<>();operater.add("=");operater.add("=");operater.add("=");operater.add(">");operater.add("<=");//查询结果List<QCTestResultDto> resList=EntityManager().FindAllSimple(QCTestResultDto.class,hs,"TestDate asc,TestTime asc",-1,null,operater);//质控使用的规则List<BTQCRules> useRules=new ArrayList<>();//项目单独维护的规则List<BTQCMaterialTCRules> tcRules=EntityManager().FindByColVal(BTQCMaterialTCRules.class,"MaterialDR",materialDR);//有项目规则就用项目的规则if(tcRules!=null&&tcRules.size()>0){for(BTQCMaterialTCRules one:tcRules){BTQCRules rule=EntityManager().DolerGet(BTQCRules.class,one.QCRulesDR);useRules.add(rule);}}//否则用质控物上的规则else{List<BTQCMaterialRules> rules=EntityManager().FindByColVal(BTQCMaterialRules.class,"MaterialDR",materialDR);if(rules!=null&&rules.size()>0){for(BTQCMaterialRules one:rules){BTQCRules rule=EntityManager().DolerGet(BTQCRules.class,one.QCRulesDR);useRules.add(rule);}}}//按序号排序规则useRules.sort(new Comparator<BTQCRules>() {@Overridepublic int compare(BTQCRules p1, BTQCRules p2) {return p1.Sequence - p2.Sequence;}});//判断规则if(resList!=null&&resList.size()>0&&useRules!=null&&useRules.size()>0){List<String> upCol=new ArrayList<>();upCol.add("QCRulesDR");upCol.add("DQIV_Status");upCol.add("ResColor");//计算方差SD,每个点偏离靶值的SD倍数先计算好CalDeviationSD(resList);//延迟更新HashMap<Integer,QCTestResultDto> lazyUpdataMap=new HashMap<>();//遍历检查每个结果for(int i=0;i<resList.size();i++){QCTestResultDto res=resList.get(i);//是否更新了质控规则,没更新的最后如果有规则就清空boolean hasUpdateRule=false;//遍历判断每个规则for(BTQCRules rule:useRules){//判断1-1S########################################一个质控测定值超过X±1S质控限。if(rule.Code.equals("Y")){int numPos=CheckSameSide(resList,i,1,1.0,true);int numNeg=CheckSameSide(resList,i,1,-1.0,false);if(numPos+numNeg>0){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}//判断1-2S########################################一个质控测定值超过X±2S质控限。else if(rule.Code.equals("A")){int numPos=CheckSameSide(resList,i,1,2.0,true);int numNeg=CheckSameSide(resList,i,1,-2.0,false);if(numPos+numNeg>0){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}//判断1-3S########################################一个质控测定值超过X±3S质控限。else if(rule.Code.equals("B")){int numPos=CheckSameSide(resList,i,1,3.0,true);int numNeg=CheckSameSide(resList,i,1,-3.0,false);if(numPos+numNeg>0){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}//判断2-2S########################################两个连续的质控测定值同时超过X-2S或同时超过X+2S质控限,或同一天不同水平超过±2S,都要求同侧.else if(rule.Code.equals("C")){int numPos=CheckSameSide(resList,i,2,2.0,true);int numNeg=CheckSameSide(resList,i,2,-2.0,false);//两个连续的质控测定值同时超过X-2S或X+2S质控限if(numPos==2||numNeg==2){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}else if(numPos==1||numNeg==1){List<QCTestResultDto> otherRes=GetOtherLevRes(res);if(otherRes!=null&&otherRes.size()>0) {//正向检查其他浓度if(numPos==1){int otNum=otherRes.size();int numPosOT=CheckSameSide(otherRes,otNum-1,otNum,2.0,true);if(numPosOT>=1){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}//反向检查其他浓度else if(numNeg==1){int otNum=otherRes.size();int numNegOT=CheckSameSide(otherRes,otNum-1,otNum,-2.0,false);if(numNegOT>=1){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}}}}//判断R-4S########################################同批连续质控点一个超过+2S,一个超过-2S,或者同一天不同浓度的超过±2S。要求不同侧else if(rule.Code.equals("R")){int numPos=CheckSameSide(resList,i,2,2.0,true);int numNeg=CheckSameSide(resList,i,2,-2.0,false);//同批连续质控点一个超过+2S,一个超过-2Sif(numPos==1&&numNeg==1){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}//或者同一天不同浓度的超过±2Selse{List<QCTestResultDto> otherRes=GetOtherLevRes(res);if(otherRes!=null&&otherRes.size()>0) {//正向检查其他浓度if(numPos==1){int otNum=otherRes.size();int numNegOT=CheckSameSide(otherRes,otNum-1,otNum,-2.0,false);if(numNegOT>=1){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}//反向检查其他浓度else if(numNeg==1){int otNum=otherRes.size();int numPosOT=CheckSameSide(otherRes,otNum-1,otNum,2.0,true);if(numPosOT>=1){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}}}}//判断R4S_########################################两个连续的测定值之差超过4S。else if(rule.Code.equals("T")){if(i>0){Double preOffset=resList.get(i-1).Offset;Double curOffset=resList.get(i).Offset;Double calDV=Math.abs(preOffset-curOffset);if(calDV>4){hasUpdateRule=true;//更新质控规则UpdateRule(res,rule,lazyUpdataMap);//终止判断if(rule.IsEnd==true){break;}}}}//判断4-1S########################################四个连续的质控测定值同时超过X-1S或X+1S。(同侧)else if(rule.Code.equals("E")){int numPos=CheckSameSide(resList,i,4,1.0,true);int numNeg=CheckSameSide(resList,i,4,-1.0,false);//四个点大于1s或-1sif(numPos==4||numNeg==4){int numPos2S=CheckSameSide(resList,i,4,2.0,true);int numNeg2S=CheckSameSide(resList,i,4,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判断3-1S########################################三个连续的质控测定值同时超过X-1S或X+1S。else if(rule.Code.equals("D")){int numPos=CheckSameSide(resList,i,3,1.0,true);int numNeg=CheckSameSide(resList,i,3,-1.0,false);//三个点大于1s或-1sif(numPos==3||numNeg==3){int numPos2S=CheckSameSide(resList,i,3,2.0,true);int numNeg2S=CheckSameSide(resList,i,3,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判断10X########################################十个连续的质控测定值落在靶值(X)的同一侧。1-2S触发else if(rule.Code.equals("G")){int numPos=CheckSameSide(resList,i,10,0.0,true);int numNeg=CheckSameSide(resList,i,10,0.0,false);//十个连续的质控测定值落在靶值(X)的同一侧if(numPos==10||numNeg==10){int numPos2S=CheckSameSide(resList,i,10,2.0,true);int numNeg2S=CheckSameSide(resList,i,10,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判断5X########################################五个连续的质控测定值落在靶值(X)的同一侧。1-2S触发else if(rule.Code.equals("F")){int numPos=CheckSameSide(resList,i,5,0.0,true);int numNeg=CheckSameSide(resList,i,5,0.0,false);//5个连续的质控测定值落在靶值(X)的同一侧if(numPos==5||numNeg==5){int numPos2S=CheckSameSide(resList,i,5,2.0,true);int numNeg2S=CheckSameSide(resList,i,5,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判判断8X########################################八个连续的质控测定值落在靶值(X)的同一侧。1-2S触发else if(rule.Code.equals("Q")){int numPos=CheckSameSide(resList,i,8,0.0,true);int numNeg=CheckSameSide(resList,i,8,0.0,false);//8个连续的质控测定值落在靶值(X)的同一侧if(numPos==8||numNeg==8){int numPos2S=CheckSameSide(resList,i,8,2.0,true);int numNeg2S=CheckSameSide(resList,i,8,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判断12X########################################十二个连续的质控测定值落在靶值(X)的同一侧。1-2S触发else if(rule.Code.equals("S")){int numPos=CheckSameSide(resList,i,12,0.0,true);int numNeg=CheckSameSide(resList,i,12,0.0,false);//十个连续的质控测定值落在靶值(X)的同一侧if(numPos==12||numNeg==12){int numPos2S=CheckSameSide(resList,i,12,2.0,true);int numNeg2S=CheckSameSide(resList,i,12,-2.0,false);//有一个点大于1-2Sif(numPos2S>1||numNeg2S>1) {hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//判断7T########################################七个连续的质控测定值呈现出向上或向下的趋势else if(rule.Code.equals("P")){int numPos=CheckTrend(resList,i,7,true);int numNeg=CheckTrend(resList,i,7,false);//十个连续的质控测定值落在靶值(X)的同一侧if(numPos==7||numNeg==7){hasUpdateRule = true;//更新质控规则UpdateRule(res, rule, lazyUpdataMap);//终止判断if (rule.IsEnd == true) {break;}}}}//没有更新规则的,如果数据里面有规则就清空if(hasUpdateRule==false&&res.QCRulesDR!=null){UpdateRule(res,null,lazyUpdataMap);}}Iterator<HashMap.Entry<Integer, QCTestResultDto>> iterator = lazyUpdataMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<Integer, QCTestResultDto> entry = iterator.next();QCTestResultDto cur=entry.getValue();//变化了才更新if(cur.NewRuleDR!=cur.QCRulesDR) {cur.QCRulesDR=cur.NewRuleDR;cur.DQIV_Status=cur.NewRuleStatus;if(cur.NewRuleDR==null){cur.ResColor="";}int ret = EntityManager().Update(cur, upCol);}}}}/*** 查找当天其他浓度的数据* @param res 当前结果* @return 当前结果时间之前的其他浓度结果*/private List<QCTestResultDto> GetOtherLevRes(QCTestResultDto res) throws Exception{HashParam hs=new HashParam();hs.Add("MaterialDR",res.MaterialDR);hs.Add("TestCodeDR",res.TestCodeDR);hs.Add("TestDate",res.TestDate);hs.Add("TestTime",res.TestTime);List<String> operater=new ArrayList<>();operater.add("=");operater.add("=");operater.add("=");operater.add("<=");List<QCTestResultDto> resList=EntityManager().FindAllSimple(QCTestResultDto.class,hs,"TestTime asc",-1,null,operater);List<QCTestResultDto> retList=new ArrayList<>();if(resList!=null&&resList.size()>0){for(QCTestResultDto one:resList){if(one.LevelNo==res.LevelNo){continue;}QCResMaterialTestCode para=EntityManager().DolerGet(QCResMaterialTestCode.class,one.ResMaterialTestCodeDR);one.RunPara=para;if(para.SD!=0) {one.Offset = (Convert.ToDouble(res.Result) - para.Mean) / para.SD;}else{one.Offset=0.0;}retList.add(one);}}return retList;}/*** 更新质控规则* @param res 结果* @param rule 规则* @param lazyMap 延迟更新* @throws Exception*/private void UpdateRule(QCTestResultDto res,BTQCRules rule,HashMap<Integer,QCTestResultDto> lazyMap) throws Exception{if(rule==null){res.NewRuleDR=null;res.NewRuleStatus="";lazyMap.put(res.RowID,res);}else{res.NewRuleDR = rule.RowID;res.NewRuleStatus = rule.Status;lazyMap.put(res.RowID,res);}}/*** 检测向上和向下趋势* @param resList* @param start* @param checkNum* @param isPos* @return*/public int CheckTrend(List<QCTestResultDto> resList,int start,int checkNum,boolean isPos){int retNum=0;Double preOffset=null;//检测数据for(int i=start;i>=0;i--){QCTestResultDto res=resList.get(i);checkNum--;if(preOffset!=null){//连续向下if(isPos==true){if(preOffset<res.Offset){retNum++;}else{break;}}//连续向下else{if(preOffset>res.Offset){retNum++;}else{break;}}}//检测数量if(checkNum==0){break;}}return retNum;}/*** 检测在一侧的点数* @param resList 所有结果* @param start 开始位置* @param checkNum 往前找的数量* @param sd sd值* @param isPos 是否正向* @return*/public int CheckSameSide(List<QCTestResultDto> resList,int start,int checkNum,Double sd,boolean isPos){int retNum=0;//检测数据for(int i=start;i>=0;i--){QCTestResultDto res=resList.get(i);checkNum--;if(isPos==true&&res.Offset>sd){retNum++;}else if(isPos==false&&res.Offset<sd){retNum++;}//检测数量if(checkNum==0){break;}}return retNum;}/*** 计算每个点的偏差SD* @param resList 结果集合*/public void CalDeviationSD(List<QCTestResultDto> resList) throws Exception{for(QCTestResultDto res:resList){//获得参数QCResMaterialTestCode para=EntityManager().DolerGet(QCResMaterialTestCode.class,res.ResMaterialTestCodeDR);res.RunPara=para;if(para.SD!=0) {res.Offset = (Convert.ToDouble(res.Result) - para.Mean) / para.SD;}else{res.Offset=0.0;}}}/*** 按点类型筛选数据* @param allData 所有数据* @param levMap 浓度* @param matLevMap 质控物浓度* @param pointRange 点类型* @return* @throws Exception*/public List<QCTestResultDto> FilterDataByPointType(List<QCTestResultDto> allData,HashMap levMap,HashMap<Integer,BTQCMaterialLevel> matLevMap,String pointRange) throws Exception{//存处理后的数据List<QCTestResultDto> dealedData=new ArrayList<>();//1:所有质控点 2:去除排除点 6:所有在控点 11:去除平行点 12:仅平行点 4:去除复查点 10:只查最后一点//7:最好点连线 8:最后一点连线 9:只查最好点//辅助判断复查点HashMap redoMap=new HashMap();//最好点的图HashMap<String,QCTestResultDto> bestMap=new HashMap();HashMap<Integer, Boolean> bestRowIDMap=new HashMap();//最后点的图HashMap<String,QCTestResultDto> lastMap=new HashMap();HashMap<Integer, Boolean> lastRowIDMap=new HashMap();if(allData!=null&&allData.size()>0){for(QCTestResultDto one:allData){//不是数字的不参与if(!Helper.IsNumeric(one.Result)){continue;}//筛选浓度if(levMap.size()>0&&!levMap.containsKey(String.valueOf(one.LevelNo))){continue;}//去除排除点if(pointRange.equals("2")&&one.ExcludeType.equals("2")){continue;}//所有在控点if(pointRange.equals("6")&&one.CurRuleStatus.equals("R")){continue;}//仅平行点if(pointRange.equals("11")&&!one.IsParallel.equals("!")){continue;}//去除平行点if(pointRange.equals("12")&&one.IsParallel.equals("!")){continue;}//去除复查点if(pointRange.equals("4")&&redoMap.containsKey(one.LevelNo+"-"+one.TestDate)){continue;}//当天第一个数据redoMap.put(one.LevelNo+"-"+one.TestDate,true);one.CurLevelNo=one.LevelNo;one.CurPointType="";one.Num=1;one.CurdateNum=Helper.DateIntToStr(one.TestDate);one.TestRTime=Helper.TimeIntToStr(one.TestTime);one.UserName="";if(one.AddUserDR!=null){SYSUser user=EntityManager().DolerGet(SYSUser.class,one.AddUserDR);one.UserName=user.CName;}one.PicResult=one.Result;one.PicX=one.PicResult;one.CurRuleCode="";one.CurRuleColour="";one.CurRuleStatus="";one.CurRuleName="";if(one.QCRulesDR!=null){BTQCRules rule=EntityManager().DolerGet(BTQCRules.class,one.QCRulesDR);one.CurRuleCode=rule.Code;one.CurRuleColour=rule.Color;one.CurRuleStatus=rule.Status;one.CurRuleName=rule.CName;}//参数QCResMaterialTestCode para=EntityManager().DolerGet(QCResMaterialTestCode.class,one.ResMaterialTestCodeDR);//结果和均值的差one.Offset=Math.abs(Convert.ToInt32(one.Result)-para.Mean);//找到最好结果if(!bestMap.containsKey(one.LevelNo+"-"+one.TestDate)){bestMap.put(one.LevelNo+"-"+one.TestDate,one);}else{QCTestResultDto pre=bestMap.get(one.LevelNo+"-"+one.TestDate);if(pre.Offset>one.Offset){bestMap.put(one.LevelNo+"-"+one.TestDate,one);}}//最后点lastMap.put(one.LevelNo+"-"+one.TestDate,one);one.TCX=String.valueOf(para.Mean);one.TCSD=String.valueOf(para.SD);BTTestCode testCode=EntityManager().DolerGet(BTTestCode.class,one.TestCodeDR);one.TCName=testCode.CName;one.CurTestCode=testCode.Code;one.CurLevelName=matLevMap.get(one.LevelNo).CName;one.TCCV=String.valueOf(para.SetCV);one.CalX="";one.CalSD="";one.CalCV="";one.CalcType="";one.AccMean="";one.AccSD="";one.AccCV="";one.SetCV=String.valueOf(para.SetCV);one.TargetCV=para.TargetCV;one.LotNo=para.LotNo;one.Event="";one.ReagentLot=para.RgLot;one.ResRemark=one.Remark;one.AutUserName="";one.OriginalRes=one.TextRes;one.TransactionRemark="";one.TransactionMethod="";one.TransactionRes="";one.TransactionType="";one.TransactionUser="";one.LotNoAll=para.LotNo;dealedData.add(one);}//转换成主键mapfor (Map.Entry<String,QCTestResultDto> entry : bestMap.entrySet()) {bestRowIDMap.put(entry.getValue().RowID,true);}//转换成主键mapfor (Map.Entry<String,QCTestResultDto> entry : lastMap.entrySet()) {lastRowIDMap.put(entry.getValue().RowID,true);}//第二次处理数据for(int i=0;i<dealedData.size();i++){//只查最好点if(pointRange.equals("9")){if(!bestRowIDMap.containsKey(dealedData.get(i).RowID)){dealedData.remove(i);i--;continue;}}//只查最后点if(pointRange.equals("10")){if(!lastRowIDMap.containsKey(dealedData.get(i).RowID)){dealedData.remove(i);i--;continue;}}//最好点连线if(pointRange.equals("7")){if(!bestRowIDMap.containsKey(dealedData.get(i).RowID)){dealedData.get(i).CurPointType="0";}}//最后点连线else{if(!lastRowIDMap.containsKey(dealedData.get(i).RowID)){dealedData.get(i).CurPointType="0";}}}}return dealedData;}/*** 查询日间质控图数据* @param Param* @param Session* @param Output* @return* @throws Exception*/public String QueryQcDrawDataDay(Parameters Param, OutValue Session, OutValue Output) throws Exception {int StartDate= Helper.ValidParam(Param.P0,0);int EndDate=Helper.ValidParam(Param.P1,0);int MachineParameterDR= Convert.ToInt32(Param.P2);String TestCodeDRS=Param.P3;String MaterialDRS=Param.P4;String Level=Param.P5;String LastPoint=Param.P6;String LotNo=Param.P7;HashParam hs=new HashParam();hs.Add("MachineParameterDR",MachineParameterDR);List<String> operater=new ArrayList<>();operater.add("=");hs.Add("TestDate",StartDate);hs.Add("TestDate",EndDate);operater.add(">=");operater.add("<=");//浓度筛选图HashMap levMap=Helper.GetSplitMap(Level,",");//项目筛选图HashMap tsMap=Helper.GetSplitMap(TestCodeDRS,",");//质控物筛选图HashMap matMap=Helper.GetSplitMap(MaterialDRS,",");String [] tsArr=TestCodeDRS.split(",");String [] matArr=MaterialDRS.split(",");String [] levArr=Level.split(",");//计算质控规则for(int i=0;i<tsArr.length;i++){int TestCodeDR=Convert.ToInt32(tsArr[i]);int MaterialDR=Convert.ToInt32(matArr[i]);List<BTQCMaterialLevel> levList=EntityManager().FindByColVal(BTQCMaterialLevel.class,"MaterialDR",MaterialDR);for(BTQCMaterialLevel lev:levList){//筛选浓度if(levMap.size()>0&&!levMap.containsKey(String.valueOf(lev.LevelNo))){continue;}//计算质控规则CalQCRule(StartDate,EndDate,MaterialDR,TestCodeDR,lev.LevelNo,"1","");}}//查询仪器、项目、日期范围的所有质控数据List<QCTestResultDto> allData=EntityManager().FindAllSimple(QCTestResultDto.class,hs,"LevelNo asc,TestDate asc,TestTime asc",-1,null,operater);//存处理后的数据List<QCTestResultDto> dealedData=new ArrayList<>();HashMap lastMap=new HashMap();if(allData!=null&&allData.size()>0){for(QCTestResultDto one:allData){//筛选浓度if(levMap.size()>0&&!levMap.containsKey(String.valueOf(one.LevelNo))){continue;}//筛选质控物if(matMap.size()>0&&!matMap.containsKey(String.valueOf(one.MaterialDR))){continue;}//筛选项目if(tsMap.size()>0&&!tsMap.containsKey(String.valueOf(one.TestCodeDR))){continue;}//最后点if(LastPoint.equals("1")) {String key = one.MaterialDR + "-" + one.TestCodeDR + "-" + one.LevelNo + "-" + one.TestDate;lastMap.put(key, one);}else{dealedData.add(one);}}//最后点if(LastPoint.equals("1")) {dealedData.addAll(lastMap.values());}//统计失控数量int lossControlNum=0;for(QCTestResultDto one:dealedData) {if(one.DQIV_Status.equals("R")){lossControlNum++;}}//补全数据for(QCTestResultDto one:dealedData){BTQCMaterial matDto=EntityManager().DolerGet(BTQCMaterial.class,one.MaterialDR);BTMIMachineParameter machDto=EntityManager().DolerGet(BTMIMachineParameter.class,matDto.MachineDR);one.CurMachName=machDto.CName;one.TestCodeNum=tsMap.size()+"";one.LossControlNum=lossControlNum+"";one.CurLevelNo=one.LevelNo;one.CurPointType="";one.Num=1;one.CurdateNum=Helper.DateIntToStr(one.TestDate);one.TestRTime=Helper.TimeIntToStr(one.TestTime);one.UserName="";if(one.AddUserDR!=null){SYSUser user=EntityManager().DolerGet(SYSUser.class,one.AddUserDR);one.UserName=user.CName;}one.PicResult=one.Result;one.PicX=one.PicResult;one.CurRuleCode="";one.CurRuleColour="";one.CurRuleStatus="";one.CurRuleName="";if(one.QCRulesDR!=null){BTQCRules rule=EntityManager().DolerGet(BTQCRules.class,one.QCRulesDR);one.CurRuleCode=rule.Code;one.CurRuleColour=rule.Color;one.CurRuleStatus=rule.Status;one.CurRuleName=rule.CName;}//参数QCResMaterialTestCode para=EntityManager().DolerGet(QCResMaterialTestCode.class,one.ResMaterialTestCodeDR);//结果和均值的差one.Offset=Math.abs(Convert.ToInt32(one.Result)-para.Mean);//最后点lastMap.put(one.LevelNo+"-"+one.TestDate,one);one.TCX=String.valueOf(para.Mean);one.TCSD=String.valueOf(para.SD);BTTestCode testCode=EntityManager().DolerGet(BTTestCode.class,one.TestCodeDR);one.TCName=testCode.CName;one.CurTestCode=testCode.Code;one.CurLevelName="";one.TCCV=String.valueOf(para.SetCV);one.CalX="";one.CalSD="";one.CalCV="";one.CalcType="";one.AccMean="";one.AccSD="";one.AccCV="";one.SetCV=String.valueOf(para.SetCV);one.TargetCV=para.TargetCV;one.LotNo=para.LotNo;one.Event="";one.ReagentLot=para.RgLot;one.ResRemark=one.Remark;one.AutUserName="";one.OriginalRes=one.TextRes;one.TransactionRemark="";one.TransactionMethod="";one.TransactionRes="";one.TransactionType="";one.TransactionUser="";one.LotNoAll=para.LotNo;}}return Helper.Object2Json(dealedData);}/*** 返回到前台的数据实体*/public static class QCTestResultDto extends QCTestResult{/*** 当前浓度*/public int CurLevelNo;/*** 点类型*/public String CurPointType;/*** 数量*/public int Num;/*** 日期*/public String CurdateNum;/*** 测试时间*/public String TestRTime;/*** 用户名*/public String UserName;/*** 画图结果*/public String PicResult;/*** 结果*/public String PicX;/*** 规则代码*/public String CurRuleCode;/*** 规则颜色*/public String CurRuleColour;/*** 规则状态*/public String CurRuleStatus;/*** 规则名称*/public String CurRuleName;/*** 靶值*/public String TCX;/*** SD*/public String TCSD;/*** 项目名称*/public String TCName;/*** 项目代码*/public String CurTestCode;/*** 浓度名称*/public String CurLevelName;/*** CV*/public String TCCV;/*** 计算均值*/public String CalX;/*** 计算SD*/public String CalSD;/*** 计算CV*/public String CalCV;/*** 计算类型*/public String CalcType;/*** 计算均值*/public String AccMean;/*** 计算均值*/public String AccSD;/*** 计算均值*/public String AccCV;/*** 计算均值*/public String SetCV;/*** 计算均值*/public String TargetCV;/*** 计算均值*/public String LotNo;/*** 计算均值*/public String Event;/*** 计算均值*/public String ReagentLot;/*** 计算均值*/public String ResRemark;/*** 计算均值*/public String AutUserName;/*** 计算均值*/public String OriginalRes;/*** 失控处理说明*/public String TransactionRemark;/*** 失控类型*/public String TransactionType;/*** 处理方法*/public String TransactionMethod;/*** 失控处理结果*/public String TransactionRes;/*** 失控处理人*/public String TransactionUser;/*** 全部批号*/public String LotNoAll;/*** 结果和靶值的偏差*/public Double Offset;/*** 运行参数*/public QCResMaterialTestCode RunPara;/*** 仪器名称*/public String CurMachName="";/*** 测试项目数量*/public String TestCodeNum="";/*** 失控数量*/public String LossControlNum="";/*** 新判断的规则*/public Integer NewRuleDR;/*** 新规则状态*/public String NewRuleStatus;}
}
质控月报的核心逻辑
import JRT.Core.Debug.DebugSession;
import JRT.Core.Dto.HashParam;
import JRT.Core.Dto.OutValue;
import JRT.Core.MultiPlatform.JRTContext;
import JRT.Core.Util.Convert;
import JRT.Core.Util.TimeParser;
import JRT.Model.Bussiness.Parameters;
import JRT.Model.Entity.*;
import JRTBLLBase.BaseHttpHandler;
import JRTBLLBase.Helper;import java.util.*;/*** 质控月报后台*/
public class ashQCDataCalMonth extends BaseHttpHandler {/*** 查询质控月报数据* @return* @throws Exception*/public String QueryTestResultMonthData() throws Exception{//开始日期String StartDate = Helper.ValidParam(JRTContext.GetRequest(Request,"StartDate"),"");//结束日期String EndDate = Helper.ValidParam(JRTContext.GetRequest(Request,"EndDate"),"");//仪器String MachineParameterDR = Helper.ValidParam(JRTContext.GetRequest(Request,"MachineParameterDR"),"");//浓度String Leavel = Helper.ValidParam(JRTContext.GetRequest(Request,"Leavel"),"");//项目String TestCodeDRS = Helper.ValidParam(JRTContext.GetRequest(Request,"TestCodeDRS"),"");//排除规则String QcRule = Helper.ValidParam(JRTContext.GetRequest(Request,"QcRule"),"");//质控物String MaterialDRS = Helper.ValidParam(JRTContext.GetRequest(Request,"MaterialDRS"),"");String PointType = Helper.ValidParam(JRTContext.GetRequest(Request,"PointType"), "");String LotType = Helper.ValidParam(JRTContext.GetRequest(Request,"LotType"), "");String FLots = Helper.ValidParam(JRTContext.GetRequest(Request,"FLots"), "");Parameters param=new Parameters();param.P0=StartDate;param.P1=EndDate;param.P2=MachineParameterDR;param.P3=Leavel;param.P4=TestCodeDRS;param.P5=QcRule;param.P6=MaterialDRS;param.P7=PointType;param.P8=LotType;param.P9=FLots;OutValue session=new OutValue();session.Value=UserLogin().SessionStr;OutValue output=new OutValue();return QueryQCMonthData(param,session,output);}/*** 查询质控月报数据的虚拟M方法** @param Param* @param Session* @param Output* @return*/public String QueryQCMonthData(Parameters Param, OutValue Session, OutValue Output) throws Exception {String SessionStr=Session.GetString();String [] sessArr=SessionStr.split("\\^");BTHospital hosDto=EntityManager().DolerGet(BTHospital.class,Convert.ToInt32(sessArr[4]));SYSUser userDto=EntityManager().DolerGet(SYSUser.class,Convert.ToInt32(sessArr[0]));Session.Value=hosDto.CName+"检验科";Session.Value+="^"+Helper.GetNowDateStr();Session.Value+="^"+"";Session.Value+="^"+"质控月报导出";Session.Value+="^"+userDto.CName;Session.Value+="^"+Helper.GetNowDateStr().substring(1,7);//开始日期String StartDate = Param.P0;//结束日期String EndDate = Param.P1;//仪器int MachineParameterDR = Helper.ValidParam(Param.P2,0);BTMIMachineParameter machDto=EntityManager().DolerGet(BTMIMachineParameter.class,MachineParameterDR);Session.Value+="^"+machDto.CName;BTWorkGroupMachine wgmDto=EntityManager().DolerGet(BTWorkGroupMachine.class,machDto.WorkGroupMachineDR);Session.Value+="^"+wgmDto.CName;BTWorkGroup wgDto=EntityManager().DolerGet(BTWorkGroup.class,wgmDto.WorkGroupDR);Session.Value+="^"+wgDto.CName;//浓度String Leavel = Param.P3;//项目String TestCodeDRS = Param.P4;//排除规则String QcRule = Param.P5;//质控物String MaterialDRS = Param.P6;String PointType = Param.P7;String LotType = Param.P8;String FLots = Param.P9;//计算项目String [] tsArr=TestCodeDRS.split(",");//计算质控物String [] matArr=MaterialDRS.split(",");//浓度图HashMap levMap=Helper.GetSplitMap(Leavel,",");List<QCMonthRetDto> retList=new ArrayList<>();//存所有的质控规则HashMap<Integer,Boolean> ruleMap=new HashMap();//循环计算每个项目的月报数据for(int i=0;i<tsArr.length;i++){String MaterialDR=matArr[i];//得到质控物的规则List<BTQCMaterialRules> ruleList=EntityManager().FindByColVal(BTQCMaterialRules.class,"MaterialDR",Convert.ToInt32(MaterialDR));if(ruleList!=null&&ruleList.size()>0){for(BTQCMaterialRules rule:ruleList){ruleMap.put(rule.QCRulesDR,true);}}//得到质控物的浓度数据List<BTQCMaterialLevel> levList=EntityManager().FindByColVal(BTQCMaterialLevel.class,"MaterialDR",Convert.ToInt32(MaterialDR));for(BTQCMaterialLevel lev:levList) {String levStr=String.valueOf(lev.LevelNo);if(levMap.size()>0&&!levMap.containsKey(levStr)){continue;}//计算一个项目浓度的月报数据List<HashMap> calResList=CalOneMonthData(Helper.ValidParam(StartDate,0),Helper.ValidParam(EndDate,0),Convert.ToInt32(MaterialDR),Convert.ToInt32(tsArr[i]),Convert.ToInt32(levStr),PointType,false);for(HashMap one:calResList){QCMonthRetDto oneMon=new QCMonthRetDto();Helper.CopyProperties(one.get("LastPara"),oneMon);BTQCMaterial matDto=EntityManager().DolerGet(BTQCMaterial.class,oneMon.MaterialDR);oneMon.MatName=matDto.CName;oneMon.YearMonth=Helper.DateIntToStr(oneMon.TestDate).substring(0,7);oneMon.AccMean=String.valueOf(one.get("AccMean"));oneMon.AccSD=String.valueOf(one.get("AccSD"));oneMon.AccCV=String.valueOf(one.get("AccCV"));oneMon.AccMax=String.valueOf(one.get("AccMax"));oneMon.AccMin=String.valueOf(one.get("AccMin"));oneMon.AccNum=String.valueOf(one.get("AccNum"));oneMon.AccResStr=String.valueOf(one.get("AccResStr"));oneMon.CalMean=String.valueOf(one.get("CalMean"));oneMon.CalSD=String.valueOf(one.get("CalSD"));oneMon.CalCV=String.valueOf(one.get("CalCV"));oneMon.CalMax=String.valueOf(one.get("CalMax"));oneMon.CalMin=String.valueOf(one.get("CalMin"));oneMon.CalNum=String.valueOf(one.get("CalNum"));oneMon.CalResStr=String.valueOf(one.get("CalResStr"));oneMon.CalLossNum=String.valueOf(one.get("CalLossNum"));oneMon.CalWaringNum=String.valueOf(one.get("CalWaringNum"));oneMon.CalDealNum=String.valueOf(one.get("CalDealNum"));oneMon.CalLossRate=String.valueOf(one.get("CalLossRate"));oneMon.CalDealRate=String.valueOf(one.get("CalDealRate"));oneMon.CalWaringRate=String.valueOf(one.get("CalWaringRate"));oneMon.CalDealWRate=String.valueOf(one.get("CalDealWRate"));oneMon.CalInMean=String.valueOf(one.get("CalInMean"));oneMon.CalInSD=String.valueOf(one.get("CalInSD"));oneMon.CalInCV=String.valueOf(one.get("CalInCV"));oneMon.CalInMax=String.valueOf(one.get("CalInMax"));oneMon.CalInMin=String.valueOf(one.get("CalInMin"));oneMon.CalInNum=String.valueOf(one.get("CalInNum"));oneMon.CalInResStr=String.valueOf(one.get("CalInResStr"));if(!oneMon.CalCV.isEmpty()&&!oneMon.TargetCV.isEmpty()){if(Convert.ToDouble(oneMon.CalCV)<Convert.ToDouble(oneMon.TargetCV)){oneMon.IsQualified="通过";}}BTTestCode tsDto=EntityManager().DolerGet(BTTestCode.class,oneMon.TestCodeDR);oneMon.Synonym=tsDto.Synonym;oneMon.TCName=tsDto.CName;oneMon.LevelName=lev.CName;retList.add(oneMon);}}}//所有的质控规则String AllRuleName="";Iterator<HashMap.Entry<Integer, Boolean>> iterator = ruleMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<Integer, Boolean> entry = iterator.next();BTQCRules rule=EntityManager().DolerGet(BTQCRules.class,entry.getKey());if(AllRuleName.isEmpty()){AllRuleName=rule.CName;}else{AllRuleName+=","+rule.CName;}}Session.Value+="^"+AllRuleName;return Helper.Object2Json(retList);}/*** 计算一个项目浓度的月报数据* @param StartDate 开始日期* @param EndDate 结束日期* @param MaterialDR 质控物* @param TestCodeDR 项目* @param LevelNo 浓度* @param PointType 点类型* @param isQCMap 是否是质控画图,画图不需要计算失控处理率相关东西* @return 计算数据* @throws Exception*/public List<HashMap> CalOneMonthData(int StartDate,int EndDate,int MaterialDR,int TestCodeDR,int LevelNo,String PointType,boolean isQCMap) throws Exception {//返回的数据List<HashMap> retList=new ArrayList<>();//往前推一年取数据算累计数据int accStartData=Helper.AddDays(StartDate,-365);HashParam hs=new HashParam();hs.Add("MaterialDR",MaterialDR);hs.Add("TestCodeDR",TestCodeDR);hs.Add("LevelNo",LevelNo);hs.Add("TestDate",accStartData);hs.Add("TestDate",EndDate);List<String> operater=new ArrayList<>();operater.add("=");operater.add("=");operater.add("=");operater.add(">");operater.add("<=");//查询结果List<QCTestResultDto> resList=EntityManager().FindAllSimple(QCTestResultDto.class,hs,"TestDate asc,TestTime asc",-1,null,operater);//筛选点类型数据resList=FilterDataByPointType(resList,PointType);//按批号分别计算HashMap<String,CalDto> calMap=new HashMap<>();//前一个计算键String preCalKey="";if(resList!=null&&resList.size()>0){for(int i=resList.size()-1;i>=0;i--){QCTestResultDto one=resList.get(i);//计算的键,相同的键算一批String calKey=one.RunPara.LotNo;//没维护批号的按靶值和SD相同的算if(calKey.isEmpty()){calKey=one.RunPara.Mean+"-"+one.RunPara.SD;}calKey=one.MaterialDR+"-"+one.TestCodeDR+"-"+one.LevelNo+"-"+calKey;//按计算键得到计算实体CalDto curCalDto=null;//创建新的计算实体if(!calMap.containsKey(calKey)){CalDto newCal=new CalDto();newCal.LastPara=one.RunPara;calMap.put(calKey,newCal);curCalDto=newCal;}else{curCalDto=calMap.get(calKey);}//查询是否有失控处理,质控图不统计失控处理率那些if((isQCMap!=true)&&(one.DQIV_Status.equals("R")||one.DQIV_Status.equals("W"))){HashParam hsTran=new HashParam();hsTran.Add("TestResultDR",one.RowID);if(EntityManager().CheckHasData(QCTestResultTransaction.class,hsTran,null,null)==true){one.HasDeal=true;}}//算本次信息if(one.TestDate>=StartDate){//加入月数据curCalDto.AddCalRes(one);preCalKey=calKey;}//小于开始日期的就是累计数据,如果和前一个计算键不同就说明批号不是一个,就不往前找了else if(one.TestDate<StartDate){if(!calKey.equals(preCalKey)){break;}}//加入累计数据curCalDto.AddAccRes(one);}//使用迭代器遍历计算数据Iterator<HashMap.Entry<String, CalDto>> iterator = calMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, CalDto> entry = iterator.next();HashMap calRes=entry.getValue().GetCalRes();//计算唯一键calRes.put("CalKey",entry.getKey());retList.add(calRes);}}return retList;}/*** 处理点范围* @param allData 所有数据* @param pointRange 点类型* @return 处理后的数据* @throws Exception*/public List<QCTestResultDto> FilterDataByPointType(List<QCTestResultDto> allData,String pointRange) throws Exception{//存处理后的数据List<QCTestResultDto> dealedData=new ArrayList<>();//1:所有质控点 2:去除排除点 6:所有在控点 11:去除平行点 12:仅平行点 4:去除复查点 10:只查最后一点//7:最好点连线 8:最后一点连线 9:只查最好点//辅助判断复查点HashMap redoMap=new HashMap();//最好点的图HashMap<String,QCTestResultDto> bestMap=new HashMap();HashMap<Integer, Boolean> bestRowIDMap=new HashMap();//最后点的图HashMap<String,QCTestResultDto> lastMap=new HashMap();HashMap<Integer, Boolean> lastRowIDMap=new HashMap();if(allData!=null&&allData.size()>0){for(QCTestResultDto one:allData){//不是数字的不参与if(!Helper.IsNumeric(one.Result)){continue;}//去除排除点if(pointRange.equals("2")&&one.ExcludeType.equals("2")){continue;}//仅平行点if(pointRange.equals("11")&&!one.IsParallel.equals("!")){continue;}//去除平行点if(pointRange.equals("12")&&one.IsParallel.equals("!")){continue;}//去除复查点if(pointRange.equals("4")&&redoMap.containsKey(one.LevelNo+"-"+one.TestDate)){continue;}//只查最后一点if(pointRange.equals("10")&&redoMap.containsKey(one.LevelNo+"-"+one.TestDate)){continue;}//取规则状态if(one.QCRulesDR!=null){BTQCRules ruleDto=EntityManager().DolerGet(BTQCRules.class,one.QCRulesDR);one.CurRuleStatus=ruleDto.Status;}//所有在控点if(pointRange.equals("6")&&one.CurRuleStatus.equals("R")){continue;}//当天第一个数据redoMap.put(one.LevelNo+"-"+one.TestDate,true);//参数QCResMaterialTestCode para=EntityManager().DolerGet(QCResMaterialTestCode.class,one.ResMaterialTestCodeDR);//结果和均值的差one.Offset=Math.abs(Convert.ToInt32(one.Result)-para.Mean);//找到最好结果if(!bestMap.containsKey(one.LevelNo+"-"+one.TestDate)){bestMap.put(one.LevelNo+"-"+one.TestDate,one);}else{QCTestResultDto pre=bestMap.get(one.LevelNo+"-"+one.TestDate);if(pre.Offset>one.Offset){bestMap.put(one.LevelNo+"-"+one.TestDate,one);}}//最后点lastMap.put(one.LevelNo+"-"+one.TestDate,one);one.RunPara=para;dealedData.add(one);}//转换成主键mapfor (Map.Entry<String,QCTestResultDto> entry : bestMap.entrySet()) {bestRowIDMap.put(entry.getValue().RowID,true);}//转换成主键mapfor (Map.Entry<String,QCTestResultDto> entry : lastMap.entrySet()) {lastRowIDMap.put(entry.getValue().RowID,true);}//第二次处理数据for(int i=0;i<dealedData.size();i++){QCTestResultDto one=dealedData.get(i);//只查最好点if(pointRange.equals("9")){if(!bestRowIDMap.containsKey(one.RowID)){dealedData.remove(i);i--;continue;}}//只查最后点if(pointRange.equals("10")){if(!lastRowIDMap.containsKey(one.RowID)){dealedData.remove(i);i--;continue;}}}}return dealedData;}/*** 返回到前台的数据实体*/public static class QCTestResultDto extends QCTestResult {/*** 运行参数*/public QCResMaterialTestCode RunPara;/*** 规则状态*/public String CurRuleStatus;/*** 结果和靶值的偏差*/public Double Offset;/*** 是否进行失控处理*/public Boolean HasDeal;}/*** 计算计算均值、SD、累计均值、SD用到的承载实体*/public static class CalDto{/*** 最后的参数*/public QCResMaterialTestCode LastPara;/*** 失控数*/private int CalLossNum=0;/*** 警告数*/private int CalWaringNum=0;/*** 处理数*/private int CalDealNum=0;/*** 警告处理数*/private int CalDealWNum=0;/*** 失控数*/private int AccLossNum=0;/*** 警告数*/private int AccWaringNum=0;/*** 处理数*/private int AccDealNum=0;/*** 警告处理数*/private int AccDealWNum=0;/*** 总和*/private Double CalSumTotal=0.0;/*** 平方和*/private Double CalQuadraticSum=0.0;/*** 数据数量*/private int CalNum=0;/*** 存计算的结果*/private List<Double> CalResList=new ArrayList<>();/*** 在控数据总和*/private Double CalInSumTotal=0.0;/*** 在控数据平方和*/private Double CalInQuadraticSum=0.0;/*** 在控数据数据数量*/private int CalInNum=0;/*** 在控数据存计算的结果*/private List<Double> CalInResList=new ArrayList<>();/*** 总和*/private Double AccSumTotal=0.0;/*** 平方和*/private Double AccQuadraticSum=0.0;/*** 数据数量*/private int AccNum=0;/*** 存计算的结果*/private List<Double> AccResList=new ArrayList<>();/*** 添加累计结果* @param one 质控结果*/public void AddAccRes(QCTestResultDto one){Double res=Convert.ToDouble(one.Result,LastPara.Precision);//累计只算非失控的if(!one.DQIV_Status.equals("R")){AccResList.add(res);AccSumTotal+=res;AccNum++;}}/*** 添加当前结果* @param one 质控结果*/public void AddCalRes(QCTestResultDto one){Double res=Convert.ToDouble(one.Result,LastPara.Precision);//失控数if(one.DQIV_Status.equals("R")) {CalLossNum++;if(one.HasDeal==true){CalDealNum++;}}//警告数else if(one.DQIV_Status.equals("W")) {CalWaringNum++;if(one.HasDeal==true){CalDealWNum++;}}CalResList.add(res);CalSumTotal+=res;CalNum++;//本月在控数据if(!one.DQIV_Status.equals("R")) {CalInResList.add(res);CalInSumTotal+=res;CalInNum++;}}/*** 计算月均值和累计均值等信息* @return*/public HashMap GetCalRes(){//依次返回:计算值:均值、SD、CV、Min、Max、Num、ResStr 累计值:均值、SD、CV、Min、Max、Num、ResStrHashMap hsRet=new HashMap();hsRet.put("CalLossNum",CalLossNum);hsRet.put("CalWaringNum",CalWaringNum);hsRet.put("CalDealNum",CalDealNum);if(CalNum>0) {hsRet.put("CalLossRate", CalLossNum / CalNum);}else{hsRet.put("CalLossRate", "");}if(CalLossNum>0) {hsRet.put("CalDealRate", CalDealNum / CalLossNum);}else{hsRet.put("CalDealRate", "");}if(CalLossNum>0) {hsRet.put("CalWaringRate", CalWaringNum / CalNum);}else{hsRet.put("CalWaringRate", "");}if(CalWaringNum>0) {hsRet.put("CalDealWRate", CalDealWNum / CalWaringNum);}else{hsRet.put("CalDealWRate", "");}hsRet.put("CalMean","");hsRet.put("CalSD","");hsRet.put("CalCV","");hsRet.put("CalMin","");hsRet.put("CalMax","");hsRet.put("CalNum","");hsRet.put("CalResStr","");hsRet.put("CalInMean","");hsRet.put("CalInSD","");hsRet.put("CalInCV","");hsRet.put("CalInMin","");hsRet.put("CalInMax","");hsRet.put("CalInNum","");hsRet.put("CalInResStr","");hsRet.put("AccMean","");hsRet.put("AccSD","");hsRet.put("AccCV","");hsRet.put("AccMin","");hsRet.put("AccMax","");hsRet.put("AccNum","");hsRet.put("AccResStr","");hsRet.put("LastPara",LastPara);if(CalNum>1) {Double calAve = Convert.ToDouble(CalSumTotal / CalNum,LastPara.Precision);if(calAve>0) {Double maxVal=CalResList.get(0);Double minVal=CalResList.get(0);StringBuilder allResSB=new StringBuilder();int index=-1;for (Double res : CalResList) {CalQuadraticSum += (res - calAve) * (res - calAve);if(maxVal<res){maxVal=res;}if(minVal>res){minVal=res;}index++;if(index==0){allResSB.append(String.valueOf(res));}else{allResSB.append(","+String.valueOf(res));}}Double SD = Convert.ToDouble(Math.sqrt(CalQuadraticSum / (CalNum - 1)),LastPara.Precision);Double CV = Convert.ToDouble(SD / calAve * 100,LastPara.Precision);hsRet.put("CalMean",Helper.FormatNumber(calAve,LastPara.Precision));hsRet.put("CalSD",Helper.FormatNumber(SD,LastPara.Precision));hsRet.put("CalCV",Helper.FormatNumber(CV,LastPara.Precision));hsRet.put("CalMin",Helper.FormatNumber(minVal,LastPara.Precision));hsRet.put("CalMax",Helper.FormatNumber(maxVal,LastPara.Precision));hsRet.put("CalNum",String.valueOf(CalNum));hsRet.put("CalResStr",allResSB.toString());}}if(CalInNum>1) {Double calAve = Convert.ToDouble(CalInSumTotal / CalInNum,LastPara.Precision);if(calAve>0) {Double maxVal=CalInResList.get(0);Double minVal=CalInResList.get(0);StringBuilder allResSB=new StringBuilder();int index=-1;for (Double res : CalInResList) {CalInQuadraticSum += (res - calAve) * (res - calAve);if(maxVal<res){maxVal=res;}if(minVal>res){minVal=res;}index++;if(index==0){allResSB.append(String.valueOf(res));}else{allResSB.append(","+String.valueOf(res));}}Double SD = Convert.ToDouble(Math.sqrt(CalQuadraticSum / (CalNum - 1)),LastPara.Precision);Double CV = Convert.ToDouble(SD / calAve * 100,LastPara.Precision);hsRet.put("CalInMean",Helper.FormatNumber(calAve,LastPara.Precision));hsRet.put("CalInSD",Helper.FormatNumber(SD,LastPara.Precision));hsRet.put("CalInCV",Helper.FormatNumber(CV,LastPara.Precision));hsRet.put("CalInMin",Helper.FormatNumber(minVal,LastPara.Precision));hsRet.put("CalInMax",Helper.FormatNumber(maxVal,LastPara.Precision));hsRet.put("CalInNum",String.valueOf(CalInNum));hsRet.put("CalInResStr",allResSB.toString());}}if(AccNum>1) {Double accAve = Convert.ToDouble(AccSumTotal / AccNum,LastPara.Precision);if(accAve>0) {Double maxVal=AccResList.get(0);Double minVal=AccResList.get(0);StringBuilder allResSB=new StringBuilder();int index=-1;for (Double res : AccResList) {AccQuadraticSum += (res - accAve) * (res - accAve);if(maxVal<res){maxVal=res;}if(minVal>res){minVal=res;}index++;if(index==0){allResSB.append(String.valueOf(res));}else{allResSB.append(","+String.valueOf(res));}}Double SD = Convert.ToDouble(Math.sqrt(AccQuadraticSum / (AccNum - 1)),LastPara.Precision);Double CV = Convert.ToDouble(SD / accAve * 100,LastPara.Precision);hsRet.put("AccMean",Helper.FormatNumber(accAve,LastPara.Precision));hsRet.put("AccSD",Helper.FormatNumber(SD,LastPara.Precision));hsRet.put("AccCV",Helper.FormatNumber(CV,LastPara.Precision));hsRet.put("AccMin",Helper.FormatNumber(minVal,LastPara.Precision));hsRet.put("AccMax",Helper.FormatNumber(maxVal,LastPara.Precision));hsRet.put("AccNum",String.valueOf(CalNum));hsRet.put("AccResStr",allResSB.toString());}}return hsRet;}}/*** 查询质控浓度数据** @return*/public String QueryQCLeaveData() throws Exception {int MaterialDR = Helper.ValidParam(JRTContext.GetRequest(Request, "MaterialDR"), 0);List<BTQCMaterialLevel> retList = EntityManager().FindByColVal(BTQCMaterialLevel.class, "MaterialDR", MaterialDR);return Helper.Object2Json(retList);}/*** 查询仪器的批号* @return* @throws Exception*/public String QryMachineLot() throws Exception{//返回的数据List<String> retData = new ArrayList<>();int MachineParameterDR = Helper.ValidParam(JRTContext.GetRequest(Request,"MachineParameterDR"), 0);String MaterialDR = Helper.ValidParam(JRTContext.GetRequest(Request,"MaterialDR"), "");int StartDate = Helper.ValidParam(JRTContext.GetRequest(Request,"StartDate"), 0);int EndDate = Helper.ValidParam(JRTContext.GetRequest(Request,"EndDate"), 0);//查询仪器的所有质控物List<BTQCMaterial> matList=EntityManager().FindByColVal(BTQCMaterial.class,"MachineDR",MachineParameterDR);//查询每个质控物下的项目for(BTQCMaterial mat:matList) {List<String> operators = new ArrayList<>();HashParam hs = new HashParam();hs.Add("MaterialDR", mat.RowID);operators.add("=");hs.Add("StartDate", StartDate);operators.add("<=");//先找小于开始日期的最近数据List<BTQCMaterialTestCode> lastData = EntityManager().FindAllSimple(BTQCMaterialTestCode.class, hs, "StartDate desc", 1, null, operators);//然后安装最近开始日期和结束日期找模板数据List<String> operatorsFind = new ArrayList<>();HashParam hsFind = new HashParam();hsFind.Add("MaterialDR", mat.RowID);operatorsFind.add("=");//结束日期hsFind.Add("StartDate", EndDate);operatorsFind.add("<=");List<String> joinerFind = new ArrayList<>();if (lastData != null && lastData.size() > 0) {joinerFind.add("and");operatorsFind.add(">=");//开始日期hsFind.Add("StartDate", lastData.get(0).StartDate);}//目标数据List<BTQCMaterialTestCodeDto> perData = EntityManager().FindAllSimple(BTQCMaterialTestCodeDto.class, hsFind, "StartDate asc", -1, joinerFind, operatorsFind);HashMap map = new HashMap();if (perData != null && perData.size() > 0) {for (BTQCMaterialTestCodeDto one : perData) {if (!map.containsKey(one.LotNo)) {retData.add(one.LotNo);map.put(one.LotNo, true);}}}}return Helper.Object2Json(retData);}/*** 查询工作组数据** @return*/public String QueryWorkGroupData() throws Exception {//得到用户的角色List<SYSUserRoleDto> roleList = EntityManager().FindByColVal(SYSUserRoleDto.class, "UserDR", Convert.ToInt32(UserLogin().UserID));if (roleList != null && roleList.size() > 0) {for (SYSUserRoleDto one : roleList) {BTWorkGroup wgDto = EntityManager().DolerGet(BTWorkGroup.class, one.WorkGroupDR);one.WorkGroupName = wgDto.CName;one.CurWorkGroupDR = UserLogin().GroupID;}}return Helper.Object2Json(roleList);}/*** 查询仪器** @return*/public String QryMachineParameter() throws Exception {int WorkGroupDR = Helper.ValidParam(JRTContext.GetRequest(Request, "WorkGroupDR"), 0);List<BTWorkGroupMachine> wgmList = EntityManager().FindByColVal(BTWorkGroupMachine.class, "WorkGroupDR", WorkGroupDR);List<BTMIMachineParameter> retList = new ArrayList<>();if (wgmList != null && wgmList.size() > 0) {for (BTWorkGroupMachine wgm : wgmList) {//查询工作小组下的所有仪器List<BTMIMachineParameter> machList = EntityManager().FindByColVal(BTMIMachineParameter.class, "WorkGroupMachineDR", wgm.RowID);retList.addAll(machList);}}return Helper.Object2Json(retList);}/*** 查询仪器项目** @return*/public String QryMachineTestCode() throws Exception {int MachineParameterDR = Helper.ValidParam(JRTContext.GetRequest(Request, "MachineParameterDR"), 0);int StartDate = Helper.ValidParam(JRTContext.GetRequest(Request, "StartDate"), 0);int EndDate = Helper.ValidParam(JRTContext.GetRequest(Request, "EndDate"), 0);//返回的数据List<BTQCMaterialTestCodeDto> retData = new ArrayList<>();//查询仪器的所有质控物List<BTQCMaterial> matList=EntityManager().FindByColVal(BTQCMaterial.class,"MachineDR",MachineParameterDR);//查询每个质控物下的项目for(BTQCMaterial mat:matList) {List<String> operators = new ArrayList<>();HashParam hs = new HashParam();hs.Add("MaterialDR", mat.RowID);operators.add("=");hs.Add("StartDate", StartDate);operators.add("<=");//先找小于开始日期的最近数据List<BTQCMaterialTestCode> lastData = EntityManager().FindAllSimple(BTQCMaterialTestCode.class, hs, "StartDate desc", 1, null, operators);List<String> operatorsFind = new ArrayList<>();//然后安装最近开始日期和结束日期找模板数据HashParam hsFind = new HashParam();hsFind.Add("MaterialDR", mat.RowID);operatorsFind.add("=");//结束日期hsFind.Add("StartDate", EndDate);operatorsFind.add("<=");List<String> joinerFind = new ArrayList<>();if (lastData != null && lastData.size() > 0) {joinerFind.add("and");operatorsFind.add(">=");//开始日期hsFind.Add("StartDate", lastData.get(0).StartDate);}//目标数据List<BTQCMaterialTestCodeDto> perData = EntityManager().FindAllSimple(BTQCMaterialTestCodeDto.class, hsFind, "StartDate asc", -1, joinerFind, operatorsFind);HashMap map = new HashMap();if (perData != null && perData.size() > 0) {for (BTQCMaterialTestCodeDto one : perData) {BTQCMaterial matDto = EntityManager().DolerGet(BTQCMaterial.class, one.MaterialDR);one.MaterialName = matDto.CName;BTTestCode tsDto = EntityManager().DolerGet(BTTestCode.class, one.TestCodeDR);one.CName = tsDto.CName;one.Code = tsDto.Code;one.Synonym = tsDto.Synonym;if (!map.containsKey(one.MaterialDR + "-" + one.TestCodeDR)) {retData.add(one);map.put(one.MaterialDR + "-" + one.TestCodeDR, true);}}}}return Helper.Object2Json(retData);}/*** 月报查询返回的实体*/public static class QCMonthRetDto extends QCResMaterialTestCode{/*** 月报是否通过,月CV小于目标CV就是通过*/public String IsQualified="";/*** 质控物名称*/public String MatName="";/*** 年月*/public String YearMonth="";/*** 项目缩小*/public String Synonym="";/*** 项目名称*/public String TCName="";/*** 浓度名称*/public String LevelName="";/*** 计算均值*/public String CalMean="";/*** 计算SD*/public String CalSD="";/*** 计算CV*/public String CalCV="";/*** 计算最小值*/public String CalMin="";/*** 计算最大值*/public String CalMax="";/*** 计算数量*/public String CalNum="";/*** 计算结果串*/public String CalResStr="";/*** 在控数据计算均值*/public String CalInMean="";/*** 在控数据计算SD*/public String CalInSD="";/*** 在控数据计算CV*/public String CalInCV="";/*** 在控数据计算最小值*/public String CalInMin="";/*** 在控数据计算最大值*/public String CalInMax="";/*** 在控数据计算数量*/public String CalInNum="";/*** 在控数据计算结果串*/public String CalInResStr="";/*** 累计均值*/public String AccMean="";/*** 累计SD*/public String AccSD="";/*** 累计CV*/public String AccCV="";/*** 累计最小*/public String AccMin="";/*** 累计最大*/public String AccMax="";/*** 累计数量*/public String AccNum="";/*** 累计结果串*/public String AccResStr="";/*** 失控数量*/public String CalLossNum="";/*** 警告数量*/public String CalWaringNum="";/*** 处理数量*/public String CalDealNum="";/*** 失控率*/public String CalLossRate="";/*** 处理率*/public String CalDealRate="";/*** 警告率*/public String CalWaringRate="";/*** 警告处理率*/public String CalDealWRate="";}/*** 查询批次项目实体*/public static class BTQCMaterialTestCodeDto extends BTQCMaterialTestCode {/*** 质控物名称*/public String MaterialName="";/*** 项目名称*/public String CName="";/*** 项目缩写*/public String Synonym="";/*** 项目代码*/public String Code="";}/*** 角色查询实体*/public static class SYSUserRoleDto extends SYSUserRole {//工作组名称public String WorkGroupName="";//当前工作组public String CurWorkGroupDR="";}
}