JRT1.6发布

经过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="";
    }
}

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乌鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值