JRT1.6发布

news2024/12/28 3:06:20

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1646017.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

调用第三方接口——支付宝付款

沙箱环境是支付宝开放平台为开发者提供的用于接口开发及主要功能联调的模拟环境。 参考 登录 - 支付宝 在沙箱环境下&#xff0c;已经分配好了用于模拟测试的应用信息、商家信息、买家信息等 小程序文档 - 支付宝文档中心 内网穿透&#xff08;支付宝付款需要在公网进行检查…

谁能取代迈巴赫,征服互联网安全大佬周鸿祎?

‍作者 |老缅 编辑 |德新 4月18日&#xff0c;「周鸿祎卖车」登上了微博热搜。这位360创始人、董事长发微博称&#xff1a;自己做了一个艰难的决定&#xff0c;将把陪伴9年的迈巴赫600给卖掉。 随后&#xff0c;他解释道&#xff1a;「这是因为我需要体验新一代车的感觉。古人…

从零开始学RSA: [WUSTCTF2020]情书等5题

1 [WUSTCTF2020]情书 题目 Premise: Enumerate the alphabet by 0、1、2、..... 、25 Using the RSA system Encryption:0156 0821 1616 0041 0140 2130 1616 0793 Public Key:2537 and 13 Private Key:2537 and 937flag: wctf2020{Decryption}解题 前提&#xff1a;用0、…

C++初阶学习第五弹——类与对象(下)——类与对象的收官战

类与对象&#xff08;上&#xff09;&#xff1a;C初阶学习第三弹——类与对象&#xff08;上&#xff09;——初始类与对象-CSDN博客 类与对象&#xff08;中&#xff09;&#xff1a;C初阶学习第四弹——类与对象&#xff08;中&#xff09;——刨析类与对象的核心点-CSDN博…

Linux环境下的事件驱动力量:探索Libevent的高性能I/O架构

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的Linux高性能服务器编程系列之《Linux环境下的事件驱动力量&#xff1a;探索Libevent的高性能I/O架构》&#xff0c;在这篇文章中&#xff0c;你将会学习到Libevent的高性能I/O原理以及应用&#xff0c;并且我会给出源码…

攻防世界-xff-referer

题目信息 分析过程 显示ip必须为123.123.123.123&#xff0c;则进行伪造 解题过程 打开repeator 提示必须来自https://www.google.com&#xff0c;则再次构造Referer 相关知识 x-forwarded-for 和 referer的区别: x-forwarded-for 用来证明ip的像是“127.0.0.1”这种&a…

为什么感觉没有效果

以前在辅导小儿作业的时候&#xff0c;我会在常用的搜索引擎里去寻找答案&#xff0c;一般情况下都能解决问题。 但是最近一段时间&#xff0c;我发现&#xff0c;搜索引擎搜出来的结果还没有利用短视频搜出来的答案更全面&#xff0c;短视频软件不仅可以显示AI整理出来的答案…

“先锋”西凤

执笔 | 文 清 编辑 | 古利特 制曲是酿酒的第一道工序&#xff0c;也是中国酿酒史上的一大创新&#xff0c;对白酒风味的影响至关重要。西凤酿酒人坚信“曲是酒之骨”&#xff0c;“曲”的品质决定酒的“骨气”&#xff0c;“酒曲”是酒体形成主题风味的基本定型元素和催化剂…

5分钟学会掼蛋

一、基本规则 1、用牌&#xff1a;总计108张&#xff0c;每人发牌27张。 2、牌型&#xff1a;八炸弹、七炸弹、六炸弹、五炸弹、四炸弹、天王炸、同花顺、顺子、钢板、三同张、三带二、单牌、对牌、三连对&#xff0c;注意掼蛋没有三带一的牌型。3、牌型大小&#xff1a;天王炸…

跟TED演讲学英文:What moral decisions should driverless cars make by Iyad Rahwan

What moral decisions should driverless cars make? Link: https://www.ted.com/talks/iyad_rahwan_what_moral_decisions_should_driverless_cars_make Speaker: Iyad Rahwan Date: September 2016 文章目录 What moral decisions should driverless cars make?Introduct…

electron 通信总结

默认开启上下文隔离的情况下 渲染进程调用主进程方法&#xff1a; 主进程 在 main.js 中&#xff0c; 使用 ipcMain.handle&#xff0c;添加要处理的主进程方法 const { ipcMain } require("electron"); 在 electron 中创建 preload.ts 文件&#xff0c;从 ele…

LangChain框架学习总结

目录 一、简介 二、概念 三、组件具体介绍 3.1 Models 3.1.1 LLMs 3.1.2 Chat Models 3.1.3 Text Embedding Modesl 3.1.4 总结 3.2 Prompts 3.2.1 LLM Prompt Template 3.2.1.1 自定义PromptTemplate 3.2.1.2 partial PromptTemplate 3.2.1.3 序列化PromptTemplat…

Python使用割圆法求π值

三国时期刘徽提出的割圆法有多牛掰&#xff0c;看这个&#xff1a;刘徽割圆术到底做了什么&#xff1f; - 知乎 用Python实现的该算法代码如下&#xff1a; #!/usr/bin/env python """使用割圆法计算π值Usage::$ python calc_circle_pi.py 20 # 参数20是迭代…

【Kubernetes系统与CKA(D)考试经验】

文章目录 应用程序部署模式的发展历程传统部署模式虚拟化部署模式容器部署模式容器部署模式的好处容器部署的弊端 容器编排Kubernetes网址Kubernetes架构互联网架构体系云原生&#xff08;微服务容器化Devops不可变基础设施&#xff09;Kubernetes架构Kubernetes组件 Kubernete…

【Docker】★★★

docker 的网络模式 ●host模式&#xff1a;使用 --nethost 指定 容器与宿主机共享网络命名空间、ip和端口 ●container模式&#xff1a;使用 --netcontainer:NAME_or_ID 指定 新建的容器共享已有容器的网络命名空间、ip和端口 ●none模式&#xff1a;使用 --netnone 指定 不进行…

数据结构——链表专题2

文章目录 一、返回倒数第k 个节点二、链表的回文结构三、相交链表 一、返回倒数第k 个节点 原题链接&#xff1a;返回倒数第k 个节点 利用快慢指针的方法&#xff1a;先让fast走k步&#xff0c;然后fast和slow一起走&#xff0c;直到fast为空&#xff0c;最后slow指向的结点就…

如何利用现货黄金避险功能来交易?

黄金自古以来就是投资者青睐的具有规避风险功能的投资品种&#xff0c;现货黄金作为以黄金为投资标的物的品种&#xff0c;自然也具备了规避风险的功能。如果出现了风险事件&#xff0c;避险情绪会为现货黄金带来颇为可观的行情&#xff0c;所以我们需要懂得如何利用现货黄金的…

智能AI摄像头项目

项目概要 硬件说明&#xff1a;易百纳rv1126 38板&#xff0c;易百纳GC2053摄像头&#xff0c;拓展版&#xff08;自绘&#xff09;&#xff0c;屏幕驱动板&#xff08;自绘&#xff09;&#xff0c;3.1inch mipi屏&#xff0c;FT5316触摸屏 开发环境 硬件分析 开发环境及sd…

代码随想录训练营31day-动态规划4

一、完全背包&#xff08;参考博客&#xff09; 和01背包区别在于物品可以无限次放入背包。完全背包和01背包问题唯一不同的地方就是&#xff0c;每种物品有无限件。 因此在需要在遍历顺序上进行区别&#xff0c;参考代码随想录&#xff1a; 二、518.零钱兑换II 题目求的是组…

光端机(2)——光纤通信学习笔记九

学习笔记里面只关注基本原理和概念&#xff0c;复杂的公式和推导都没有涉及 光端机 光发射机 作用&#xff1a;实现电光转换。将来自电端机的电信号对光源发出的光波进行调制&#xff0c;然后将调制好的光信号耦合到光线中传输。 基本性能要求 1.合适的发光波长&#xff08;光…