package com.yonyou.hrcloud.pm.ps.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.yonyou.hrcloud.pm.base.model.Column;
import com.yonyou.hrcloud.pm.base.model.Indicator;
import com.yonyou.hrcloud.pm.base.model.IndicatorClass;
import com.yonyou.hrcloud.pm.ps.model.*;
import com.yonyou.hrcloud.pm.ps.service.*;
import com.yonyou.hrcloud.pm.result.dao.IAdjustScoreDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import com.alibaba.fastjson.JSONObject;
import com.yonyou.hrcloud.adder.context.AppContext;
import com.yonyou.hrcloud.adder.exception.AdderBusinessException;
import com.yonyou.hrcloud.adder.model.param.PagerRequest;
import com.yonyou.hrcloud.adder.model.param.Sorter;
import com.yonyou.hrcloud.adder.model.query.Condition;
import com.yonyou.hrcloud.adder.model.query.Operator;
import com.yonyou.hrcloud.adder.model.query.SqlExpression;
import com.yonyou.hrcloud.adder.service.IGenericService;
import com.yonyou.hrcloud.commons.org.model.CommonOrg;
import com.yonyou.hrcloud.pm.base.model.Period;
import com.yonyou.hrcloud.pm.base.service.IRemindService;
import com.yonyou.hrcloud.pm.common.model.CommonValue;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumAuditType;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumColumnType;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumMarkState10;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumSchemeScoreColumnCode;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumWorkStep;
import com.yonyou.hrcloud.pm.common.model.PmStaff;
import com.yonyou.hrcloud.pm.helper.ListHelper;
import com.yonyou.hrcloud.pm.helper.OrgHelper;
import com.yonyou.hrcloud.pm.helper.StaffHelper;
import com.yonyou.hrcloud.pm.helper.Systemutil;
import com.yonyou.hrcloud.pm.helper.Toolkit;
import com.yonyou.hrcloud.pm.helper.WorkflowHelper;
import com.yonyou.hrcloud.pm.ia.service.ISheetSettingService;
import com.yonyou.hrcloud.pm.manage.service.ISystemManagService;
import com.yonyou.hrcloud.pm.notice.model.NoticeExtendParam;
import com.yonyou.hrcloud.pm.notice.service.INoticeFactoryService;
import com.yonyou.hrcloud.pm.pa.dao.IAppraiseDao;
import com.yonyou.hrcloud.pm.pa.model.Appraise;
import com.yonyou.hrcloud.pm.pa.model.AppraiseData;
import com.yonyou.hrcloud.pm.pa.service.IAppraiseService;
import com.yonyou.hrcloud.pm.ps.dao.IOperationDao;
import com.yonyou.hrcloud.pm.result.dao.IApproveScoreDao;
import com.yonyou.hrcloud.pm.result.model.ApproveScore;
import com.yonyou.hrcloud.pm.result.model.ResultConfirm;
import com.yonyou.hrcloud.pm.result.model.Score;
import com.yonyou.hrcloud.pm.result.service.IResultComfirmService;
import com.yonyou.hrcloud.pm.result.service.ISummaryScoreService;
import com.yonyou.hrcloud.pm.wf.model.BaseParam;
import com.yonyou.hrcloud.pm.wf.model.Workflow;
import com.yonyou.hrcloud.pm.wf.model.WorkflowEngine;
import com.yonyou.hrcloud.pm.wf.model.WorkflowParam;
import com.yonyou.hrcloud.pm.wf.model.WorkflowStep;
import com.yonyou.hrcloud.pm.wf.service.IWorkflowBaseService;
import com.yonyou.hrcloud.pm.wf.service.IWorkflowService;

import com.yonyou.iuap.utils.PropertyUtil;

/**
 * 操作流程实现层
 *
 * @author Flysea
 */
@Service
@Transactional
public class OperationServiceImpl implements IOperationService {

    @Resource
    public IGenericService daoex;

    @Resource
    public ISchemeService schemeService;

    @Resource
	public IOperationDao operationDao;

    @Resource
    public IEvaGroupService daoGroup;

    @Resource
    public ISheetService sheetService;

    @Resource
    public IApproveScoreDao daoAppScore;

    @Resource
    public IAppraiseDao daoAppraise;

    @Resource
    public IWorkflowService wfSrv;

    @Resource
    public IWorkflowBaseService wfbService;

    @Resource
    public IAppraiseService apprService;

    @Resource
    public INoticeFactoryService fService;

    @Resource
	ISyncResultService syncResultSrv;

    @Resource
    IResultSettingService resultSettingService;
    
    @Resource
    ISheetSettingService sheetSettingService;
    
    @Resource
    IOperationGaugeService gaugeService;
    
    @Resource
    ISchemeGaugeService schemeGaugeService;
    
	@Resource
	IRemindService remindService;

	@Resource
    IExcelService excelService;

    @Resource
    IOperationPartialService op2Srv;

    @Resource
    ISummaryScoreService sumSrv;

    @Resource
    IResultComfirmService confirmService;

    @Resource
    private IAdjustScoreDao adjustScoreDao;

	@Resource
	private ISystemManagService sysService;

    protected static final Logger logger = LoggerFactory.getLogger(OperationServiceImpl.class);
    
	@Override
	public void delete(String id) {
		List<Scheme> objs = daoex.findByIds(Scheme.class, id);
		if (objs.size() > 0) {
			Scheme obj = objs.get(0);
			Condition cond = new Condition();
			cond.addExpression("schemeid", obj.getId());
			List<ApproverGroup> approverGroups = resultSettingService.queryApproverGroupByConditon(cond, null);
			if (approverGroups != null && approverGroups.size() > 0)
				throw new AdderBusinessException("方案已存在于考核结果审核规则中，不可以删除", "pm.i18n_pbc.ps.015");
			if (obj.getSchemestate() == CommonValue.EnumSchemeState.State2.ordinal()) {
				// 方案状态是设置中，且没有指标填报数据则可以删除
				if (!haveSheetData(id)) {
					wfSrv.delWorkflow(obj.getId());
					//中期回顾方案删除关联表数据
					if(obj.getSchememode() == CommonValue.EnumSchemeMode.pm_mtr.getIndex()){
						Condition relationCondition = new Condition();
						relationCondition.addExpression("formulaschemeid",obj.getId());
						relationCondition.addExpression("formulaschememode",CommonValue.EnumSchemeMode.pm_mtr.getIndex());
						List<SchemeRelation> relationList = daoex.find(SchemeRelation.class, relationCondition, null);
						if(CollectionUtils.isNotEmpty(relationList)){
							relationList.forEach(relation->daoex.delete(SchemeRelation.class,relation.getId()));
						}
					}
					schemeService.delete(id);
				} else if (!obj.isIsallowfillup()) {
					throw new AdderBusinessException("请先删除考核对象", "pm.i18n_pbc.ps.025");
				} else
					throw new AdderBusinessException("方案已填报，不可以删除", "pm.i18n_pbc.ps.016");
			}
		}
	}

    @Override
	public void submit(Scheme scheme) {
		// scheme是完整的，校验方案
		gaugeService.checkScheme(scheme);
		scheme.setSchemestate(CommonValue.EnumSchemeState.State1.getIndex());
		scheme.setFdate(new Date());
		if (!daoex.update(scheme))
			throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
		// 生成初始量表
		doInitSheet(scheme, true);
		// 2019-5-16新增按公共量表创建
		schemeGaugeService.createIndiOnStartScheme(scheme);
		// 创建工作流
		Workflow wf = wfSrv.queryWorkflowByBizid(scheme.getId());
		if (wf == null)
			wf = WorkflowHelper.createPMWorkflow(scheme.getId(), scheme.getSchemename());
		List<WorkflowStep> oWorkflowStep = new ArrayList<WorkflowStep>();
		List<EvaAppraiser> approves = new ArrayList<EvaAppraiser>();
		// 轮次已经在querySchemeByID排好序
		int nowTurn = 1;
		for (EvaAppraiser item : scheme.getOEvaAppraiser()) {
			// 筛选指标审核，并重排顺序
			if (item.getIsapprove()) {
				EvaAppraiser t;
				try {
					t = (EvaAppraiser) item.clone();
					t.setTurn(nowTurn);
					approves.add(t);
				} catch (CloneNotSupportedException e) {
					logger.error(e.getMessage());
				}
				nowTurn++;
			}
		}
		for (EvaAppraiser item : approves) {
			// 生成指标审核工作流步骤
			oWorkflowStep.add(WorkflowHelper.createPMWorkflowStep(item, EnumWorkStep.step1, 1));
		}
		for (EvaAppraiser item : scheme.getOEvaAppraiser()) {
			// 生成评价工作流步骤
			int workStepOrder = 2;
			if (approves.size() == 0)
				workStepOrder = 1;
			logger.debug("pm: createPMWorkflowStep " + JSONObject.toJSONString(item));
			oWorkflowStep.add(WorkflowHelper.createPMWorkflowStep(item, EnumWorkStep.step2, workStepOrder));
		}
		wf.setOWorkflowStep(oWorkflowStep);
		try {
			wfSrv.createWorkflow(wf);
		} catch (DuplicateKeyException e) {
			throw new AdderBusinessException("考核流程中有重复的考核人", "pm.i18n_pbc.ps.002");
		}
		
		// 2019-5-16如不允许员工填报，则需要创建考核人工作流，此时量表的信息已创建
		if (!scheme.isIsallowfillup() && scheme.getIndisource() != CommonValue.EnumIndiSource.issued.getIndex()) {
			// 此处生成流程的好处可以校验数据是否正确，在开始评分生成有点晚了
			Condition appr_cond = new Condition();
			appr_cond.addExpression("schemeid", scheme.getId());
			appr_cond.addExpression("enablestate", true);
			List<Sheet> sheetlist = daoex.find(Sheet.class, appr_cond, null);
			for (Sheet sheet : sheetlist) {
				sheetSettingService.delWorkflowEngnie(sheet.getId());
				// modify by zengcl 导入结果数据 不需要考核人工作流
				if(!scheme.isIsimportresult()) {
					sheetSettingService.createAppraiserWorkflow(scheme, sheet);
				}
//						sheetSettingService.createAppraiserWorkflow(scheme, sheet);
				// 修改量表状态
				sheet.setMarkStatus(EnumMarkState10.State4.getIndex());
				sheet.setIsaudit(true);
				daoex.update(sheet);
			}
		}
	}

	@Override
    public void cancelSubmit(Scheme scheme) {
        scheme.setSchemestate(CommonValue.EnumSchemeState.State2.ordinal());
        scheme.setFdate(null);
        daoex.update(scheme);
    }

	@Override
	public void completing(Scheme scheme) {
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State1.getIndex())
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if (!scheme.isIsallowfillup() && scheme.getIndisource() == CommonValue.EnumIndiSource.hrfill.getIndex())
			throw new AdderBusinessException("方案已设置为不允许员工填报", "pm.i18n_pbc.ps.019");
		// 发送开始填报消息
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		condObj.addExpression("mark_status", CommonValue.EnumMarkState10.State2.getIndex(), Operator.LESS);
		condObj.addExpression("enablestate", true);
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		List<String> staffids = new ArrayList<String>();
		for (Sheet item : sheetList) {
			staffids.add(item.getStaffid());
			if (scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex()) {
				item.setMarkStatus(CommonValue.EnumMarkState10.State3.getIndex());
				daoex.update(item, Arrays.asList("markStatus"));
			}
		}

		scheme.setSchemestate(CommonValue.EnumSchemeState.State3.getIndex());
		if (!daoex.update(scheme))
			throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
		if (!scheme.isIsallowfillup())
			return;
		if (staffids.size() > 0) {
			// 对方案下量表，发送通知
			logger.debug("#######pm completing 方案{}共需发送{}等共{}个通知", scheme.getSchemename(), staffids.get(0),
					staffids.size());
			/*
			 * NoticeExtendParam ep = new NoticeExtendParam("", scheme.getId(), staffids,
			 * CommonValue.EnumSendNoticeType.NOTICE);
			 */

			// 只发送通知类型消息，接受到消息里没有连接，所以改为发应用消息。
			NoticeExtendParam ep = new NoticeExtendParam();
			ep.title = "指标填报";
			ep.staffIds = staffids;
			ep.schemeId = scheme.getId();
			// 2019-5-6平台更换门户，造成消息通知不能跳转，改为代办任务
			ep.sendTodoNotice = true;
			ep.businessKey = "indiFill_" + scheme.getId();
			try {
				fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIFILL, ep);
				// sendNotice(scheme.getId(), staffids, 0, null);
			} catch (Exception e) {
				logger.error("pm:completing ", e);
			}
		} else
			logger.error("#######pm completing 方案{}无需发送通知", scheme.getSchemename());
	}

    @Override
	public List<PmStaff> completed(Scheme scheme, boolean isForce) {
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State3.getIndex())
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		// 检查是否还有未填报结束的考核对象，如果没有则直接更新方案
		Integer iCount = sheetService.queryCompletionRatio(scheme.getId());
		if (iCount == null)
			throw new AdderBusinessException("方案中不存在可以开始评分的考核对象", "pm.i18n_pbc.ps.004");
		if (iCount != 100) {
			// 方案填报还未完成，根据是否强制，非强制则返回未完成的人员列表
			Condition condObj = new Condition();
			condObj.addExpression("schemeid", scheme.getId());
			condObj.addExpression("enablestate", true);
			condObj.addExpression("isaudit", false);
			List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
			if (isForce) {
				for (Sheet item : sheetList) {
					item.setEnablestate(false);
					daoex.update(item, Arrays.asList("enablestate"));
				}
			} else {
				Map<String, PmStaff> staffMap = StaffHelper.getPMStaffList(sheetList, null);
				StaffHelper.simplifyStaff(staffMap);
				return StaffHelper.convertStaffMapToList(staffMap);
			}
		}
		// 填报完成，更新方案状态
		scheme.setSchemestate(CommonValue.EnumSchemeState.State4.getIndex());
		daoex.update(scheme);
		return null;
	}

    @Override
	public void refill(Scheme scheme, List<String> staffids) {
		// 可选择人员，对部分人员进行重新填报，这些人员的评分数据全部清空，但其他人员的评分数据不受影响。
		// 重新填报人员的PBC填报数据不变，个人PBC状态重置为“待提交”，可直接编辑原有的PBC，然后再次提交审核。
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State4.getIndex()
				&& scheme.getSchemestate() != CommonValue.EnumSchemeState.State5.getIndex())
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if(!scheme.isIsallowcalc()){
			throw new AdderBusinessException("该方案不支持此操作", "pm.i18n_pbc.ps.033");
		}
		if(scheme.getSchememode() < CommonValue.EnumSchemeMode.pm_mtr.getIndex() &&
				! op2Srv.checkAllMtrOver(scheme.getId())){
			throw new AdderBusinessException("该方案下尚有未结束的中期回顾方案", "pm.i18n_pbc.ps.028");
		}
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		condObj.addExpression("staffid", staffids, Operator.IN);
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		List<String> staffidList = new ArrayList<String>();
		// 循环量表，准备删除数据
		for (Sheet item : sheetList) {
			// 更改量表状态，保留审核人意见为重新填报查看
			item.setIsaudit(false);
			item.setMarkStatus(1);
			item.setEnablestate(true);
			// 注意delSheetAppraiseData也会更新Sheet时间戳，所以后删除
			daoex.update(item);
			// 所选人员只保留个人PBC填报数据，其PBC审核结果、以及PBC打分数据将删除
			daoAppraise.delSheetAppraiseData(item.getId());
			// 清除审批意见
			sheetSettingService.cleanApproverComment(item.getId());
			// 删除工作流程（填报、评价环节），填报提交时会再次创建
			wfSrv.delWorkflowEngine(WorkflowHelper.getPMDelWorkflowEngineCondition(item.getId()));
			// 给重新填报的人发消息
			staffidList.add(item.getStaffid());
		}
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State4.getIndex()) {
			scheme.setSchemestate(CommonValue.EnumSchemeState.State3.getIndex());
			daoex.update(scheme);
		}
		// 发送通知
		/*
		 * NoticeExtendParam ep = new NoticeExtendParam("", scheme.getId(), staffidList,
		 * CommonValue.EnumSendNoticeType.NOTICE);
		 */
		// 通知类型不带连接，所以改为发连接通知
		NoticeExtendParam ep = new NoticeExtendParam();
		ep.title = "";
		ep.staffIds = staffids;
		ep.schemeId = scheme.getId();
		fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIFILL, ep);
		// sendNotice(scheme.getId(), staffidList, 0, null);
	}

	@Override
	public void startScore(Scheme scheme) {
		if (scheme.isIsallowfillup() && scheme.getSchemestate() != CommonValue.EnumSchemeState.State4.getIndex()) {
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		}
		if (!scheme.isIsallowfillup() && (scheme.getSchemestate() == CommonValue.EnumSchemeState.State2.getIndex()
				|| scheme.getSchemestate() > CommonValue.EnumSchemeState.State4.getIndex())) {
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		}
		if(!scheme.isIsallowcalc()){
			throw new AdderBusinessException("该方案不支持此操作", "pm.i18n_pbc.ps.033");
		}
		// 检查是否中期评价已结束
		checkMtr(scheme);
		scheme.setSchemestate(CommonValue.EnumSchemeState.State5.getIndex());
		if (!daoex.update(scheme))
			throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
		// 强制填报结束，可能造成有人员未填报终审，所以这里不检查量表是否都已经审核完
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		condObj.addExpression("isaudit", false);
		// condObj.addExpression("enablestate", false);
		// 查询无效的量表
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		List<String> sheetids = new ArrayList<String>();
		for (Sheet item : sheetList) {
			sheetids.add(item.getId());
		}
		// 生成评价结构，已终审的并且有效的
		String sql = "sheetid in (select id from pm_sheet where schemeid='" + scheme.getId()
				+ "' and enablestate=1 and isaudit=1)";
		condObj = new Condition();
		condObj.addExpressions(new SqlExpression(sql));
		Sorter sortObj = new Sorter(Direction.ASC, Arrays.asList("turn", "indicatorid"));
		List<SheetAppraiser> apprSheetList = daoex.find(SheetAppraiser.class, condObj, sortObj);
		for (int i = apprSheetList.size() - 1; i >= 0; i--) {
			// 排除掉未终审的考核对象
			if (sheetids.contains(apprSheetList.get(i).getSheetid()))
				apprSheetList.remove(i);
		}
		if (apprSheetList.isEmpty())
			throw new AdderBusinessException("方案中不存在可以开始评分的考核对象", "pm.i18n_pbc.ps.004");
		createAppraiseData(scheme, apprSheetList);

		// 删除那些未完成审核的量表评分工作流
		wfSrv.delWorkflowEngineByParam(sheetids, EnumWorkStep.step2.getIndex());
		// 推动工作流从填报完成到评分开始
		WorkflowParam param = new WorkflowParam();
		param.setWorkstep(EnumWorkStep.step2);
		param.setBiztype(CommonValue.EnumWorkflowType.performance);
		param.setBizinfo(Arrays.asList(scheme.getId()));
		wfbService.setPushState(param);
	}

    @Override
    public void rescore(Scheme scheme, List<String> staffids) {
        // 选择部分人员，进行重新评分，如果这些人已经有审核分数了，清空审核分数。其他人员的审核分数不受影响。
        // 重新评分人员的状态重置为第一轮打分的“待提交”状态，可直接修改第一轮的评分，然后提交下一轮评价人进行打分。
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State6.getIndex())
            throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if (CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()) {
			throw new AdderBusinessException("中期回顾方案不支持此操作", "pm.i18n_pbc.ps.032");
		}
        Condition condObj = new Condition();
        condObj.addExpression("schemeid", scheme.getId());
        condObj.addExpression("staffid", staffids, Operator.IN);
        List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
        // 循环量表，删除评价数据
        for (Sheet item : sheetList) {
            // 所选人员只保留个人PBC数据，其PBC审核结果、以及PBC打分数据将删除
            daoAppraise.clearSheetAppraiseData(item.getId());
            // 退回评价流程到初始状态
            BaseParam param = new BaseParam();
            param.setBiztype(CommonValue.EnumWorkflowType.performance);
            param.setBizid(item.getId());
            param.setWorkstep(CommonValue.EnumWorkStep.step2);
            wfSrv.reloadWorkflowEngine(param);
        }
        scheme.setSchemestate(CommonValue.EnumSchemeState.State5.getIndex());
        daoex.update(scheme);
    }

    @Override
    public List<PmStaff> calculating(Scheme scheme, boolean isForce) {
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State5.getIndex())
            throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if(!scheme.isIsallowcalc()){
			throw new AdderBusinessException("该方案不支持此操作", "pm.i18n_pbc.ps.033");
		}
        if (isForce) {
			// 处理未填报结束的人失效
			Condition condObj = new Condition();
			condObj.addExpression("schemeid", scheme.getId());
			condObj.addExpression("enablestate", true);
			condObj.addExpression("isaudit", false);
			List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
			for (Sheet item : sheetList) {
				item.setEnablestate(false);
				daoex.update(item, Arrays.asList("enablestate"));
			}
            condObj = new Condition();
            condObj.addExpression("schemeid", scheme.getId());
            condObj.addExpression("enablestate", true);
            condObj.addExpression("iscalc", false);
            condObj.addExpression("isaudit", true);
            sheetList = daoex.find(Sheet.class, condObj, null);
            // 计算弃权
            for (Sheet item : sheetList) {
                apprService.appraiserFinalCallback(item.getId());
            }
        } else {
            // 评分结束要处理未评分完毕的考核对象
            int iCount = sheetService.queryAppraiseRatio(scheme.getId());
            if (iCount != 100) {
                // 方案评分还未完成，则返回未完成的人员列表
                Condition condObj = new Condition();
                condObj.addExpression("schemeid", scheme.getId());
                condObj.addExpression("enablestate", true);
                condObj.addExpression("iscalc", false);
                List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
                Map<String, PmStaff> staffMap = StaffHelper
                        .getPMStaffList(sheetList, null);
                StaffHelper.simplifyStaff(staffMap);
                return StaffHelper.convertStaffMapToList(staffMap);
            }
        }
        scheme.setSchemestate(CommonValue.EnumSchemeState.State6.getIndex());
        daoex.update(scheme);
        return null;
    }

	@Override
	public void initAudit(Scheme scheme) {
		initAuditCheck(scheme);
		// 查询结果审核流程设置
		List<EvaAppraiser> evaAppraiserList = getEvaAppraiserSet(scheme.getId());
		if (evaAppraiserList.isEmpty())
			throw new AdderBusinessException("请先进行结果审核设置", "pm.i18n_pbc.ps.005");
		// 查询方案下有效量表
		List<Sheet> sheetList = getValidSheets(scheme.getId());
		if (sheetList.isEmpty())
			throw new AdderBusinessException("未查询到需要进行结果审核的考核对象", "pm.i18n_pbc.ps.006");
		checkDistNum(sheetList, scheme);
		scheme.setSchemestate(CommonValue.EnumSchemeState.State7.getIndex());
		boolean ret = daoex.update(scheme, Arrays.asList("schemestate"));
		if (!ret)
			throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
		// evaSumList为没有考核对象组，即方案级审核人的流程
		List<EvaAppraiser> evaSumList = new ArrayList<EvaAppraiser>();
		for (EvaAppraiser item : evaAppraiserList) {
			if (item.getGroupid() == null)
				evaSumList.add(item);
		}
		// 查询方案下人员和考核对象组的关系
		// <staffid,groupid>考核对象属于哪个组
		Map<String, String> evaObjectMap = getEvaObjectMap(scheme.getId());
		// 先做组审核，循环量表，这个考核对象属于哪个组，找到审核人是谁。<sheetid,List>
		List<ApproveScore> appScoreList = getApproveScore(scheme.getId(), sheetList, evaAppraiserList, evaSumList,
				evaObjectMap);
		setStaffDeptid(appScoreList);
		// 删除原有审核人数据，保存现有审核人数据
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		daoAppScore.deleteApproveScore(condObj);
		// 20201116解决插入数据太多
		daoex.insertByBatch(appScoreList);
		sheetList = null;
		evaAppraiserList = null;
		evaSumList = null;
		evaObjectMap = null;
		// 生成工作流
		Workflow wf = wfSrv.queryWorkflowByBizid(scheme.getId());
		List<WorkflowEngine> engines = WorkflowHelper.addPMWorkflowEngine(wf.getId(), appScoreList);
		condObj = new Condition();
		condObj.addExpression("bizinfo", scheme.getId());
		condObj.addExpression("workstep", CommonValue.EnumWorkStep.step3.getIndex());
		wfSrv.delWorkflowEngine(condObj);
		wfSrv.addWorkflowEngine(engines);
		// 推动工作流待处理
		WorkflowParam param = new WorkflowParam();
		param.setWorkstep(EnumWorkStep.step3);
		param.setBiztype(CommonValue.EnumWorkflowType.performance);
		param.setBizinfo(Arrays.asList(scheme.getId()));
		wfbService.setPushState(param);
		appScoreList = null;
	}

    @Override
    public void endAudit(Scheme scheme) {
        if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State7.getIndex())
            throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if(CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()){
			throw new AdderBusinessException("中期回顾方案不支持结果审核", "pm.i18n_pbc.ps.030");
		}
        // 检查结果审核是否完成
        if (sheetService.queryResultRatio(scheme.getId()) != 100)
            throw new AdderBusinessException("存在结果审核未完成的人员", "pm.i18n_pbc.ps.007");
        scheme.setSchemestate(CommonValue.EnumSchemeState.State8.getIndex());
        daoex.update(scheme);
    }

    @Override
    public void reexamined(Scheme scheme, List<String> groupids) {
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State8.getIndex())
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if (CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()) {
			throw new AdderBusinessException("中期回顾方案不支持结果发布", "pm.i18n_pbc.ps.031");
		}
		// 20200104增加汇总方案校验
		checkSummaryScheme(scheme.getId());
        // 选择考核组，对部分考核组进行结果的重新审核及强制分布。其他组的审核结果和强制分布结果不受影响。
        // 第一轮审核分数保留，其他轮次审核分数删除，可直接修改第一轮审核分数，然后提交给第二轮进行审核。
        Condition condObj = new Condition();
        condObj.addExpression("schemeid", scheme.getId());
        condObj.addExpression("groupid", groupids, Operator.IN);
        List<EvaObject> evaObjectList = daoex.find(EvaObject.class, condObj, null);
        // 根据组里的考核对象找到量表
        List<String> sheetids = new ArrayList<String>();
        List<Sheet> sheetList = getSheetidByEvaObject(evaObjectList);
		for (Sheet item : sheetList) {
			sheetids.add(item.getId());
			if (item.isIsover()) {
				item.setIsover(false);
				daoex.update(item, Arrays.asList("isover"));
			}
		}
        condObj = new Condition();
        condObj.addExpression("schemeid", scheme.getId());
        condObj.addExpression("sheetid", sheetids, Operator.IN);
        List<ApproveScore> appScoreList = daoex.find(ApproveScore.class, condObj, null);
        for (ApproveScore item : appScoreList) {
            item.setMarkStatus(CommonValue.EnumMarkState30.State1.getIndex());
            if (item.getTurn() > 1) {
                item.setScore(null);
                item.setAprTime(null);
                item.setGradeitemid(null);
                item.setGradeitemname(null);
                item.setComment(null);
            }
            daoex.update(item);
        }
        // 更新方案
        scheme.setSchemestate(CommonValue.EnumSchemeState.State7.getIndex());
        if (!daoex.update(scheme))
        	throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
        // 清除考核结果调整数据
        adjustScoreDao.deleteAdjustScoreBySchemeId(scheme.getId(), scheme.getTenantid());
        // 退回结果审核流程到初始状态
        BaseParam param = new BaseParam();
        param.setBiztype(CommonValue.EnumWorkflowType.performance);
        param.setBizids(sheetids);
        param.setWorkstep(CommonValue.EnumWorkStep.step3);
        wfSrv.reloadWorkflowEngine(param);
        // 退回方案级和多方案的结果审核
        param.setBizids(null);
        param.setBizinfo(Arrays.asList(scheme.getId()));
        wfSrv.reloadWorkflowEngine30(param, Arrays.asList(EnumAuditType.type2, EnumAuditType.type3));
    }

    @Override
    public void cancelAudit(Scheme scheme) {
		if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State7.getIndex())
            throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if(CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()){
			throw new AdderBusinessException("中期回顾方案不支持结果审核", "pm.i18n_pbc.ps.030");
		}
        daoAppScore.cancelAudit(scheme.getId());
    }

    @Override
	public void publish(Scheme scheme) {
    	// add by zengcl 适配  建工项目 导入结果后到直接到评分结束阶段，进行结果发布   20201222 begin  
    	if(scheme.isIsimportresult()) {
    		if (!scheme.isIsresultaudited()) {
    			// 如果方案没有结果审核，则设置流程结束
    			sheetService.doEndProcess(scheme.getId());
    			scheme = daoex.load(Scheme.class, scheme.getId());
    		}
    		// 检查是否可发布
    		List<Sheet> sheetList = sheetService.checkPublish(scheme.getId());
    		if (!sheetList.isEmpty())
    			throw new AdderBusinessException("存在不符合发布条件的数据，请处理", "pm.i18n_pbc.ps.008");
    		// 同步绩效到人员子集
    		List<Score> scores = syncResultSrv.insertResult(scheme);
    		try {
    			scheme.setSchemestate(CommonValue.EnumSchemeState.State9.getIndex());
    			scheme.setTdate(new Date());
    			if (!daoex.update(scheme))
    				throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
    			// 量表设置发布，为了事务放在最后
    			sheetService.publish(scheme.getId(), true);
    			// 20190828新增发送通知
    			if (scores != null) {
    				List<String> staffids = scores.stream().map(obj -> obj.getStaffid()).distinct()
    						.collect(Collectors.toList());
    				NoticeExtendParam ep = new NoticeExtendParam("考核结果", scheme.getId(), staffids,
    						CommonValue.EnumSendNoticeType.NOTICE);
    				ep.desc = "您的考核结果已发布，快去看看吧\n";
    				ep.isSynchronized = false;
    				ep.setSendTxtEmail(true);
    				ep.enumNoticeType = CommonValue.EnumNoticeType.RESULTPUBLISH;
    				fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.SCORE, ep);
    			}
    		} catch (Exception e) {
    			syncResultSrv.delete(scheme);
    			throw e;
    		}
    	}else     	// add by zengcl 适配  建工项目 导入结果后到直接到评分结束阶段，进行结果发布   20201222 end
    	{
			// 如果方案没有启用结果审核，状态不在评分已结束；启用结果审核，状态不在结果已审核；则状态不正确
			if (!scheme.isIsresultaudited() && scheme.getSchemestate() != CommonValue.EnumSchemeState.State6.getIndex()
					|| scheme.isIsresultaudited()
							&& scheme.getSchemestate() != CommonValue.EnumSchemeState.State8.getIndex())
				throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
			if (CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()) {
				throw new AdderBusinessException("中期回顾方案不支持结果发布", "pm.i18n_pbc.ps.031");
			}
			if (!scheme.isIsresultaudited()) {
				// 如果方案没有结果审核，则设置流程结束
				sheetService.doEndProcess(scheme.getId());
				scheme = daoex.load(Scheme.class, scheme.getId());
			}
			// 检查是否可发布
			List<Sheet> sheetList = sheetService.checkPublish(scheme.getId());
			if (!sheetList.isEmpty())
				throw new AdderBusinessException("存在不符合发布条件的数据，请处理", "pm.i18n_pbc.ps.008");
			// 同步绩效到人员子集
			List<Score> scores = null;
			if (scheme.isIsresultconfirm()) {
				scores = syncResultSrv.insertResultExt(scheme, false);
			} else {
				scores = syncResultSrv.insertResult(scheme);
			}
			try {
				scheme.setPdate(new Date());
				scheme.setSchemestate(CommonValue.EnumSchemeState.State9.getIndex());
				if (!scheme.isIsresultconfirm()) { // 没有 结果确认环节的话,标记方案结束
					// 结果已发布，没有认可的方案发布后直接结束
					scheme.setIsend(true);
					scheme.setTdate(scheme.getPdate());
				}
				if (!daoex.update(scheme))
					throw new AdderBusinessException("更新数据失败", "pm.i18n_core.comm.022");
				// 量表设置发布，为了事务放在最后
				sheetService.publish(scheme.getId(), true);
				// 20190828新增发送通知
				if (scores != null) {
					List<String> staffids = scores.stream().map(obj -> obj.getStaffid()).distinct()
							.collect(Collectors.toList());
					NoticeExtendParam ep = new NoticeExtendParam("考核结果", scheme.getId(), staffids,
							CommonValue.EnumSendNoticeType.NOTICE);
					ep.desc = "您的考核结果已发布，快去看看吧\n";
					ep.isSynchronized = false;
					ep.setSendTxtEmail(true);
					ep.enumNoticeType = CommonValue.EnumNoticeType.RESULTPUBLISH;
					fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.SCORE, ep);
				}
				if (scheme.isIsresultconfirm()){
					List<ResultConfirm> rescon_lst = confirmService.createResultConfirmRecord(scheme.getId()); // 生成员工确认记录
					List<String> staffids = rescon_lst.stream().map(obj -> obj.getStaffid()).distinct()
							.collect(Collectors.toList());
					NoticeExtendParam ep = new NoticeExtendParam("结果确认", scheme.getId(), staffids,
							CommonValue.EnumSendNoticeType.NOTICE);
					ep.desc = "您有新的考核结果待确认\n";
					ep.isSynchronized = false;
					ep.setSendTxtEmail(true);
					fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.RESULTCONFIRM, ep);
					
					// 单独给领导发结果确认
					Map<String,List<ResultConfirm>> leadermap = rescon_lst.stream().filter(reconfirm -> StringUtils.isNotEmpty(reconfirm.getLeaderid()))
							.collect(Collectors.groupingBy(ResultConfirm::getLeaderid, Collectors.toList()));
					Iterator<String> leaderIter = leadermap.keySet().iterator();
					while(leaderIter.hasNext()){
						String leaderid = leaderIter.next();
						List<String> staffinl = leadermap.get(leaderid).stream()
								.map(ResultConfirm::getStaffid).collect(Collectors.toList());
						NoticeExtendParam ep2 = new NoticeExtendParam("结果确认", scheme.getId(), Arrays.asList(leaderid),
								CommonValue.EnumSendNoticeType.NOTICE);
						ep2.desc = "您有新的对" + getStaffNamesByStaffids(staffinl) + "等人的考核结果待确认\n";
						ep2.isSynchronized = false;
						ep2.setSendTxtEmail(true);
						fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.RESULTCONFIRM, ep2);
					}
					
				}
			} catch (Exception e) {
				if (!scheme.isIsresultconfirm()) {
					syncResultSrv.delete(scheme);
				}
				throw e;
			}
    	}
	}

    private String getStaffNamesByStaffids(List<String> staffids) {
		staffids = staffids.stream().sorted( (staff1 ,staff2) -> staff1.compareTo(staff2) ).collect(Collectors.toList());
		Map<String, PmStaff> staffList = StaffHelper.queryStaffByIds(staffids, false);
		List<PmStaff> pl = new ArrayList<>();
		for (String str : staffids) {
			pl.add(staffList.get(str));
		}
		List<String> staffname = new ArrayList<String>();
		for (int i = 0 ; i < staffids.size() && i < 3; i++) {
			staffname.add(staffList.get(staffids.get(i)).name);
		}
		return String.join(",", staffname);
	}

    @Override
	public void cancelPublic(Scheme scheme) {
		if(CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()){
			throw new AdderBusinessException("中期回顾方案不支持结果发布", "pm.i18n_pbc.ps.031");
		}
		// 检查是否出现在汇总方案中
		checkSummaryScheme(scheme.getId());
		// 同步绩效到人员子集(删除)
		syncResultSrv.delete(scheme);
		if (scheme.isIsresultaudited()) {
			scheme.setSchemestate(CommonValue.EnumSchemeState.State8.getIndex());
		}
		else {
			scheme.setSchemestate(CommonValue.EnumSchemeState.State6.getIndex());
		}
		scheme.setIsend(false);
		scheme.setTdate(null);
		daoex.update(scheme);
		// 量表设置取消发布
		sheetService.publish(scheme.getId(), false);
	}

    @Override
    public Map<String, Object> queryStaffByConditon(String schemeid, EnumWorkStep workstep) {
        // 查询提醒人员
        Map<String, Object> objs = new Hashtable<>();
        // 根据环节准备查询条件，填报人员已提交的不显示，审核人员未到达的不显示
        // 输出的PmStaff中define1：轮次；define2：状态；define3：考核组名或考核对象集合
		if (workstep.equals(EnumWorkStep.step1)) {
			// 填报环节
			// 查询方案下未填报的量表数据
			List<Sheet> sheetList = queryNoFillSheetListByScheme(schemeid);
			// 查询考核对象人员信息
			Map<String, PmStaff> staffMap = StaffHelper.getPMStaffList(sheetList, null);
			for (Sheet item : sheetList) {
				// 循环未终审的考核对象，设置填报人员状态名称
				if (staffMap.containsKey(item.getStaffid())) {
					staffMap.get(item.getStaffid()).state = CommonValue.EnumMarkState10.values()[item.getMarkStatus()]
							.getDescription();
					staffMap.get(item.getStaffid()).define2 = item.getMarkStatus();
				}
			}
			List<PmStaff> staffList = StaffHelper.convertStaffMapToList(staffMap);
			// 查询方案提醒过人员的记录
			Map<String, Date> reminds = remindService.queryRemindList(schemeid, CommonValue.EnumRemindType.WorkStep10);
			setStaffRemindTime(staffList, reminds);
			objs.put("1", staffList);
			// 审核人
			staffList = queryStaffListByDisposeEngine(schemeid, workstep);
			setStaffRemindTime(staffList, reminds);
			objs.put("2", staffList);
			// 查询所有审核通过的人员列表
			staffList = queryPassStaffList(schemeid, workstep);
			objs.put("3", staffList);
			// 封装人员所属考核组信息，放到人员的define3字段上
			// 获取未填报人员列表
			List<PmStaff> noFillStaffList = (List<PmStaff>) objs.get("1");
			// 获取已审核人员列表
			List<PmStaff> passStaffList = (List<PmStaff>) objs.get("3");
			// 设置人员的所属考核组信息保存到人员的define3字段
			setStaffGroupToDefine3(noFillStaffList, passStaffList, schemeid);
			// 处理审核人员对应的人员及审核对象个数，拼成字符串，封装到define3字段上
			List<PmStaff> disposepersonList = (List<PmStaff>) objs.get("2");
			// 设置该考核人下考核对象的人数及第一个人的名字，封装到define3字段
			setStaffCountToDefine3(schemeid, workstep, disposepersonList);
		} else if (workstep.equals(EnumWorkStep.step2)) {
            // 评价环节，查询评价人状态
            List<WorkflowEngine> engines = getPendingWorkflow(schemeid, workstep);
            Map<String, PmStaff> staffMap = StaffHelper.getPMStaffList(engines, "getDisposeperson");
            // 有多个评价对象的
            List<PmStaff> staffMulti = new ArrayList<PmStaff>();
            // 只有一个评价对象的
            List<PmStaff> staffSingle = new ArrayList<PmStaff>();
			getProgressInfo(schemeid, workstep, engines, staffSingle, staffMulti);
            // 指标填报中的要再调一次此方法
            //staffSingle.sort(Comparator.naturalOrder());
            Collections.sort(staffSingle);
            //staffMulti.sort(Comparator.naturalOrder());
            Collections.sort(staffMulti);
			// 查询方案提醒过人员的记录
			Map<String, Date> reminds = remindService.queryRemindList(schemeid, CommonValue.EnumRemindType.WorkStep20);
			setStaffRemindTime(staffSingle, reminds);
			setStaffRemindTime(staffMulti, reminds);
            objs.put("1", staffSingle);
            objs.put("2", staffMulti);
			engines = getPassAuditWorkflow(schemeid, workstep);
			List<PmStaff> staffOver = new ArrayList<>();
			getProgressInfo(schemeid, workstep, engines, staffOver, null);
			logger.debug("queryStaffByConditon 3 " + JSONObject.toJSONString(staffOver));
			objs.put("3", staffOver);
			engines = null;
        } else if (workstep.equals(EnumWorkStep.step3)) {
            // 结果审核环节
            List<PmStaff> staffList = queryStaffListByDisposeEngine(schemeid,workstep);
            objs.put("1", staffList);
        }
        return objs;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public List queryRemindDetail(String schemeid, EnumWorkStep workstep,
                                  String staffid) {
        BaseParam param = new BaseParam();
        param.setBizinfo(Arrays.asList(schemeid));
        param.setWorkstep(workstep);
        param.setBiztype(CommonValue.EnumWorkflowType.performance);
        param.setCurrentOperator(staffid);
        // 只显示待处理的
        param.setWorkflowStateList(Arrays
                .asList(CommonValue.EnumWorkflowState.PENDING));
        // 查询工作流引擎
        List<WorkflowEngine> engines = wfSrv.queryWorkflowEngine(param);
        if (engines.isEmpty())
            return new ArrayList<PmStaff>();
        List<String> sheetids = new ArrayList<String>();
        Map<String, WorkflowEngine> enginesMap = new Hashtable<String, WorkflowEngine>();
        for (WorkflowEngine item : engines) {
            if (!sheetids.contains(item.getBizid())) {
                sheetids.add(item.getBizid());
                enginesMap.put(item.getBizid(), item);
            }
        }
        Condition condObj = new Condition();
        condObj.addExpression("schemeid", schemeid);
        condObj.addExpression("id", sheetids, Operator.IN);
        // 查询评价的量表
        List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
        Map<String, PmStaff> staffMap = StaffHelper
                .getPMStaffList(sheetList, null);
        for (Sheet item : sheetList) {
            if (staffMap.containsKey(item.getStaffid())) {
                String strState = "";
				if (workstep.equals(EnumWorkStep.step2)) {
					if (enginesMap.get(item.getId()).getState() >= 6) {
						strState = CommonValue.EnumMarkState.State3.getDescription();
						// define2是状态
						staffMap.get(item.getStaffid()).define2 = CommonValue.EnumMarkState.State3.getIndex();
					} else {
						strState = CommonValue.EnumMarkState.State1.getDescription();
						staffMap.get(item.getStaffid()).define2 = CommonValue.EnumMarkState.State1.getIndex();
					}
				} else {
					if (enginesMap.get(item.getId()).getState() >= 6) {
						strState = CommonValue.EnumMarkState30.State3.getDescription();
						staffMap.get(item.getStaffid()).define2 = CommonValue.EnumMarkState30.State3.getIndex();
					} else {
						strState = CommonValue.EnumMarkState30.State1.getDescription();
						staffMap.get(item.getStaffid()).define2 = CommonValue.EnumMarkState30.State1.getIndex();
					}
				}
                staffMap.get(item.getStaffid()).state = strState;
                // 轮次放到自定义define1上
                staffMap.get(item.getStaffid()).define1 = enginesMap.get(
                        item.getId()).getStepserial();
            }
        }
        List<PmStaff> staffList = StaffHelper.convertStaffMapToList(staffMap);
        sheetList = null;
        engines = null;
        return staffList;
    }

	/*@Override
    public String sendReminder(String schemeid, List<String> staffids,
			Integer sendType, String title) {
		Scheme scheme = daoex.load(Scheme.class, schemeid);
		if (scheme == null)
			throw new AdderBusinessException("方案不正确");
		Period p = daoex.load(Period.class, scheme.getPeriodid());
		NoticeBaseParam noticeParam = new NoticeBaseParam();
		if (StringUtils.isEmpty(title))
			noticeParam.title = "绩效提醒";
		else
			noticeParam.title = title;
		noticeParam.staffIds = staffids;
		noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/performance?platform=ykj&target=performance&code=${esncode}";
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex()) {
			// 填报中，提醒完成填报
			if (sendType.equals(0)) {
				noticeParam.desc = "请您尽快完成指标填报";
			} else {
				noticeParam.desc = "请您尽快完成指标审核";
				noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=pbcaudit&code=${esncode}";
			}
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
			noticeParam.desc = "请您尽快完成评分";
			noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=evaluate&code=${esncode}";
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
			noticeParam.desc = "请您尽快完成结果审核";
			noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=auditResult&code=${esncode}";
		} else
			return "方案状态不正确";
		noticeParam.desc += "\n绩效方案：" + scheme.getSchemename() + "\n" + "绩效期间："
				+ p.getPeriodname();
		return noticSrv.sendAppNotice(noticeParam);
	}
*/

	@Override
	public String sendReminder(String schemeid, List<String> staffids, Integer sendType, String title) {
		Scheme scheme = daoex.load(Scheme.class, schemeid);
		if (scheme == null) {
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		}
		// 检查staffids中哪些是非评分的
		List<String> staffFill = new ArrayList<>();
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
			Condition cond = new Condition();
			cond.addExpression("schemeid", schemeid);
			cond.addExpression("staffid", staffids, Operator.IN);
			cond.addExpression("isaudit", false);
			List<Sheet> sheetList = daoex.find(Sheet.class, cond, null);
			if (!sheetList.isEmpty()) {
				// staffFill = sheetList.stream().map(obj -> obj.getStaffid()).collect(Collectors.toList());
				staffFill = ListHelper.collect(sheetList, "getStaffid");
				Toolkit.removeSubList(staffids, staffFill);
			}
		}
		NoticeExtendParam ep = new NoticeExtendParam();
		ep.title = title;
		ep.staffIds = staffids;
		ep.schemeId = schemeid;
		String msg = "";
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex() || !staffFill.isEmpty()) {
			if (!staffFill.isEmpty())
				ep.staffIds = staffFill;
			// 填报中，提醒完成填报
			if (sendType.equals(0)) {
				// 指标填报提醒
				msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIFILL, ep);
			} else {
				// 指标审核提醒
				msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIAUDIT, ep);
			}
			remindService.saveRemind(schemeid, CommonValue.EnumRemindType.WorkStep10, ep.staffIds, null);
		}
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
			if (staffids.isEmpty())
				return "";
			ep.staffIds = staffids;
			// 评分提醒
			msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.SCORE, ep);
			remindService.saveRemind(schemeid, CommonValue.EnumRemindType.WorkStep20, staffids, null);
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
			// 结果审核提醒
			msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.RESULTAUDIT, ep);
			remindService.saveRemind(schemeid, CommonValue.EnumRemindType.WorkStep30, staffids, null);
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State9.getIndex() 
				&& scheme.isIsresultconfirm()) {
			// 结果确认提醒
			msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.RESULTCONFIRM, ep);
			remindService.saveRemind(schemeid, CommonValue.EnumRemindType.WorkStep40, staffids, null);
		} else if (scheme.getSchemestate() != CommonValue.EnumSchemeState.State3.getIndex())
			msg = "方案状态不正确";
		return msg;
	}

    @Override
    public String sendNotice(String schemeid, List<String> staffids,
                             Integer sendType, String title) {
        Scheme scheme = daoex.load(Scheme.class, schemeid);
        if (scheme == null)
            throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
        NoticeExtendParam ep = new NoticeExtendParam();
        ep.staffIds = staffids;
        ep.schemeId = schemeid;
        ep.sendAppNotice = false;
        ep.sendTxtNotice = true;
        ep.sendTodoNotice = false;
        String msg;
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex()) {
            // 填报中，提醒完成填报
            if (sendType.equals(0)) {
                //指标填报文本通知
                msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIFILL, ep);
            } else {
                //指标审核文本通知
                msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.INDIAUDIT, ep);
            }
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
			// 评分文本通知
			msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.SCORE, ep);
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
            //结果审核文本通知
            msg = fService.getNoticeServiceToSend(CommonValue.EnumNoticeType.RESULTAUDIT, ep);
        } else
            return "方案状态不正确";
        return msg;
    }

	/*@Override
	public String sendNotice(String schemeid, List<String> staffids,
			Integer sendType, String title) {
		Scheme scheme = daoex.load(Scheme.class, schemeid);
		if (scheme == null)
			throw new AdderBusinessException("方案不正确");
		Period p = daoex.load(Period.class, scheme.getPeriodid());
		NoticeBaseParam noticeParam = new NoticeBaseParam();
		if (StringUtils.isEmpty(title))
			noticeParam.title = "绩效通知";
		else
			noticeParam.title = title;
		noticeParam.staffIds = staffids;
		noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/performance?platform=ykj&target=performance&code=${esncode}";
		if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex()) {
			// 填报中，提醒完成填报
			if (sendType.equals(0)) {
				noticeParam.desc = "您有新的指标填报待办";
			} else {
				noticeParam.desc = "您有新的指标审核待办";
				noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=pbcaudit&code=${esncode}";
			}
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
			noticeParam.desc = "您有新的评分待办";
			noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=evaluate&code=${esncode}";
		} else if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
			noticeParam.desc = "您有新的结果审核待办";
			noticeParam.detailUrl = "http://hrcloud.yyuap.com/wap/#/router-bridge?platform=ykj&target=auditResult&code=${esncode}";
		} else
			return "方案状态不正确";
		noticeParam.desc += "\n绩效方案：" + scheme.getSchemename() + "\n" + "绩效期间："
				+ p.getPeriodname();
		return noticSrv.sendTextNotice(noticeParam);
	}*/

    /**
     * 评分开始创建评价结构
     *
	 * @param scheme
	 *            方案
	 * @param apprSheetList
	 *            量表评价人设置集合（可以是整个方案的，也可以是部分量表的）
     */
	private void createAppraiseData(Scheme scheme, List<SheetAppraiser> apprSheetList) {
        List<String> staffids = new ArrayList<String>();
        for (SheetAppraiser item : apprSheetList) {
            if (!staffids.contains(item.getStaffid()))
                staffids.add(item.getStaffid());
        }
        Map<String, PmStaff> staffMap = StaffHelper
                .queryStaffByIds(staffids);
        List<String> apprKey = new ArrayList<String>();
        List<Appraise> apprList = new ArrayList<Appraise>();
        List<AppraiseData> apprDataList = new ArrayList<AppraiseData>();
        for (SheetAppraiser item : apprSheetList) {
			String key = item.getSheetid() + "-" + item.getTurn() + "-" + item.getStaffid();
            if (!apprKey.contains(key)) {
                apprKey.add(key);
                Appraise appr = new Appraise();
                appr.setSchemeid(scheme.getId());
                appr.setSheetid(item.getSheetid());
                appr.setAppraiser(item.getStaffid());
                // 判断是否按轮次顺序打分
                if (scheme.isIsturn())
                    appr.setTurn(item.getTurn());
                else
                    appr.setTurn(1);
				if (!staffMap.containsKey(item.getStaffid())) {
					logger.error("pm:createAppraiseData " + key);
					throw new AdderBusinessException("考核对象的评价人未对应人员，请检查", "pm.i18n_pbc.ps.018");
				}
                appr.setDeptid(staffMap.get(item.getStaffid()).deptid);
                appr.setMarkStatus(CommonValue.EnumMarkState.State1.getIndex());
                apprList.add(appr);
            }

            AppraiseData apprData = new AppraiseData();
            apprData.setIndicatorid(item.getIndicatorid());
            apprData.setPeriodcode(scheme.getPeriodcode());
            apprData.setColumncode(EnumSchemeScoreColumnCode.CODE008.getCode());// "008"
            apprData.setSheetid(item.getSheetid());
            apprData.setAppraiser(item.getStaffid());
            if (scheme.isIsturn())
                apprData.setTurn(item.getTurn());
            else
                apprData.setTurn(1);
            apprData.setDimid(item.getDimid());
            apprData.setDeptid(staffMap.get(item.getStaffid()).deptid);
            // apprData.setAprStatus(CommonValue.EnumMarkState.State1.getIndex());
            apprDataList.add(apprData);
            try {
                // 增加评分说明
                AppraiseData apprData2 = (AppraiseData) apprData.clone();
                apprData2.setColumncode("009");
                apprDataList.add(apprData2);
                // 增加用户自定义栏目
				if (scheme.getSchememode() == CommonValue.EnumSchemeMode.pm_mtr.getIndex())
					addCustomColumnData(apprDataList, apprData);
            } catch (CloneNotSupportedException e) {
                logger.error(e.getMessage());
            }
        }
        // 之前有过评价不再插入
        Condition condObj = new Condition();
        condObj.addExpression("sheetid", apprList.get(0).getSheetid());
        if (daoex.find(Appraise.class, condObj, null).isEmpty()) {
            daoex.insertByBatch(apprList);
            daoex.insertByBatch(apprDataList);
		} else if (!sysService.checkPermissions2()) {
			// 调试模式可以跳过，否则抛出异常
			throw new AdderBusinessException("评分数据已存在，请检查数据正确性", "pm.i18n_pbc.ps.018");
		}
    }

	@Override
	public void createAppraiseData(Scheme scheme, Sheet sheet) {
		if (!sheet.isIsaudit())
			return;
		Condition condObj = new Condition();
		condObj.addExpression("sheetid", sheet.getId());
		Sorter sortObj = new Sorter(Direction.ASC, Arrays.asList("turn", "indicatorid"));
		List<SheetAppraiser> apprSheetList = daoex.find(SheetAppraiser.class, condObj, sortObj);
		createAppraiseData(scheme, apprSheetList);
	}

	/**
	 * @param periodcode
	 * @return java.util.List<java.util.Map<java.lang.String,java.lang.String>>
	 * @author ZhangTao
	 * @description 根据绩效期间code查询考核方案的填报进度信息
	 * @date 2019/6/18
	 **/
	@Override
	@Transactional(readOnly = true)
	public Page<EvaObject> querySchemeRateByPeriodCode(String periodcode,int pageNum,int pageSize) {
		Page<EvaObject> evaObjPage = null;
		StopWatch stopWatch = new StopWatch("pm:querySchemeRateByPeriodCode");
		stopWatch.start("1");
		//查询期间下的所有方案集合
		List<Scheme> schemeList = queryFillInSchemeListByPeirodCode(periodcode);
		stopWatch.stop();
		stopWatch.start("2");
		if(CollectionUtils.isNotEmpty(schemeList)){
			// Map<String,Scheme> schemeMap = schemeList.stream().collect(Collectors.toMap(Scheme::getId,Function.identity()));
			Map<String,Scheme> schemeMap = ListHelper.toMap(schemeList, "getId");
			//根据传入的期间code获取期间名称
			String periodName = queryPeriodNameByPeirodCode(periodcode);
			//查询该方案下所有考核对象
			// List<String> schemeidList = schemeList.stream().map(Scheme::getId).collect(Collectors.toList());
			List<String> schemeidList = ListHelper.collect(schemeList, "getId");
			evaObjPage = queryEvaObjPageBySchemeList(schemeidList,pageNum,pageSize);
			List<EvaObject> evaObjectList = evaObjPage.getContent();
			//获取分页后的方案id集合
			// List<String> pageSchemeidList = evaObjectList.stream().map(EvaObject::getSchemeid).distinct().collect(Collectors.toList());
			List<String> pageSchemeidList = ListHelper.collect(evaObjectList, "getSchemeid");
			//查询方案所属组织信息
			Map<String,CommonOrg> orgMap = queryCommonOrgIdAndOrgMapBySchemeIdList(pageSchemeidList,schemeMap);
			//获取考核对象的人员信息
			// List<String> staffidList = evaObjectList.stream().map(EvaObject::getStaffid).collect(Collectors.toList());
			List<String> staffidList = ListHelper.collect(evaObjectList, "getStaffid");
			//查询量表数据
			Condition sheetConditon = new Condition();
			sheetConditon.addExpression("schemeid",pageSchemeidList,Operator.IN);
			sheetConditon.addExpression("staffid",staffidList,Operator.IN);
			List<Sheet> sheetList = daoex.find(Sheet.class, sheetConditon, null);
			// List<String> sheetIdList = sheetList.stream().map(Sheet::getId).collect(Collectors.toList());
			List<String> sheetIdList = ListHelper.collect(sheetList, "getId");
			// Map<String, Sheet> sheetSchemeIdANdStaffIdMap = sheetList.stream().collect(
			// Collectors.toMap(sheet->sheet.getSchemeid()+sheet.getStaffid(),
			// Function.identity()));
			Map<String, Sheet> sheetSchemeIdANdStaffIdMap = new Hashtable<>();
			for (Sheet sheet : sheetList) {
				sheetSchemeIdANdStaffIdMap.put(sheet.getSchemeid() + sheet.getStaffid(), sheet);
			}
			//根据量表id查询工作流信息
			Condition wfengineCondition = new Condition();
			wfengineCondition.addExpression("bizid",sheetIdList,Operator.IN);
			wfengineCondition.addExpression("workstep", EnumWorkStep.step1.getIndex());
			List<WorkflowEngine> workflowEngineList = daoex.find(WorkflowEngine.class, wfengineCondition, null);
			// Map<String, List<WorkflowEngine>> wfSheetIdMap = workflowEngineList.stream().collect(Collectors.groupingBy(WorkflowEngine::getBizid));
			Map<String, List<WorkflowEngine>> wfSheetIdMap = ListHelper.groupingBy(workflowEngineList, "getBizid");
			//获取人员的部门编码
			Map<String, PmStaff> pmStaffMap = StaffHelper.queryStaffByIds(staffidList);
			Map<String, String> deptIdANdCodeMap = queryDeptCodeByStaffIdList(pmStaffMap);
			//获取所有的分组信息
			Map<String, String> groupMap = queryGroupNameByEvaObject(evaObjectList);

			//获取最大轮次数
			Condition turnConditon = new Condition();
			turnConditon.addExpression("workstep", EnumWorkStep.step1.getIndex());
			turnConditon.addExpression("bizinfo",pageSchemeidList,Operator.IN);
			turnConditon.addExpression("tenantid",AppContext.getContext().getScope());
			Integer maxTurn = operationDao.queryMaxTurnByCondition(turnConditon);
			for (EvaObject evaObject : evaObjectList) {
				Map<String,Object> infoMap = new HashMap<>();
				String schemeid = evaObject.getSchemeid();
				String staffid = evaObject.getStaffid();
				infoMap.put("periodname",periodName);
				if(pmStaffMap.get(staffid) != null){
					PmStaff pmStaff = pmStaffMap.get(staffid);
					pmStaff.code = (pmStaff.code == null ? "" : pmStaff.code);
					pmStaff.name = (pmStaff.name == null ? "" : pmStaff.name);
					pmStaff.psnclname = (pmStaff.psnclname == null ? "" : pmStaff.psnclname);
					pmStaff.deptname = (pmStaff.deptname == null ? "" : pmStaff.deptname);
					if(StringUtils.isEmpty(pmStaff.deptid)){
						pmStaff.deptcode = "";
					}else{
						pmStaff.deptcode = (deptIdANdCodeMap.get(pmStaff.deptid) == null ? "" : deptIdANdCodeMap.get(pmStaff.deptid));
				}
					evaObject.setStaff(pmStaff);
				}else{
					PmStaff pmStaff = new PmStaff();
					pmStaff.code = "";
					pmStaff.name = "";
					pmStaff.psnclname = "";
					pmStaff.deptcode = "";
					pmStaff.deptname = "";
					evaObject.setStaff(pmStaff);
				}
				infoMap.put("schemename",schemeMap.get(schemeid).getSchemename());
				infoMap.put("schemestate",CommonValue.EnumSchemeState.values()[schemeMap.get(schemeid).getSchemestate()].getDescription());
				infoMap.put("groupname",groupMap.get(evaObject.getGroupid()));
				if(sheetSchemeIdANdStaffIdMap.get(schemeid+staffid).getMarkStatus() < CommonValue.EnumMarkState10.State2.getIndex()){
					infoMap.put("submitted","否");
				}else{
					infoMap.put("submitted","是");
				}
				if(maxTurn != null){
					List<String> stepturns = new ArrayList<>(maxTurn);
					List<WorkflowEngine> workflowEngines = wfSheetIdMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId());
					if(CollectionUtils.isNotEmpty(workflowEngines)){
						// Map<String, Integer> wfSheetidStepAndStateMap = workflowEngines.stream().
						// collect(Collectors.toMap(wf -> wf.getBizid() + wf.getStepserial(),
						// WorkflowEngine::getState));
						Map<String, Integer> wfSheetidStepAndStateMap = new Hashtable<>();
						for (WorkflowEngine wf : workflowEngines) {
							wfSheetidStepAndStateMap.put(wf.getBizid() + wf.getStepserial(), wf.getState());
						}
						for (int i = 1; i <= maxTurn ; i++) {
							if(wfSheetidStepAndStateMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId()+i) != null){
								Integer wfState = wfSheetidStepAndStateMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId()+i);
								if(wfState < CommonValue.EnumWorkflowState.PASS_AUDIT.getIndex()){
									stepturns.add("否");
								}else{
									stepturns.add("是");
								}
							}else{
								stepturns.add("");
							}
						}
					}else{
						for (int i = 1; i <= maxTurn ; i++) {
							stepturns.add("");
						}
					}
					infoMap.put("stepturns",stepturns);
				}else{
					infoMap.put("stepturns",new ArrayList<String>(0));
				}
				//设置方案组织编码和组织名称
				if(orgMap.get(schemeMap.get(schemeid).getOrgid()) != null){
					infoMap.put("schemeorgcode",orgMap.get(schemeMap.get(schemeid).getOrgid()).getCode());
					infoMap.put("schemeorgname",orgMap.get(schemeMap.get(schemeid).getOrgid()).getName());
				}else{
					infoMap.put("schemeorgcode","");
					infoMap.put("schemeorgname","");
				}
				evaObject.setOtherInfo(infoMap);
			}
		}
		stopWatch.stop();
		if (stopWatch.getTotalTimeSeconds() > 3.0) {
			logger.error("pm:querySchemeRateByPeriodCode " + stopWatch.prettyPrint());
		}
		else
			logger.debug("pm:querySchemeRateByPeriodCode " + stopWatch.prettyPrint());
		return evaObjPage;
	}

	/**
	 * @param periodcode
	 * @return void
	 * @author ZhangTao
	 * @description 根据绩效期间code导出填报进展
	 * @date 2019/6/21
	 **/
	@Override
	public void exportEvaObjectByPeriodCode(HttpServletRequest request, HttpServletResponse
			response, String periodcode) {
		List<Map<String,Object>> data = new ArrayList<>();
		//查询期间下的所有方案集合
		List<Scheme> schemeList = queryFillInSchemeListByPeirodCode(periodcode);
		if(CollectionUtils.isNotEmpty(schemeList)){
			// Map<String, Scheme> schemeMap = schemeList.stream().collect(Collectors.toMap(Scheme::getId, Function.identity()));
			Map<String, Scheme> schemeMap = ListHelper.toMap(schemeList, "getId");
			//根据传入的期间code获取期间名称
			String periodName = queryPeriodNameByPeirodCode(periodcode);
			//查询该方案下所有考核对象
			// List<String> schemeidList = schemeList.stream().map(Scheme::getId).collect(Collectors.toList());
			List<String> schemeidList = ListHelper.collect(schemeList, "getId");
			List<EvaObject> evaObjectList = queryEvaObjPageBySchemeList(schemeidList);
			//查询方案所属组织信息
			Map<String,CommonOrg> orgMap = queryCommonOrgIdAndOrgMapBySchemeIdList(schemeidList,schemeMap);
			//获取考核对象的人员信息
			// List<String> staffidList = evaObjectList.stream().map(EvaObject::getStaffid).collect(Collectors.toList());
			List<String> staffidList = ListHelper.collect(evaObjectList, "getStaffid");
			//查询量表数据
			Condition sheetConditon = new Condition();
			sheetConditon.addExpression("schemeid",schemeidList,Operator.IN);
			sheetConditon.addExpression("staffid",staffidList,Operator.IN);
			List<Sheet> sheetList = daoex.find(Sheet.class, sheetConditon, null);
			// List<String> sheetIdList = sheetList.stream().map(Sheet::getId).collect(Collectors.toList());
			List<String> sheetIdList = ListHelper.collect(sheetList, "getId");
			// Map<String, Sheet> sheetSchemeIdANdStaffIdMap = sheetList.stream().collect(
			// Collectors.toMap(sheet->sheet.getSchemeid()+sheet.getStaffid(),
			// Function.identity()));
			Map<String, Sheet> sheetSchemeIdANdStaffIdMap = new Hashtable<>();
			for (Sheet sheet : sheetList) {
				sheetSchemeIdANdStaffIdMap.put(sheet.getSchemeid() + sheet.getStaffid(), sheet);
			}
			//根据量表id查询工作流信息
			Condition wfengineCondition = new Condition();
			wfengineCondition.addExpression("bizid",sheetIdList,Operator.IN);
			wfengineCondition.addExpression("workstep", EnumWorkStep.step1.getIndex());
			List<WorkflowEngine> workflowEngineList = daoex.find(WorkflowEngine.class, wfengineCondition, null);
			// Map<String, List<WorkflowEngine>> wfSheetIdMap = workflowEngineList.stream().collect(Collectors.groupingBy(WorkflowEngine::getBizid));
			Map<String, List<WorkflowEngine>> wfSheetIdMap = ListHelper.groupingBy(workflowEngineList, "getBizid");

			//获取人员的部门编码
			Map<String, PmStaff> pmStaffMap = StaffHelper.queryStaffByIds(staffidList);
			Map<String, String> deptIdANdCodeMap = queryDeptCodeByStaffIdList(pmStaffMap);
			//获取所有的分组信息
			Map<String, String> groupMap = queryGroupNameByEvaObject(evaObjectList);

			//获取最大轮次数
			Condition turnConditon = new Condition();
			turnConditon.addExpression("workstep", EnumWorkStep.step1.getIndex());
			turnConditon.addExpression("bizinfo",schemeidList,Operator.IN);
			turnConditon.addExpression("tenantid",AppContext.getContext().getScope());
			Integer maxTurn = operationDao.queryMaxTurnByCondition(turnConditon);
			for (EvaObject evaObject : evaObjectList) {
				Map<String,Object> infoMap = new HashMap<>();
				String schemeid = evaObject.getSchemeid();
				String staffid = evaObject.getStaffid();
				infoMap.put("periodname",periodName);
				if(pmStaffMap.get(staffid) != null && pmStaffMap.get(staffid).deptid != null){
					String deptcode = deptIdANdCodeMap.get(pmStaffMap.get(staffid).deptid);
					infoMap.put("staffcode",pmStaffMap.get(staffid).code == null ? "":pmStaffMap.get(staffid).code);
					infoMap.put("staffname",pmStaffMap.get(staffid).name == null ? "":pmStaffMap.get(staffid).name);
					infoMap.put("psnclname",pmStaffMap.get(staffid).psnclname == null ? "":pmStaffMap.get(staffid).psnclname);
					infoMap.put("deptcode",deptcode == null ? "":deptcode);
					infoMap.put("deptname",pmStaffMap.get(staffid).deptname == null ? "":pmStaffMap.get(staffid).deptname);
				}else{
					infoMap.put("staffcode","");
					infoMap.put("staffname","");
					infoMap.put("psnclname","");
					infoMap.put("deptcode","");
					infoMap.put("deptname","");
				}
				infoMap.put("schemename",schemeMap.get(schemeid).getSchemename());
				infoMap.put("schemestate",CommonValue.EnumSchemeState.values()[schemeMap.get(schemeid).getSchemestate()].getDescription());
				infoMap.put("groupname",groupMap.get(evaObject.getGroupid()));
				if(sheetSchemeIdANdStaffIdMap.get(schemeid+staffid).getMarkStatus() < CommonValue.EnumMarkState10.State2.getIndex()){
					infoMap.put("submitted","否");
				}else{
					infoMap.put("submitted","是");
				}
				if(maxTurn != null){
					List<String> stepturns = new ArrayList<>(maxTurn);
					List<WorkflowEngine> workflowEngines = wfSheetIdMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId());
					if(CollectionUtils.isNotEmpty(workflowEngines)){
						// Map<String, Integer> wfSheetidStepAndStateMap = workflowEngines.stream().
						// collect(Collectors.toMap(wf -> wf.getBizid() + wf.getStepserial(),
						// WorkflowEngine::getState));
						Map<String, Integer> wfSheetidStepAndStateMap = new Hashtable<>();
						for (WorkflowEngine wf : workflowEngines) {
							wfSheetidStepAndStateMap.put(wf.getBizid() + wf.getStepserial(), wf.getState());
						}
						for (int i = 1; i <= maxTurn ; i++) {
							if(wfSheetidStepAndStateMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId()+i) != null){
								Integer wfState = wfSheetidStepAndStateMap.get(sheetSchemeIdANdStaffIdMap.get(schemeid + staffid).getId()+i);
								if(wfState < CommonValue.EnumWorkflowState.PASS_AUDIT.getIndex()){
									stepturns.add("否");
								}else{
									stepturns.add("是");
								}
							}else{
								stepturns.add("");
							}
						}
					}else{
						for (int i = 1; i <= maxTurn ; i++) {
							stepturns.add("");
						}
					}
					infoMap.put("stepturns",stepturns);
				}else{
					infoMap.put("stepturns",new ArrayList<String>(0));
				}
				//设置方案组织编码和组织名称
				if(orgMap.get(schemeMap.get(schemeid).getOrgid()) != null){
					infoMap.put("schemeorgcode",orgMap.get(schemeMap.get(schemeid).getOrgid()).getCode());
					infoMap.put("schemeorgname",orgMap.get(schemeMap.get(schemeid).getOrgid()).getName());
				}else{
					infoMap.put("schemeorgcode","");
					infoMap.put("schemeorgname","");
				}
				data.add(infoMap);
			}
		}
		if(CollectionUtils.isNotEmpty(data)){
			excelService.exportFillInEvaObjectByPeriod2Excel(request,response,data);
		}
	}

	/**
	 * @param request
	 * @param response
	 * @param scheme
	 * @return void
	 * @author ZhangTao
	 * @description 根据该方案id导出方案下考核对象的考核结果
	 * @date 2019/10/26
	 **/
	@Override
	public void exportEvaObjectBySchemeId(HttpServletRequest request, HttpServletResponse response, Scheme scheme) {
		String schemeid = scheme.getId();
		//查询方案量表
		Condition sheetConditon = new Condition();
		sheetConditon.addExpression("schemeid",schemeid);
		sheetConditon.addExpression("enablestate",1);
		List<Sheet> sheetList = daoex.find(Sheet.class, sheetConditon, null);
		if(CollectionUtils.isNotEmpty(sheetList)){
			List<Map<String,String>> dataList = new ArrayList<>();
			//查询人员
            List<String> staffidList = ListHelper.collect(sheetList, "getStaffid");
            List<PmStaff> pmStaffList = StaffHelper.queryStaffByIds3(staffidList);
			Collections.sort(pmStaffList);
			//根据考核对象查询考核对象分组信息
			Condition evaCondition = new Condition();
			evaCondition.addExpression("schemeid",schemeid);
			evaCondition.addExpression("staffid",staffidList,Operator.IN);
			List<EvaObject> evaObjectList = daoex.find(EvaObject.class, evaCondition, null);
			Map<String, String> staffidAndGroupidMap = ListHelper.collect(evaObjectList, "getStaffid", "getGroupid");
			List<String> groupidList = ListHelper.collect(evaObjectList, "getGroupid");
			List<EvaGroup> groupList = daoex.findByIds(EvaGroup.class, groupidList.toArray(new String[groupidList.size()]));
			Map<String, String> groupidAndNameMap = ListHelper.collect(groupList, "getId", "getGroupname");
			//查询考核得分
			Condition numCondition = new Condition();
			numCondition.addExpression("schemeid",schemeid);
			numCondition.addExpression("staffid",staffidList,Operator.IN);
			numCondition.addExpression("columncode","003");
			List<Score> numScoreList = daoex.find(Score.class, numCondition, null);
			Map<String, Score> numMap = ListHelper.toMap(numScoreList, "getStaffid");
			//查询考核等级
			Condition textCondition = new Condition();
			textCondition.addExpression("schemeid",schemeid);
			textCondition.addExpression("staffid",staffidList,Operator.IN);
			textCondition.addExpression("columncode","010");
			List<Score> textScoreList = daoex.find(Score.class, textCondition, null);
			Map<String, String> textMap = ListHelper.collect(textScoreList, "getStaffid", "getText");
			for (PmStaff pmStaff : pmStaffList) {
				Map<String,String> data = new HashMap<>();
				data.put("staffcode",pmStaff.code == null ? "" : pmStaff.code);
				data.put("staffname",pmStaff.name);
				data.put("orgname",pmStaff.corpname == null ? "" : pmStaff.corpname);
				data.put("deptname",pmStaff.deptname == null ? "" : pmStaff.deptname);
				data.put("psnclname",pmStaff.psnclname == null ? "" : pmStaff.psnclname);
				data.put("groupname",groupidAndNameMap.get(staffidAndGroupidMap.get(pmStaff.id)));
				data.put("numvalue",numMap.get(pmStaff.id).getNumvalue() == null ?
						"" : numMap.get(pmStaff.id).getNumvalue().stripTrailingZeros().toPlainString());
				data.put("text",textMap.get(pmStaff.id));
				dataList.add(data);
			}
			excelService.exportEvaObjectByScheme2Excel(request,response,dataList,scheme.getSchemename());
		}else{
			throw new AdderBusinessException("考核对象异常，请检查", "pm.i18n_pbc.ps.009");
		}
	}

    /**
     * @param request
     * @param response
     * @param schemeid
     * @return void
     * @author ZhangTao
     * @description 导出绩效考核结果与指标得分
     * @date 2019/9/16
     **/
    @Override
    public void exportFinalScoreAndIndiScore(HttpServletRequest request, HttpServletResponse response, String schemeid) {
        Map<String,Object> data = new HashMap<>();
        Scheme scheme = daoex.load(Scheme.class, schemeid);
        if(scheme == null){
            throw new AdderBusinessException("当前方案不存在！", "pm.i18n_core.ps.025");
        }
        Period period = daoex.load(Period.class, scheme.getPeriodid());
        data.put("schemeName",scheme.getSchemename());
        data.put("periodName",period.getPeriodname());
        //根据方案查询当前人员有权限的量表
        List<Sheet> sheetList = querySheetListBySchemeAndDeptid(schemeid);
        if(CollectionUtils.isNotEmpty(sheetList)){
            List<String> sheetidList = sheetList.stream().map(Sheet::getId).collect(Collectors.toList());
            //获取人员id集合
            List<String> staffidList = sheetList.stream().map(Sheet::getStaffid).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(staffidList)){
                //根据sheetid集合查询sheetdata
                Condition dataCondition = new Condition();
                dataCondition.addExpression("sheetid",sheetidList,Operator.IN);
                dataCondition.addExpression("columncode",Arrays.asList("006","007"),Operator.IN);
                List<SheetData> sheetDataList = daoex.find(SheetData.class, dataCondition, null);
                Map<String,BigDecimal> indiScoreMap = new HashMap<>(4);
                Map<String,String> actFinishTextMap = new HashMap<>(4);
                sheetDataList.forEach(sheetData -> {
                    String sheetid = sheetData.getSheetid();
                    String columncode = sheetData.getColumncode();
                    String indicatorId = sheetData.getIndicatorid();
                    if("006".equals(columncode)){
                        actFinishTextMap.put(indicatorId+sheetid,sheetData.getText());
                    }
                    if("007".equals(columncode)){
                        indiScoreMap.put(indicatorId+sheetid,sheetData.getNumvalue());
                    }
                });
                //根据sheetid结合查询appraisedata，查询评分具体数据
                Condition appCondition = new Condition();
                appCondition.addExpression("sheetid",sheetidList,Operator.IN);
                appCondition.addExpression("columncode",Arrays.asList("008","009"),Operator.IN);
                List<AppraiseData> appraiseDataList = daoex.find(AppraiseData.class, appCondition,
                        new Sorter(Direction.ASC, Arrays.asList("sheetid", "indicatorid","turn")));
                Set<String> appraiserSet = appraiseDataList.stream().map(appraiseData -> appraiseData.getAppraiser()).collect(Collectors.toSet());
                appraiserSet.addAll(staffidList);
                //查询人员信息
                Map<String, PmStaff> pmStaffMap = StaffHelper.queryStaffByIds(new ArrayList<>(appraiserSet));
                //将查询出的apprasedata数据按照指标id和sheetid分组，用于下边匹配数据
                Map<String,List<AppraiseData>> indiAndSheetAndAppdataMap = new HashMap<>();
                appraiseDataList.forEach(appraiseData -> {
                    String indicatorid = appraiseData.getIndicatorid();
                    String sheetid = appraiseData.getSheetid();
                    if(indiAndSheetAndAppdataMap.get(indicatorid+sheetid) == null){
                        List<AppraiseData> appraiseDatas = new ArrayList<>();
                        appraiseDatas.add(appraiseData);
                        indiAndSheetAndAppdataMap.put(indicatorid+sheetid,appraiseDatas);
                    }else{
                        List<AppraiseData> appraiseDatas = indiAndSheetAndAppdataMap.get(indicatorid+sheetid);
                        appraiseDatas.add(appraiseData);
                    }
                });
                //获取人员id对应sheetid的map
                Map<String, String> staffIdAndSheetIdMap = sheetList.stream().collect(
                        Collectors.toMap(Sheet::getStaffid, Sheet::getId));
                Condition scoreCondition = new Condition();
                scoreCondition.addExpression("sheetid",sheetidList,Operator.IN);
                scoreCondition.addExpression("columncode",Arrays.asList(CommonValue.EnumSchemeScoreColumnCode.CODE003.getCode(),
                        CommonValue.EnumSchemeScoreColumnCode.CODE010.getCode()),Operator.IN);
                List<Score> scoreList = daoex.find(Score.class, scoreCondition, null);
                Map<String,BigDecimal> scoreMap = new HashMap<>(4);
                Map<String,String> gradeMap = new HashMap<>(4);
                //查询人员的确认分数和确认等级
                scoreList.forEach(score->{
                    String staffid = score.getStaffid();
                    String columncode = score.getColumncode();
                    if(CommonValue.EnumSchemeScoreColumnCode.CODE003.getCode().equals(columncode)){
                        scoreMap.put(staffid,score.getNumvalue());
                    }
                    if(CommonValue.EnumSchemeScoreColumnCode.CODE010.getCode().equals(columncode)){
                        gradeMap.put(staffid,score.getText());
                    }
                });
                //根据量表id查询量表的所有指标集合
                Condition sheetIndiCondition = new Condition();
                sheetIndiCondition.addExpression("sheetid",sheetidList,Operator.IN);
                List<SheetIndicator> sheetIndicatorList = daoex.find(SheetIndicator.class, sheetIndiCondition,
                        new Sorter(Direction.ASC, Arrays.asList("sheetid", "disp_seq")));
                //将查询到的指标数据按照指标分类和sheetid分组
                Map<String,List<SheetIndicator>> indiClassAndSheetidAndSheetIndiMap = new HashMap<>();
                sheetIndicatorList.forEach(sheetIndicator -> {
                    if(indiClassAndSheetidAndSheetIndiMap.get(sheetIndicator.getIndiParent()+sheetIndicator.getSheetid()) == null){
                        List<SheetIndicator> sheetIndiList = new ArrayList<>();
                        sheetIndiList.add(sheetIndicator);
                        indiClassAndSheetidAndSheetIndiMap.put(sheetIndicator.getIndiParent()+sheetIndicator.getSheetid(),sheetIndiList);
                    }else{
                        List<SheetIndicator> sheetIndiList = indiClassAndSheetidAndSheetIndiMap.get(
                                sheetIndicator.getIndiParent()+sheetIndicator.getSheetid());
                        sheetIndiList.add(sheetIndicator);
                    }

                });
                //根据sheetid查询sheetid下边指标分类的分组信息，用于根据sheetid获取所有的指标分组数据
                Map<String, Set<String>> sheetIdAndIndiClassIdMap = sheetIndicatorList.stream().collect(Collectors.groupingBy(
                        SheetIndicator::getSheetid, Collectors.mapping(SheetIndicator::getIndiParent, Collectors.toCollection(TreeSet::new))));
                //查询指标分类信息，并转成map，用于匹配
                Map<String,IndicatorClass> indicatorClassMap = new HashMap<>();
                //查询指标信息，并转成map，用于匹配
                Map<String,Indicator> indicatorMap = new HashMap<>();
                if(CollectionUtils.isNotEmpty(sheetIndicatorList)){
                    String[] indiClassIdArray = sheetIndicatorList.stream().map(SheetIndicator::getIndiParent).
                            toArray(String[]::new);
                    List<IndicatorClass> indiClassList = daoex.findByIds(IndicatorClass.class, indiClassIdArray);
                    indicatorClassMap = indiClassList.stream().collect(Collectors.toMap(IndicatorClass::getId,Function.identity()));
                    String[] indiIdArray = sheetIndicatorList.stream().map(SheetIndicator::getIndicatorid).
                            toArray(String[]::new);
                    List<Indicator> indiList = daoex.findByIds(Indicator.class, indiIdArray);
                    indicatorMap = indiList.stream().collect(Collectors.toMap(Indicator::getId,Function.identity()));
                }
                //查询轮次的评分信息，封装到数据
                Condition appraiseCondition = new Condition();
                appraiseCondition.addExpression("sheetid",sheetidList,Operator.IN);
                List<Appraise> appraiseList = daoex.find(Appraise.class, appraiseCondition,
                        new Sorter(Direction.ASC, Arrays.asList("sheetid", "turn")));
                Map<String, List<Appraise>> appraiseMap = appraiseList.stream().collect(Collectors.groupingBy(Appraise::getSheetid));
                List<Map<String,Object>> dataList = new ArrayList<>();
                BigDecimal hundred = new BigDecimal(100);
                //封装组织数据
                for (String staffid : staffidList) {
                    PmStaff pmStaff = pmStaffMap.get(staffid);
                    Map<String,Object> dataMap = new HashMap<>();
                    dataMap.put("staffCode",pmStaff.code == null ? "" : pmStaff.code);//人员编码
                    dataMap.put("staffName",pmStaff.name == null ? "" : pmStaff.name);//人员姓名
                    dataMap.put("orgName",pmStaff.corpname == null ? "" : pmStaff.corpname);//人员组织名称
                    dataMap.put("deptName",pmStaff.deptname == null ? "" : pmStaff.deptname);//人员部门名称
                    dataMap.put("score",scoreMap.get(staffid) == null ? "" : scoreMap.get(staffid).stripTrailingZeros().toPlainString());//考核得分
                    dataMap.put("grade",gradeMap.get(staffid) == null ? "" : gradeMap.get(staffid));//考核等级
                    //指标分类集合
                    List<Map<String,Object>> indiClassList = new ArrayList<>();
                    String sheetid = staffIdAndSheetIdMap.get(staffid);
                    //获取指标分类的集合
                    Set<String> indiClassIdSet = sheetIdAndIndiClassIdMap.get(sheetid);
                    for (String indiClassId : indiClassIdSet) {
                        List<SheetIndicator> sheetIndicators = indiClassAndSheetidAndSheetIndiMap.get(indiClassId + sheetid);
                        Map<String,Object> indiClassMap = new HashMap<>();
                        //指标分类名称
                        indiClassMap.put("indiClassName",indicatorClassMap.get(indiClassId).getIndiclassname());
                        //指标分类权重
						if(scheme.isIsdoubleweight()){
							indiClassMap.put("indiClassWeight", sheetIndicators.get(0).getIndiclassWeight().multiply(hundred).stripTrailingZeros().toPlainString()+"%");
						}else{
							indiClassMap.put("indiClassWeight", "");
						}
                        //获取指标集合
                        List<Map<String,Object>> indiList = new ArrayList<>();
                        for (SheetIndicator sheetIndicator : sheetIndicators) {
                            Map<String,Object> sheetIndiMap = new HashMap<>();
                            String indicatorId = sheetIndicator.getIndicatorid();
                            //指标名称
                            sheetIndiMap.put("indiName",indicatorMap.get(indicatorId).getIndiname());
                            //指标权重
                            sheetIndiMap.put("indiWeight",sheetIndicator.getActWeight().multiply(hundred).stripTrailingZeros().toPlainString()+"%");
                            //指标得分
                            sheetIndiMap.put("indiScore",indiScoreMap.get(indicatorId+sheetid) == null ? "" :
                                    indiScoreMap.get(indicatorId+sheetid).stripTrailingZeros().toPlainString()+"分");
                            //指标轮次打分信息
                            List<AppraiseData> appraiseDatas = indiAndSheetAndAppdataMap.get(indicatorId+sheetid);
                            Map<Integer, String> turnScoreMap = appraiseDatas.stream().filter(appraiseData -> "008".
                                    equals(appraiseData.getColumncode())).collect(Collectors.groupingBy(
                                    AppraiseData::getTurn, Collectors.mapping(appraiseData->pmStaffMap.get(
                                            appraiseData.getAppraiser()).name+" "+(appraiseData.getNumvalue() == null ? "":
                                                    appraiseData.getNumvalue().stripTrailingZeros().toPlainString()+"分")
                                            , Collectors.joining("\n"))));
                            Map<Integer, String> turnTextMap = appraiseDatas.stream().filter(appraiseData -> "009".
                                    equals(appraiseData.getColumncode()) && appraiseData.getText() != null).collect(Collectors.groupingBy(
                                            AppraiseData::getTurn, Collectors.mapping(AppraiseData::getText, Collectors.joining("\n"))));
                            List<Map<String,Object>> indiTurnInfo = new ArrayList<>();
                            turnScoreMap.forEach((turn,scoreStr)->{
                                Map<String,Object> turnInfoMap = new HashMap<>(8);
                                turnInfoMap.put("turn","第" + turn + "轮");
                                turnInfoMap.put("actFinish",actFinishTextMap.get(indicatorId+sheetid) == null ? "" :actFinishTextMap.get(indicatorId+sheetid));
                                turnInfoMap.put("turnText",turnTextMap.get(turn) == null ? "" : turnTextMap.get(turn));
                                turnInfoMap.put("turnScore",scoreStr);
                                indiTurnInfo.add(turnInfoMap);
                            });
                            sheetIndiMap.put("indiTurnInfo",indiTurnInfo);
                            indiList.add(sheetIndiMap);
                        }
                        indiClassMap.put("indiList",indiList);
                        indiClassList.add(indiClassMap);
                    }
                    dataMap.put("indiClassList",indiClassList);
                    dataMap.put("turnTotalInfo",appraiseMap.get(sheetid));
                    dataList.add(dataMap);
                }
                data.put("list",dataList);
                excelService.exportFinalScoreAndIndiScore(request,response,data);
            }
        }else{
            throw new AdderBusinessException("{0}", "pm.i18n_flow.wf.001", "该方案下未查询到符合条件的考核结果");
        }
    }

    /**
     * @author ZhangTao
     * @description 根据方案查询当前人员有权限的量表
     * @date 2019/9/16
     * @param schemeid
     * @return java.util.List<com.yonyou.hrcloud.pm.ps.model.Sheet>
     **/
    private List<Sheet> querySheetListBySchemeAndDeptid(String schemeid){
        Condition condObj = new Condition();
        String runtime = PropertyUtil.getPropertyByKey("runtime", "prod");
        if ("dev".equals(runtime)) {
            String userid = AppContext.getContext().getUserId();
            String staffid = StaffHelper.getStaffByUserId(userid);
            Map<String, PmStaff> pmStaffMap = StaffHelper.queryStaffByIds(Arrays.asList(staffid));
            condObj.addExpression("deptid", pmStaffMap.get(staffid).deptid);
        }
        else {
            OrgHelper.setOrgCondition(condObj,"deptid", CommonValue.EnumServiceCode.SCHEME.getCode());
        }
        condObj.addExpression("schemeid",schemeid);
        condObj.addExpression("enablestate","1");
        List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
        return sheetList;
    }

    /**
	 * @author ZhangTao
	 * @description 根据绩效期间code查询填报阶段的考核方案集合
	 * @date 2019/6/20
	 * @param periodcode
	 * @return java.util.List<com.yonyou.hrcloud.pm.ps.model.Scheme>
	 **/
	private List<Scheme> queryFillInSchemeListByPeirodCode(String periodcode){
		Condition condObj = new Condition();
		condObj.addExpression("schememode", CommonValue.EnumSchemeMode.pm_pbc.getIndex());
		condObj.addExpression("tenantid", AppContext.getContext().getScope());
		condObj.addExpression("schemestate", CommonValue.EnumSchemeState.State3.getIndex(), Operator.GREATEREQUAL);
		condObj.addExpression("schemestate", CommonValue.EnumSchemeState.State4.getIndex(), Operator.LESSEQAUL);
		condObj.addExpression("periodcode",periodcode);
		String userid = AppContext.getContext().getUserId();
		String runtime = PropertyUtil.getPropertyByKey("runtime", "prod");
		if ("dev".equals(runtime)) {
			condObj.addExpression("creator", userid);
		}
		else {
			OrgHelper.setOrgCondition(condObj, CommonValue.EnumServiceCode.SCHEME.getCode());
		}
		Sorter sortObj = new Sorter(Direction.DESC, Arrays.asList("tdate"));
		Sorter sortObj2 = new Sorter(Direction.DESC, Arrays.asList("periodcode", "creationtime"));
		sortObj = sortObj.and(sortObj2);
		//查询期间下的所有方案集合
		List<Scheme> schemeList = daoex.find(Scheme.class, condObj, sortObj);
		return schemeList;
	}

	/**
	 * @author ZhangTao
	 * @description 根据传入的期间code获取期间名称
	 * @date 2019/6/20
	 * @param periodcode
	 * @return java.lang.String
	 **/
	private String queryPeriodNameByPeirodCode(String periodcode){
		Condition periodConditon = new Condition();
		periodConditon.addExpression("periodcode",periodcode);
		List<Period> periodList = daoex.find(Period.class,periodConditon,null);
		String periodName = "";
		if(CollectionUtils.isNotEmpty(periodList)){
			periodName = periodList.get(0).getPeriodname();
		}
		return periodName;
	}

	/**
	 * @author ZhangTao
	 * @description 根据方案分页查询对应的考核对象
	 * @date 2019/6/20
	 * @param schemeidList
	 * @param pageNum
	 * @param pageSize
	 * @return org.springframework.data.domain.Page<com.yonyou.hrcloud.pm.ps.model.EvaObject>
	 **/
	private Page<EvaObject> queryEvaObjPageBySchemeList(List<String> schemeidList,int pageNum,int pageSize){
		Condition evaObjCondition = new Condition();
		evaObjCondition.addExpression("schemeid",schemeidList,Operator.IN);
		Sorter evaObjSort = new Sorter(Direction.ASC,Arrays.asList("groupid","staffid"));
		Pageable page = new PagerRequest(pageNum,pageSize,evaObjSort);
		Page<EvaObject> evaObjPage = daoex.findPage(EvaObject.class, evaObjCondition, page);
		return evaObjPage;
	}

    /**
	 * @author ZhangTao
	 * @description 根据方案查询对应的考核对象
	 * @date 2019/6/20
	 * @param schemeidList
	 * @return java.util.List<com.yonyou.hrcloud.pm.ps.model.EvaObject>
	 **/
	private List<EvaObject> queryEvaObjPageBySchemeList(List<String> schemeidList){
		Condition evaObjCondition = new Condition();
		evaObjCondition.addExpression("schemeid",schemeidList,Operator.IN);
		Sorter evaObjSort = new Sorter(Direction.ASC,"groupid");
		List<EvaObject> evaObjList = daoex.find(EvaObject.class,evaObjCondition,evaObjSort);
		return evaObjList;
	}

	/**
	 * @author ZhangTao
	 * @description 根据方案id集合查询所有组织信息
	 * @date 2019/6/20
	 * @param
	 * @return java.util.Map<java.lang.String,com.yonyou.iuap.org.admin.dto.CommonOrg>
	 **/
	private Map<String,CommonOrg> queryCommonOrgIdAndOrgMapBySchemeIdList(List<String> pageSchemeidList,Map<String,Scheme> schemeMap){
		List<String> orgidList = new ArrayList<>();
		for (int i = 0; i < pageSchemeidList.size(); i++) {
			if(StringUtils.isNotEmpty(schemeMap.get(pageSchemeidList.get(i)).getOrgid())){
				orgidList.add(schemeMap.get(pageSchemeidList.get(i)).getOrgid());
			}
		}
		Map<String,CommonOrg> orgMap = new HashMap<>();
		if(CollectionUtils.isNotEmpty(orgidList)){
			List<CommonOrg> orgList = OrgHelper.queryAdminOrgsByidList(orgidList);
            List<CommonOrg> deptList = OrgHelper.querydeptsByidList(orgidList);
            if(CollectionUtils.isNotEmpty(deptList)){
               orgList.addAll(deptList);
            }
            // orgMap = orgList.stream().collect(Collectors.toMap(CommonOrg::getId,Function.identity()));
			orgMap = ListHelper.toMap(orgList, "getId");
		}
		return orgMap;
	}

	/**
	 * @author ZhangTao
	 * @description 获取人员的部门编码
	 * @date 2019/6/20
	 * @param pmStaffMap
	 * @return java.util.Map<java.lang.String,java.lang.String>
	 **/
	private Map<String,String> queryDeptCodeByStaffIdList(Map<String, PmStaff> pmStaffMap){
		// List<String> deptids = pmStaffMap.values().stream().filter(pmstaff ->
		// StringUtils.isNotEmpty(pmstaff.deptid)).map(pmStaff -> pmStaff.deptid)
		// .distinct().collect(Collectors.toList());
		List<String> deptids = ListHelper.filterAndcollect(new ArrayList<PmStaff>(pmStaffMap.values()), "deptid", false,
				"deptid");
		List<CommonOrg> CommonOrgList = OrgHelper.querydeptsByidList(deptids);
		// Map<String, String> deptIdANdCodeMap = CommonOrgList.stream().collect(Collectors.toMap(CommonOrg::getId, CommonOrg::getCode));
		Map<String, String> deptIdANdCodeMap = ListHelper.toMap(CommonOrgList, "getId", "getCode");
		return deptIdANdCodeMap;
	}

	/**
	 * @author ZhangTao
	 * @description 获取所有的分组信息
	 * @date 2019/6/20
	 * @param evaObjectList
	 * @return java.util.Map<java.lang.String,java.lang.String>
	 **/
	private Map<String,String> queryGroupNameByEvaObject(List<EvaObject> evaObjectList){
		// String[] groupidArray =
		// evaObjectList.stream().map(EvaObject::getGroupid).distinct().toArray(String[]::new);
		List<String> groupidArrayTmp = ListHelper.collect(evaObjectList, "getGroupid");
		String[] groupidArray = groupidArrayTmp.toArray(new String[groupidArrayTmp.size()]);
		List<EvaGroup> groupList = daoex.findByIds(EvaGroup.class, groupidArray);
		// Map<String, String> groupMap = groupList.stream().collect(Collectors.toMap(EvaGroup::getId, EvaGroup::getGroupname));
		Map<String, String> groupMap = ListHelper.toMap(groupList, "getId", "getGroupname");
		return groupMap;
	}

    /**
     * 指标填报数据是否存在
     *
     * @param schemeid
     * @return true有数据；false无数据
     */
    private boolean haveSheetData(String schemeid) {
        Condition condObj = new Condition();
        condObj.addExpression("schemeid", schemeid);
        Pageable page = new PagerRequest(0, 1);
        List<SheetData> sheetDataList = daoex.findPage(SheetData.class,
                condObj, page).getContent();
        return !sheetDataList.isEmpty();
    }

	/**
	 * 生成初始量表，支持重复创建
	 *
	 * @param scheme
	 * @param onlycheck
	 *            是否只检查
	 */
	private void doInitSheet(Scheme scheme, boolean onlycheck) {
		// 查找之前创建过的量表
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		List<Sheet> sheetOldList = daoex.find(Sheet.class, condObj, null);
        /*Map<String, String> sheetOldMap = sheetOldList.stream().collect(
                Collectors.toMap(Sheet::getStaffid, Sheet::getId));*/
        Map<String, String> sheetOldMap = ListHelper.toMap(sheetOldList, "getStaffid", "getId");
		List<String> ids = new ArrayList<String>();
		List<Sheet> sheetList = new ArrayList<Sheet>();
		// 要保证scheme.getOGroups()是有的
		for (EvaGroup item : scheme.getOGroups()) {
			// scheme中没有查询考核对象，这里进行加载
			EvaGroup group = item;
			if (CollectionUtils.isEmpty(group.getOEvaObjects()))
				group = daoGroup.queryEvaGroupByID(item.getId(), false);
			if (CollectionUtils.isEmpty(group.getOEvaObjects()))
				throw new AdderBusinessException("考核对象异常，请检查", "pm.i18n_pbc.ps.009");
			for (EvaObject psn : group.getOEvaObjects()) {
				// 新增的人员添加到sheetList
				if (sheetOldMap.containsKey(psn.getStaffid()))
					continue;
				Sheet sheet = new Sheet();
				sheet.setStaffid(psn.getStaffid());
				ids.add(psn.getStaffid());
				sheet.setSchemeid(scheme.getId());
				sheet.setEnablestate(true);
				sheet.setPeriodcode(scheme.getPeriodcode());
				sheetList.add(sheet);
			}
		}
		if (sheetList.isEmpty() && sheetOldList.isEmpty())
			throw new AdderBusinessException("方案设置不完整", "pm.i18n_pbc.ps.001");
        Map<String, PmStaff> staffMap = StaffHelper.queryStaffByIds(ids);
		for (Sheet item : sheetList) {
			if (staffMap.get(item.getStaffid()) == null) {
				logger.error("pm:考核对象异常，请检查。" + item.getStaffid());
				throw new AdderBusinessException("考核对象异常，请检查", "pm.i18n_pbc.ps.009");
			}
			item.setDeptid(staffMap.get(item.getStaffid()).deptid);
		}
		// 保存新增的量表
		if (!sheetList.isEmpty() && !onlycheck) {
			daoex.insertByBatch(sheetList);
		}
		sheetOldList = null;
		sheetOldMap = null;
		ids = null;
		sheetList = null;
		staffMap = null;
	}

    /**
     * 给审核人数据赋值部门id
     *
     * @param appScoreList
     */
    private void setStaffDeptid(List<ApproveScore> appScoreList) {
        List<String> ids = new ArrayList<String>();
        for (ApproveScore item : appScoreList) {
            if (!ids.contains(item.getAuditor()))
                ids.add(item.getAuditor());
        }
        Map<String, PmStaff> staffList = StaffHelper.queryStaffByIds(ids);
        for (ApproveScore item : appScoreList) {
            if (staffList.get(item.getAuditor()) == null)
                throw new AdderBusinessException("未获取到人员信息", "pm.i18n_core.comm.010");
            item.setDeptid(staffList.get(item.getAuditor()).deptid);
        }
    }

    /**
     * 根据考核对象找到量表id集合
     *
     * @param evaObjectList
     * @return
     */
	private List<Sheet> getSheetidByEvaObject(List<EvaObject> evaObjectList) {
		List<String> staffids = new ArrayList<String>();
		String schemeid = "";
		for (EvaObject item : evaObjectList) {
			staffids.add(item.getStaffid());
			schemeid = item.getSchemeid();
		}
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		condObj.addExpression("staffid", staffids, Operator.IN);
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		return sheetList;
	}

    /**
     * 获取指定方案环节的待办流程数据
     *
     * @param schemeid
     * @param workstep
     * @return
     */
    private List<WorkflowEngine> getPendingWorkflow(String schemeid, EnumWorkStep workstep) {
        BaseParam param = new BaseParam();
        param.setBizinfo(Arrays.asList(schemeid));
        param.setWorkstep(workstep);
        param.setBiztype(CommonValue.EnumWorkflowType.performance);
        param.setWorkflowState(CommonValue.EnumWorkflowState.PENDING);
        List<WorkflowEngine> engines = wfSrv.queryWorkflowEngine(param);
        return engines;
    }

    /**
     * @author ZhangTao
     * @description 获取制定方案环节的审核通过流程数据
     * @date 2019/3/23
     * @param schemeid  方案id
     * @param workstep  指定环节
     * @return java.util.List<com.yonyou.hrcloud.pm.wf.model.WorkflowEngine>
     **/
    private List<WorkflowEngine> getPassAuditWorkflow(String schemeid, EnumWorkStep workstep){
		BaseParam param = new BaseParam();
		param.setBizinfo(Arrays.asList(schemeid));
		param.setWorkstep(workstep);
		param.setBiztype(CommonValue.EnumWorkflowType.performance);
		param.setWorkflowState(CommonValue.EnumWorkflowState.PASS_AUDIT);
		List<WorkflowEngine> engines = wfSrv.queryWorkflowEngine(param);
		return engines;
	}

    /**
     * 转换工作流状态名称和序号
     *
     * @param workstep
     * @param state
     * @return
     */
    private String[] getWorkflowStateName(EnumWorkStep workstep, int state) {
        String[] strState = new String[2];
        if (workstep.equals(EnumWorkStep.step2)) {
            if (state >= CommonValue.EnumWorkflowState.PASS_AUDIT.getIndex()) {
                strState[0] = CommonValue.EnumMarkState.State3.getDescription();
                strState[1] = String.valueOf(CommonValue.EnumRemind.State3.getIndex());
            } else {
                strState[0] = CommonValue.EnumMarkState.State1.getDescription();
                strState[1] = String.valueOf(CommonValue.EnumRemind.State2.getIndex());
            }
        } else {
            if (state >= CommonValue.EnumWorkflowState.PASS_AUDIT.getIndex()) {
                strState[0] = CommonValue.EnumMarkState30.State3.getDescription();
                strState[1] = String.valueOf(CommonValue.EnumRemind.State5.getIndex());
            } else {
                strState[0] = CommonValue.EnumMarkState30.State1.getDescription();
                strState[1] = String.valueOf(CommonValue.EnumRemind.State4.getIndex());
            }
        }
        return strState;
    }

	/**
	 * 检查强分人数和有效量表是否一致
	 *
	 * @param sheetList
	 *            方案下有效量表集合
	 * @param scheme
	 *            检查的方案
	 */
	private void checkDistNum(List<Sheet> sheetList, Scheme scheme) {
		if (scheme.getDistid() != null) {
			// 加载方案级强制分布信息，检查有效量表和方案强分人数是否一致
			Distribution distObj = daoex.load(Distribution.class, scheme.getDistid());
			if (sheetList.size() != distObj.getDistsum())
				throw new AdderBusinessException("方案设置中，强制分布的人数可能发生了变化，请您前往确认。", "pm.i18n_pbc.ps.037");
		}
		if (scheme.getOGroups() != null) {
			// 检查方案下对象组有效量表和强分人数是否一致
			List<String> groupDistList = new ArrayList<String>();
			for (EvaGroup item : scheme.getOGroups()) {
				if (item.getDistid() != null)
					groupDistList.add(item.getDistid());
			}
			if (groupDistList.size() > 0) {
				// 目前要求要么所有组都有强分，要么都没有
				List<Distribution> distObjList = daoex.findByIds(Distribution.class,
						groupDistList.toArray(new String[groupDistList.size()]));
				int distsum = 0;
				for (Distribution item : distObjList) {
					distsum += item.getDistsum();
				}
				if (sheetList.size() != distsum)
					throw new AdderBusinessException("方案设置中，强制分布的人数可能发生了变化，请您前往确认。", "pm.i18n_pbc.ps.037");
			}
			groupDistList = null;
		}
		// 根据方案查找多方案组
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", scheme.getId());
		List<ApproverGroup> groups = daoex.find(ApproverGroup.class, condObj, null);
		if (!CollectionUtils.isEmpty(groups)) {
			if (groups.get(0).getDistid() != null) {
				// 此结果审核开始的方案设置过多方案，且多方案有强分，检查合计人数是否一致
				String schemegroupid = groups.get(0).getSchemegroupid();
				condObj = new Condition();
				condObj.addExpression("schemegroupid", schemegroupid);
				List<ApproverGroup> groups2 = daoex.find(ApproverGroup.class, condObj, null);
				List<String> schemeids = new ArrayList<String>();
				// 查询多方案中有哪些方案
				for (ApproverGroup item : groups2) {
					schemeids.add(item.getSchemeid());
				}
				Distribution distObj = daoex.load(Distribution.class, groups.get(0).getDistid());
				// 查询方案下有效量表
				condObj = new Condition();
				condObj.addExpression("schemeid", schemeids, Operator.IN);
				condObj.addExpression("iscalc", true);
				condObj.addExpression("isaudit", true);
				condObj.addExpression("markStatus", 4);
				int sheetcount = sheetService.querySheetCountAll(condObj);
				if (sheetcount != distObj.getDistsum())
					throw new AdderBusinessException("考核结果审核规则中，强制分布的人数可能发生了变化，请您前往确认。", "pm.i18n_pbc.ps.038");
			}
		}
	}

	/**
	 * @author ZhangTao
	 * @description 查询方案下未填报的量表数据
	 * @date 2019/3/27
	 * @param schemeid
	 * @return java.util.List<com.yonyou.hrcloud.pm.ps.model.Sheet>
	 **/
	private List<Sheet> queryNoFillSheetListByScheme(String schemeid){
		// 填报环节
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		condObj.addExpression("mark_status", CommonValue.EnumMarkState10.State2.getIndex(), Operator.LESS);
		// 根据环节查询量表，如填报阶段要查询未完成指标填报人员/未完成审核人员
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		return sheetList;
	}

	/**
	 * @author ZhangTao
	 * @description 根据审核人查询对象信息
	 * @date 2019/3/27
	 * @param schemeid
	 * @param workstep
	 * @return java.util.List<com.yonyou.hrcloud.pm.common.model.PmStaff>
	 **/
	private List<PmStaff> queryStaffListByDisposeEngine(String schemeid,EnumWorkStep workstep){
		List<WorkflowEngine> engines = getPendingWorkflow(schemeid, workstep);
		Map<String, PmStaff> staffMap = StaffHelper.getPMStaffList(engines, "getDisposeperson");
		for (WorkflowEngine item : engines) {
			// 循环未终审的考核对象，设置考核对象状态名称
			if (staffMap.containsKey(item.getDisposeperson())) {
				String[] strState = getWorkflowStateName(workstep, item.getState());
				staffMap.get(item.getDisposeperson()).state = strState[0];
				staffMap.get(item.getDisposeperson()).define2 = strState[1];
			}
		}
		List<PmStaff> staffList = StaffHelper.convertStaffMapToList(staffMap);
		return staffList;
	}

	/**
	 * @author ZhangTao
	 * @description 查询所有审核通过的人员列表
	 * @date 2019/3/27
	 * @param schemeid
	 * @param workstep
	 * @return java.util.List<com.yonyou.hrcloud.pm.common.model.PmStaff>
	 **/
	private List<PmStaff> queryPassStaffList(String schemeid,EnumWorkStep workstep){
    	List<PmStaff> staffList = new ArrayList<>();
		//填报进展中已审核的列表展示
		// 填报环节
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		condObj.addExpression("mark_status", CommonValue.EnumMarkState10.State4.getIndex());
		// 根据环节查询量表，如填报阶段要查询未完成指标填报人员/未完成审核人员
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		if(CollectionUtils.isNotEmpty(sheetList)){
			//String[] passSheetIds = sheetList.stream().map(sheet->sheet.getId()).toArray(String[]::new);
			List<String> passsheetids = ListHelper.collect(sheetList, "getId");
			String[] passSheetIds = passsheetids.toArray(new String[passsheetids.size()]);
			List<Sheet> passSheetList = daoex.findByIds(Sheet.class,passSheetIds);
			// 查询考核对象人员信息
			Map<String, PmStaff> passStaffMap = StaffHelper.getPMStaffList(passSheetList, null);
			for (Sheet item : passSheetList) {
				// 循环终审的考核对象，设置填报人员状态名称
				if (passStaffMap.containsKey(item.getStaffid())) {
					passStaffMap.get(item.getStaffid()).state = CommonValue.EnumMarkState10.values()[item.getMarkStatus()]
							.getDescription();
					passStaffMap.get(item.getStaffid()).define2 = item.getMarkStatus();
				}
			}
			staffList = StaffHelper.convertStaffMapToList(passStaffMap);
		}
//		List<WorkflowEngine> passEngines = getPassAuditWorkflow(schemeid,workstep);
//		if(CollectionUtils.isNotEmpty(passEngines)){
//			String[] passSheetIds = passEngines.stream().map(engine->engine.getBizid()).toArray(String[]::new);
//		}
		return staffList;
	}

	/**
	 * @author ZhangTao
	 * @description 设置人员的所属考核组信息保存到人员的define3字段
	 * @date 2019/3/27
	 * @param noFillStaffList
	 *            未填报人员集合
	 * @param passStaffList
	 *            审核通过人员集合
	 * @param schemeid
	 *            对应方案id
	 * @return void
	 **/
	private void setStaffGroupToDefine3(List<PmStaff> noFillStaffList, List<PmStaff> passStaffList, String schemeid) {
		// 定义组合集合
		List<PmStaff> groupStaffList = new ArrayList<>();
		// 将人员组合
		groupStaffList.addAll(noFillStaffList);
		groupStaffList.addAll(passStaffList);
		if (CollectionUtils.isNotEmpty(groupStaffList)) {
			// 获取人员id，方便查询
			String[] groupStaffIds = new String[groupStaffList.size()]; // groupStaffList.stream().map(groupStaff->groupStaff.id).toArray(String[]::new);
			for(int i = 0; i < groupStaffList.size() ; i++){
				groupStaffIds[i] = groupStaffList.get(i).id;
			}
			Condition groupObjCond = new Condition();
			groupObjCond.addExpression("schemeid", schemeid);
			groupObjCond.addExpression("staffid", groupStaffIds, Operator.IN);
			// 查询方案下的人员和考核组的中间关联数据
			List<EvaObject> evaList = daoex.find(EvaObject.class, groupObjCond, null);
			if (CollectionUtils.isNotEmpty(evaList)) {
				// 将数据拼到人员数据上
				List<Object> collect = ListHelper.collect(evaList, "getGroupid");
				List<EvaGroup> groupList = daoex.findByIds(EvaGroup.class, collect.toArray(new String[collect.size()]));
				//List<EvaGroup> groupList = daoex.findByIds(EvaGroup.class,evaList.stream().map(eva->eva.getGroupid()).toArray(String[]::new));
				if(CollectionUtils.isNotEmpty(groupList)){
					//Map<String,String> evaMap = evaList.stream().collect(Collectors.toMap(EvaObject::getStaffid,EvaObject::getGroupid));
					Map<String, String> evaMap = ListHelper.toMap(evaList, "getStaffid", "getGroupid");
					//Map<String,String> groupMap = groupList.stream().collect(Collectors.toMap(EvaGroup::getId,EvaGroup::getGroupname));
					Map<String, String> groupMap = ListHelper.toMap(groupList, "getId", "getGroupname");
					/*noFillStaffList.forEach(noFillStaff->{
						noFillStaff.define3 = groupMap.get(evaMap.get(noFillStaff.id));
					});*/
					for(PmStaff noFillStaff : noFillStaffList){
						noFillStaff.define3 = groupMap.get(evaMap.get(noFillStaff.id));
					}
					/*passStaffList.forEach(passStaff->{
						passStaff.define3 = groupMap.get(evaMap.get(passStaff.id));
					});*/
					for(PmStaff passStaff : passStaffList){
						passStaff.define3 = groupMap.get(evaMap.get(passStaff.id));
					}
				}
			}
		}
	}

	/**
	 * @author ZhangTao
	 * @description 设置该考核人下考核对象的人数及第一个人的名字，封装到define3字段
	 * @date 2019/3/27
	 * @param schemeid
     * @param workstep
     * @param disposepersonList
	 * @return void
	 **/
	private void setStaffCountToDefine3(String schemeid,EnumWorkStep workstep,List<PmStaff> disposepersonList){
		if(CollectionUtils.isNotEmpty(disposepersonList)){
			BaseParam param = new BaseParam();
			param.setBizinfo(Arrays.asList(schemeid));
			param.setWorkstep(workstep);
			param.setBiztype(CommonValue.EnumWorkflowType.performance);
			// 只显示待处理的
			param.setWorkflowStateList(Arrays
					.asList(CommonValue.EnumWorkflowState.PENDING));
			// 查询工作流引擎,按照考核人分组，查询考核人对应的考核对象人数，以及考核人id和对应量表id
			List<HashMap<String,Object>> engineMapList = wfSrv.queryWorkFlowEngineCountByDisposeperson(param);
			if(CollectionUtils.isNotEmpty(engineMapList)){
				//定义量表id数据，用于查询量表信息，工作流中的bizid对应量表id
				String[] sheetids = new String[engineMapList.size()];
				//定义审核人id为键，量表id为值的map，用于后边根据审核人id获取量表信息
				Map<String,String> disposeAndBizidMap = new HashMap<>();
				//定义审核人id为键，审核对象人数为值的map，用于后边根据审核人id获取对应审核对象人数信息
				Map<String,String> disposeAndCountMap = new HashMap<>();
				//循环工作流，将信息封装到对应的map中
				for (int i =0;i<engineMapList.size();i++){
					String bizid = engineMapList.get(i).get("bizid").toString();
					sheetids[i] = bizid;
					String disposeperson = engineMapList.get(i).get("disposeperson").toString();
					String count = engineMapList.get(i).get("count").toString();
					disposeAndBizidMap.put(disposeperson,bizid);
					disposeAndCountMap.put(disposeperson,count);
				}
				//根据量表id查询对应量表数据
				List<Sheet> objSheetList = daoex.findByIds(Sheet.class,sheetids);
				if(CollectionUtils.isNotEmpty(objSheetList)){
					//将量表中的staffid封装，获取人员信息，取到人员姓名
					//Map<String,String> sheetIdAndStaffIdMap = objSheetList.stream().collect(Collectors.toMap(Sheet::getId,Sheet::getStaffid));
					Map<String,String> sheetIdAndStaffIdMap = ListHelper.toMap(objSheetList, "getId", "getStaffid");
					//List<String> objStaffIdList = objSheetList.stream().map(objStaff->objStaff.getStaffid()).collect(Collectors.toList());
					List<String> objStaffIdList = ListHelper.collect(objSheetList, "getStaffid");
					Map<String, PmStaff> objStaffMap = StaffHelper.queryStaffByIds(objStaffIdList);
					//disposepersonList.forEach(disposeStaff->{
					for(PmStaff disposeStaff : disposepersonList){
						//从审核人对应的map中找到对应的bizid即sheetid，通过sheetid找到对应人员id，通过人员id找到对应人员信息，获取人员姓名
						String staffName = objStaffMap.get(sheetIdAndStaffIdMap.get(disposeAndBizidMap.get(disposeStaff.id))).name;
						//通过审核人id获取对应审核对象个数
						String count = disposeAndCountMap.get(disposeStaff.id);
						//拼接成字符串，赋值到define3字段上，完成数据封装
						if(Integer.parseInt(count) > 1){
							disposeStaff.define3 = staffName+" 等"+count+"人";
						}else{
							disposeStaff.define3 = staffName;
						}
					} // );
				}
			}
		}
	}
	
	/**
	 * 设置人员的最近提醒时间
	 * 
	 * @param staffList
	 * @param reminds
	 */
	private void setStaffRemindTime(List<PmStaff> staffList, Map<String, Date> reminds) {
		for (PmStaff item : staffList) {
			if (reminds.containsKey(item.id))
				item.define4 = Arrays.asList(reminds.get(item.id));
		}
	}

	
	/**
	 * 获取进展信息
	 * 
	 * @param schemeid
	 * @param workstep
	 * @param engines
	 *            评价环节，查询评价人状态
	 * @param staffSingle
	 *            只有一个评价对象的
	 * @param staffMulti
	 *            有多个评价对象的，可不传，则归集到staffSingle
	 */
	private void getProgressInfo(String schemeid, EnumWorkStep workstep, List<WorkflowEngine> engines,
			List<PmStaff> staffSingle, List<PmStaff> staffMulti) {
		Map<String, PmStaff> staffMap = StaffHelper.getPMStaffList(engines, "getDisposeperson");
		Map<String, List<WorkflowEngine>> apprMap = new Hashtable<String, List<WorkflowEngine>>();
		for (WorkflowEngine item : engines) {
			String[] strState = getWorkflowStateName(workstep, item.getState());
			staffMap.get(item.getDisposeperson()).state = strState[0];
			staffMap.get(item.getDisposeperson()).define2 = strState[1];
			// 将多人的筛选出来
			if (!apprMap.containsKey(item.getDisposeperson()))
				apprMap.put(item.getDisposeperson(), new ArrayList<WorkflowEngine>());
			apprMap.get(item.getDisposeperson()).add(item);
		}
		for (Map.Entry<String, List<WorkflowEngine>> item : apprMap.entrySet()) {
			PmStaff staff = staffMap.get(item.getKey());
			if (staff == null) {
				// 人员取不到
				staff = new PmStaff();
				staff.id = item.getKey();
				staff.define1 = "失效";
			}
			if (staffMulti == null) {
				staffSingle.add(staff);
			} else {
				if (item.getValue().size() > 1) {
					staffMulti.add(staff);
				} else {
					staffSingle.add(staff);
				}
			}
		}
	}

	@Override
	public void submitSchemeMonitor(Scheme scheme, List<EvaObject> objs) {
		// scheme是完整的，校验方案
		gaugeService.checkScheme(scheme);
		// 查出考核对象的人员信息
		// List<String> evaobject_staffids = objs.stream().map(EvaObject::getStaffid).collect(Collectors.toList());
		List<String> evaobject_staffids = ListHelper.collect(objs, "getStaffid");
 		Map<String, PmStaff> staffMap = StaffHelper.queryStaffByIds(evaobject_staffids);
 		for(EvaObject evaobject : objs){
 			evaobject.setStaff(staffMap.get(evaobject.getStaffid()));
 		}
		// 启动考核监控
		objs = daoGroup.submitSchemeMonitor(scheme,objs);
		// 如果方案允许填报， 方案启动完毕后就可以到此结束了。 就不用执行面的创建工作流了。
		if (scheme.isIsallowfillup()) {
			return;
		}
		// 创建考核人工作流
		// List<String> collect = objs.stream().map(EvaObject::getStaffid).collect(Collectors.toList());
		List<String> collect = ListHelper.collect(objs, "getStaffid");
		if(collect.size() <= 0)
			return;
		Condition appr_cond = new Condition();
		appr_cond.addExpression("schemeid", scheme.getId());
		appr_cond.addExpression("staffid", collect, Operator.IN);
		appr_cond.addExpression("enablestate", true);
		List<Sheet> sheetlist = daoex.find(Sheet.class, appr_cond, null);
		for (Sheet sheet : sheetlist) {
			sheetSettingService.delWorkflowEngnie(sheet.getId());
			// modify by zengcl 导入结果数据 不需要考核人工作流
			
			if(!scheme.isIsimportresult()) {
				sheetSettingService.createAppraiserWorkflow(scheme, sheet);
			}
//			sheetSettingService.createAppraiserWorkflow(scheme, sheet);
			sheet.setMarkStatus(EnumMarkState10.State4.getIndex());
			sheet.setIsaudit(true);
			daoex.update(sheet);
		}
		// 当方案不允许填报时， 如果方案状态已经开始评分,需要开始评分。
		if(scheme.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()){
			// List<String> collect2 = sheetlist.stream().map(Sheet::getId).collect(Collectors.toList());
			List<String> collect2 = ListHelper.collect(sheetlist, "getId");
			Condition condObj = new Condition();
			condObj.addExpression("sheetid", collect2 , Operator.IN);
		    List<SheetAppraiser> apprSheetList = daoex.find(SheetAppraiser.class,
		            condObj, new Sorter(Direction.ASC, Arrays.asList("turn","indicatorid")));
		    createAppraiseData(scheme, apprSheetList);
	        // 推动工作流从填报完成到评分开始
	        WorkflowParam param = new WorkflowParam();
	        param.setWorkstep(EnumWorkStep.step2);
	        param.setBiztype(CommonValue.EnumWorkflowType.performance);
	        param.setBizinfo(Arrays.asList(scheme.getId()));
	        wfbService.setPushState(param);
		}
	}

	/**
	 * 启动方案审核检查
	 * 
	 * @param scheme
	 */
	private void initAuditCheck(Scheme scheme) {
		Systemutil.checkSafety(scheme.getTenantid());
		if (scheme == null || scheme.getSchemestate() != CommonValue.EnumSchemeState.State6.getIndex())
			throw new AdderBusinessException("方案状态不正确", "pm.i18n_pbc.ps.003");
		if (CommonValue.EnumSchemeMode.pm_mtr.getIndex() == scheme.getSchememode()) {
			throw new AdderBusinessException("中期回顾方案不支持结果审核", "pm.i18n_pbc.ps.030");
		}
	}

	/**
	 * 查询结果审核流程设置
	 * 
	 * @param schemeid
	 * @return
	 */
	private List<EvaAppraiser> getEvaAppraiserSet(String schemeid) {
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		condObj.addExpression("workstep", CommonValue.EnumWorkStep.step3.getIndex());
		Sorter sortObj = new Sorter(Direction.ASC, Arrays.asList("groupid", "turn"));
		// 按考核对象组id和轮次顺序查询结果审核流程设置
		List<EvaAppraiser> evaAppraiserList = daoex.find(EvaAppraiser.class, condObj, sortObj);
		return evaAppraiserList;
	}

	/**
	 * 查询方案下有效量表
	 * 
	 * @param schemeid
	 * @return
	 */
	private List<Sheet> getValidSheets(String schemeid) {
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		condObj.addExpression("iscalc", true);
		condObj.addExpression("isaudit", true);
		condObj.addExpression("markStatus", CommonValue.EnumMarkState10.State4.getIndex());// 4
		List<Sheet> sheetList = daoex.find(Sheet.class, condObj, null);
		return sheetList;
	}

	/**
	 * 查询方案下人员和考核对象组的关系
	 * 
	 * @param schemeid
	 * @return
	 */
	private Map<String, String> getEvaObjectMap(String schemeid) {
		Condition condObj = new Condition();
		condObj.addExpression("schemeid", schemeid);
		List<EvaObject> evaObjectList = daoex.find(EvaObject.class, condObj, null);
		// <staffid,groupid>考核对象属于哪个组
        /*Map<String, String> evaObjectMap = evaObjectList.stream().collect(
                Collectors.toMap(EvaObject::getStaffid, EvaObject::getGroupid));*/
        Map<String, String> evaObjectMap = ListHelper.toMap(evaObjectList, "getStaffid", "getGroupid");
		return evaObjectMap;
	}
	
	/**
	 * 获取结果审核总分实体
	 * 
	 * @param schemeid
	 *            方案id
	 * @param sheetList
	 *            有效量表
	 * @param evaAppraiserList
	 *            结果审核流程设置
	 * @param evaSumList
	 *            方案级
	 * @param evaObjectMap
	 *            考核对象属于哪个组
	 * @return
	 */
	private List<ApproveScore> getApproveScore(String schemeid, List<Sheet> sheetList,
			List<EvaAppraiser> evaAppraiserList, List<EvaAppraiser> evaSumList, Map<String, String> evaObjectMap) {
		// <量表id, 集合<结果审核主表>>
		Map<String, List<ApproveScore>> appScoreMap = new HashMap<String, List<ApproveScore>>(sheetList.size());
		// 遍历有效量表和结果审核设置，生成结果审核总分实体集合。1、组；2、方案级；3、多方案级
		for (Sheet sheet : sheetList) {
			for (EvaAppraiser item : evaAppraiserList) {
				if (item.getGroupid() == null) {
					// 非考核组的量表初始化一个空集合，每一个量表都会有List
					if (!appScoreMap.containsKey(sheet.getId()))
						appScoreMap.put(sheet.getId(), new ArrayList<ApproveScore>());
					continue;
				}
				if (evaObjectMap.get(sheet.getStaffid()).equals(item.getGroupid())) {
					// 先生成组的结果审核数据，量表是属于当前组的
					ApproveScore appScore = new ApproveScore();
					appScore.setSheetid(sheet.getId());
					appScore.setSchemeid(schemeid);
					appScore.setTurn(item.getTurn());
					appScore.setAuditor(item.getStaffid());
					appScore.setMarkStatus(CommonValue.EnumMarkState30.State1.getIndex());
					appScore.setGroupid(item.getGroupid());
					appScore.setAudittype(CommonValue.EnumAuditType.type1.getIndex());
					if (!appScoreMap.containsKey(sheet.getId()))
						appScoreMap.put(sheet.getId(), new ArrayList<ApproveScore>());
					appScoreMap.get(sheet.getId()).add(appScore);
				}
			}
		}
		// 增加汇总审核人，方案级和多方案都在所有组审核完后走流程
		int sheetTurnCount = 0;// 组审核的最大轮次
		int sheetMinTurnCount = 1;// 组审核的最小轮次
		for (Map.Entry<String, List<ApproveScore>> item : appScoreMap.entrySet()) {
			if (sheetTurnCount < item.getValue().size())
				sheetTurnCount = item.getValue().size();
			if (item.getValue().size() == 0)
				sheetMinTurnCount = 0;
		}
		// 校验如果设置过组审核，都得有审核人
		if (sheetTurnCount > 0 && sheetMinTurnCount == 0) {
			appScoreMap = null;
			throw new AdderBusinessException("存在考核组流程未设置审核人", "pm.i18n_pbc.ps.027");
		}
        /*List<EvaAppraiser> evaSchemeList = evaSumList.stream()
                .filter(obj -> obj.getSchemegroupid() == null)
                .collect(Collectors.toList());*/
        List<EvaAppraiser> evaSchemeList = ListHelper.filter(evaSumList, "getSchemegroupid", ListHelper.Operator.ISEmpty, null);
        /*List<EvaAppraiser> evaMultiList = evaSumList.stream()
                .filter(obj -> obj.getSchemegroupid() != null)
                .collect(Collectors.toList());*/
        
        List<EvaAppraiser> evaMultiList = ListHelper.filter(evaSumList, "getSchemegroupid", ListHelper.Operator.ISNOTEmpty, null);
		for (Map.Entry<String, List<ApproveScore>> item : appScoreMap.entrySet()) {
			for (EvaAppraiser item2 : evaSchemeList) {
				ApproveScore appScore = new ApproveScore();
				appScore.setSheetid(item.getKey());
				appScore.setSchemeid(schemeid);
				// 允许有的组1轮，有的组3轮，轮次可不连续
				appScore.setTurn(sheetTurnCount + item2.getTurn());
				appScore.setAuditor(item2.getStaffid());
				appScore.setMarkStatus(CommonValue.EnumMarkState30.State1.getIndex());
				appScore.setAudittype(CommonValue.EnumAuditType.type2.getIndex());
				item.getValue().add(appScore);
			}
			for (EvaAppraiser item2 : evaMultiList) {
				ApproveScore appScore = new ApproveScore();
				appScore.setSheetid(item.getKey());
				appScore.setSchemeid(schemeid);
				appScore.setTurn(sheetTurnCount + evaSchemeList.size() + item2.getTurn());
				appScore.setAuditor(item2.getStaffid());
				appScore.setMarkStatus(CommonValue.EnumMarkState30.State1.getIndex());
				appScore.setAudittype(CommonValue.EnumAuditType.type3.getIndex());
				appScore.setGroupid(item2.getSchemegroupid());
				item.getValue().add(appScore);
			}
		}
		List<ApproveScore> appScoreList = new ArrayList<ApproveScore>();
		for (Map.Entry<String, List<ApproveScore>> item : appScoreMap.entrySet()) {
			appScoreList.addAll(item.getValue());
		}
		return appScoreList;
	}

	/**
	 * 为评分明细增加用户自定义栏目结构
	 * 
	 * @param apprDataList
	 * @param apprData
	 */
	private void addCustomColumnData(List<AppraiseData> apprDataList, AppraiseData apprData) {
		List<Column> cols = op2Srv.queryCustomColumn(EnumColumnType.ColumnType3);
		try {
			for (Column item : cols) {
				AppraiseData apprDataCus = (AppraiseData) apprData.clone();
				apprDataCus.setColumncode(item.getColumncode());
				apprDataList.add(apprDataCus);
			}
		} catch (CloneNotSupportedException e) {
			logger.error(e.getMessage());
		}
	}
	
	/**
	 * 检查中期评价是否结束
	 * 
	 * @param scheme
	 */
	private void checkMtr(Scheme scheme) {
		if (!scheme.isIsallowmtr())
			return;
		List<SchemeRelation> r = sumSrv.querySchemeRelationList(scheme.getId());
		if (!r.isEmpty()) {
			List<String> schemeids = r.stream().map(obj -> obj.getFormulaschemeid()).collect(Collectors.toList());
			Condition cond = new Condition();
			cond.addExpression("id", schemeids, Operator.IN);
			cond.addExpression("schemestate", CommonValue.EnumSchemeState.State6.getIndex(), Operator.LESS);
			// 查询回顾子方案小于评分结束状态的
			List<Scheme> schemeList = daoex.find(Scheme.class, cond, null);
			if (!schemeList.isEmpty()) {
				for (Scheme item : schemeList) {
					if (item.isIsallowcalc()) {
						// 要评分，方案状态小于填报已结束
						throw new AdderBusinessException("方案不能开始评分，请先结束所有回顾方案", "pm.i18n_pbc.pa.025");
					} else if (!item.isIsallowcalc()
							&& item.getSchemestate() < CommonValue.EnumSchemeState.State4.getIndex()) {
						// 不用评分，方案状态小于填报已结束
						throw new AdderBusinessException("方案不能开始评分，请先结束所有回顾方案", "pm.i18n_pbc.pa.025");
					}
				}
			}
		}
	}

	/**
	 * 检查方案是否出现在汇总方案中
	 *
	 * @param schemeid
	 */
	private void checkSummaryScheme(String schemeid) {
		Condition condObj = new Condition();
		condObj.addExpression("formulaschemeid", schemeid);
		Pageable page = new PagerRequest(0, 1);
		List<SchemeRelation> schemeRelationList = daoex.findPage(SchemeRelation.class, condObj, page).getContent();
		if (!schemeRelationList.isEmpty()) {
			Scheme sumScheme = daoex.load(Scheme.class, schemeRelationList.get(0).getSchemeid());
			throw new AdderBusinessException("方案存在于汇总方案“{0}”的汇总明细中", "pm.i18n_pbc.ps.013", sumScheme.getSchemename());
		}
	}
}
