经过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>() {
            @Override
            public 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,一个超过-2S
                        if(numPos==1&&numNeg==1)
                        {
                            hasUpdateRule=true;
                            //更新质控规则
                            UpdateRule(res,rule,lazyUpdataMap);
                            //终止判断
                            if(rule.IsEnd==true)
                            {
                                break;
                            }
                        }
                        //或者同一天不同浓度的超过±2S
                        else
                        {
                            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或-1s
                        if(numPos==4||numNeg==4)
                        {
                            int numPos2S=CheckSameSide(resList,i,4,2.0,true);
                            int numNeg2S=CheckSameSide(resList,i,4,-2.0,false);
                            //有一个点大于1-2S
                            if(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或-1s
                        if(numPos==3||numNeg==3)
                        {
                            int numPos2S=CheckSameSide(resList,i,3,2.0,true);
                            int numNeg2S=CheckSameSide(resList,i,3,-2.0,false);
                            //有一个点大于1-2S
                            if(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-2S
                            if(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-2S
                            if(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-2S
                            if(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-2S
                            if(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);
            }
            //转换成主键map
            for (Map.Entry<String,QCTestResultDto> entry : bestMap.entrySet()) {
                bestRowIDMap.put(entry.getValue().RowID,true);
            }
            //转换成主键map
            for (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);
            }
            //转换成主键map
            for (Map.Entry<String,QCTestResultDto> entry : bestMap.entrySet()) {
                bestRowIDMap.put(entry.getValue().RowID,true);
            }
            //转换成主键map
            for (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、ResStr
            HashMap 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="";
    }
}
                

![从零开始学RSA: [WUSTCTF2020]情书等5题](https://img-blog.csdnimg.cn/direct/51bd0d35ea2a484c8d4a692c8333ac28.bmp#pic_center)
















