NC65 查询单据所处的流程状态以及流程平台客户端工具类

1、查询单据所处的流程状态

nc.bs.wfengine.engine.EngineService的queryFlowStatus()方法

/*** 查询单据所处的流程状态* * @param billId* @param billType* @param result* @return* @throws DbException*/public int queryFlowStatus(String billId, String billType, int flowType, String taskResult) throws DbException {IFlowStatusService flowStatusService = AbstractFlowStatusService.getFlowStatusService(flowType);return flowStatusService.queryFlowStatus(billId, billType, taskResult);}

在这里插入图片描述

nc.bs.pub.wfengine.status.AbstractFlowStatusService

package nc.bs.pub.wfengine.status;import java.util.ArrayList;
import java.util.Iterator;import nc.jdbc.framework.JdbcSession;
import nc.jdbc.framework.PersistenceManager;
import nc.jdbc.framework.SQLParameter;
import nc.jdbc.framework.exception.DbException;
import nc.jdbc.framework.processor.ArrayListProcessor;
import nc.jdbc.framework.processor.ArrayProcessor;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.vo.pub.pf.IPfRetCheckInfo;
import nc.vo.wfengine.definition.WorkflowTypeEnum;
import nc.vo.wfengine.pub.WfTaskOrInstanceStatus;
import nc.vo.wfengine.pub.WfTaskType;public abstract class AbstractFlowStatusService implements IFlowStatusService {public static IFlowStatusService getFlowStatusService(int type) {WorkflowTypeEnum flowtype = WorkflowTypeEnum.fromIntValue(type);switch (flowtype) {case Approveflow:case SubApproveflow:return new ApproveflowStatusService();case Workflow:case SubWorkflow:return new WorkflowStatusService();case SubWorkApproveflow:return new SubWorkApproveflowStatusService();}return null;}public int queryFlowStatus(String billId, String billType, String taskResult)throws DbException{return 0;}protected int queryCurrentFlowStatus(String billId, String billType,int flowType) throws DbException {// 1.查询主流程实例的状态String sql = "select procstatus,procresult from pub_wf_instance"+ " where billversionpk=? and billtype=? and procstatus!="+ WfTaskOrInstanceStatus.Inefficient.getIntValue()+ " and ( isnull(cast(workflow_type as char),'~')='~' or workflow_type=?)";// 2.查询有无处于启动状态的修单任务String sql1 = "select b.pk_wf_task from pub_wf_task b,pub_wf_instance a"+ " where a.billversionpk=? and a.billtype=? and a.procstatus!="+ WfTaskOrInstanceStatus.Inefficient.getIntValue()+ " and (isnull(cast(a.workflow_type as char),'~')='~' or a.workflow_type=?)"+ " and b.pk_wf_instance=a.pk_wf_instance and b.tasktype="+ WfTaskType.Makebill.getIntValue() + " and b.taskstatus="+ WfTaskOrInstanceStatus.Started.getIntValue();// 3.查询有无已处于启动/完成状态的审批工作项String sql2 = "select a.approvestatus,b.pk_wf_task from pub_workflownote a,pub_wf_task b"+ " where a.pk_wf_task=b.pk_wf_task and b.tasktype=" + WfTaskType.Forward.getIntValue()+ " and a.approvestatus in(" + WfTaskOrInstanceStatus.Started.getIntValue() + ","+ WfTaskOrInstanceStatus.Finished.getIntValue() + ") and a.billversionpk=? and a.pk_billtype=?"+ " and (isnull(cast(a.workflow_type as char),'~')='~' or a.workflow_type=? or a.workflow_type = 3 or a.workflow_type = 5 or a.workflow_type = 6)"; PersistenceManager persist = null;try {persist = PersistenceManager.getInstance();JdbcSession jdbc = persist.getJdbcSession();SQLParameter para = new SQLParameter();para.addParam(billId);para.addParam(billType);para.addParam(flowType);Object[] objs = (Object[]) jdbc.executeQuery(sql, para, new ArrayProcessor());if (objs != null) {// 单据已经拥有流程实例int status = ((Integer) objs[0]).intValue();String result = String.valueOf(objs[1]);if (status != WfTaskOrInstanceStatus.Finished.getIntValue()) {// 流程未结束Object objTaskPK = jdbc.executeQuery(sql1, para, new ColumnProcessor(1));if (objTaskPK != null) {String pk_wf_task = String.valueOf(objTaskPK);if (pk_wf_task != null && pk_wf_task.trim().length() > 0) {// 如果有修改单据的任务,为自由态return IPfRetCheckInfo.NOSTATE;}}ArrayList alResult = (ArrayList) jdbc.executeQuery(sql2, para, new ArrayListProcessor());boolean hasFinishedItem = false;boolean hasStartedItem = false;for (Iterator iterator = alResult.iterator(); iterator.hasNext();) {Object[] results = (Object[]) iterator.next();String taskPK2 = (String) results[1];int approveStatus = (Integer) results[0];if (taskPK2 != null) {if (approveStatus == WfTaskOrInstanceStatus.Finished.getIntValue())hasFinishedItem = true;if (approveStatus == WfTaskOrInstanceStatus.Started.getIntValue())hasStartedItem = true;}}if (hasFinishedItem) {// 如果存在已完成的审批任务,则进行中return IPfRetCheckInfo.GOINGON;} else if (hasStartedItem) {// 如果存在启动的审批任务,则提交态return IPfRetCheckInfo.COMMIT;} else// 如果无启动/完成的审批任务,则自由态return IPfRetCheckInfo.NOSTATE;}// 流程已经结束if (result != null && result.equalsIgnoreCase("Y"))return IPfRetCheckInfo.PASSING;if (result != null && result.equalsIgnoreCase("N"))return IPfRetCheckInfo.NOPASS;}// 尚无流程实例,则为自由态return IPfRetCheckInfo.NOSTATE;} finally {if (persist != null)persist.release();}}
}

2、流程平台客户端工具类

package nc.ui.pub.pf;import java.awt.Container;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;import javax.swing.JDialog;
import javax.swing.SwingUtilities;import nc.bs.dao.DAOException;
import nc.bs.framework.common.NCLocator;
import nc.bs.logging.Logger;
import nc.bs.pf.pub.BillTypeCacheKey;
import nc.bs.pf.pub.PfDataCache;
import nc.bs.pub.pf.PfUtilTools;
import nc.desktop.ui.WorkbenchEnvironment;
import nc.funcnode.ui.AbstractFunclet;
import nc.funcnode.ui.IFuncletWindow;
import nc.itf.uap.IUAPQueryBS;
import nc.itf.uap.pf.IPFConfig;
import nc.itf.uap.pf.IPFWorkflowQry;
import nc.itf.uap.pf.IPfExchangeService;
import nc.itf.uap.pf.IWorkflowDefine;
import nc.itf.uap.pf.IWorkflowMachine;
import nc.itf.uap.pf.IplatFormEntry;
import nc.itf.uap.pf.busiflow.PfButtonClickContext;
import nc.itf.uap.pf.metadata.IFlowBizItf;
import nc.message.Attachment;
import nc.message.vo.AttachmentVO;
import nc.uap.pf.metadata.PfMetadataTools;
import nc.ui.ml.NCLangRes;
import nc.ui.pf.change.PfUtilUITools;
import nc.ui.pf.clientutils.PfUtilClientAssistor;
import nc.ui.pf.pub.PFClientBizRetObj;
import nc.ui.pf.pub.PfUIDataCache;
import nc.ui.pf.workitem.ApproveFlowDispatchDialog;
import nc.ui.pf.workitem.ApproveWorkitemAcceptDlg;
import nc.ui.pf.workitem.BatchApproveModel;
import nc.ui.pf.workitem.BatchApproveWorkitemAcceptDlg;
import nc.ui.pf.workitem.WFStartDispatchDialog;
import nc.ui.pf.workitem.WorkflowWorkitemAcceptDlg;
import nc.ui.pf.workitem.beside.BesideApproveContext;
import nc.ui.pub.beans.MessageDialog;
import nc.ui.pub.beans.UIDialog;
import nc.ui.pub.bizflow.IBillReferQueryWithBusitype;
import nc.ui.pub.bizflow.IBillReferQueryWithScheme;
import nc.ui.pub.bizflow.IBillReferQueryWithTranstype;
import nc.ui.pub.workflowqry.WorkflowManageUtil;
import nc.ui.querytemplate.IBillReferQuery;
import nc.ui.querytemplate.QueryConditionDLG;
import nc.ui.querytemplate.querytree.IQueryScheme;
import nc.ui.wfengine.ext.ApplicationRuntimeAdjustContext;
import nc.ui.wfengine.ext.ApplicationRuntimeAdjustFactory;
import nc.ui.wfengine.ext.IApplicationRuntimeAdjust;
import nc.vo.jcom.lang.StringUtil;
import nc.vo.pf.change.ExchangeVO;
import nc.vo.pf.change.PfUtilBaseTools;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.billtype2.Billtype2VO;
import nc.vo.pub.billtype2.ExtendedClassEnum;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.pf.AssignableInfo;
import nc.vo.pub.pf.PfAddInfo;
import nc.vo.pub.pf.PfClientBizProcessContext;
import nc.vo.pub.pf.workflow.IPFActionName;
import nc.vo.pub.pfflow.BillactionVO;
import nc.vo.pub.pfflow01.BillbusinessVO;
import nc.vo.pub.template.ITemplateStyle;
import nc.vo.pub.workflownote.WorkflownoteVO;
import nc.vo.querytemplate.TemplateInfo;
import nc.vo.sm.UserVO;
import nc.vo.uap.pf.FlowDefNotFoundException;
import nc.vo.uap.pf.PFBusinessException;
import nc.vo.uap.pf.PFRuntimeException;
import nc.vo.uap.pf.PfProcessBatchRetObject;
import nc.vo.wfengine.core.parser.XPDLNames;
import nc.vo.wfengine.definition.IApproveflowConst;
import nc.vo.wfengine.definition.WorkflowDefinitionVO;
import nc.vo.wfengine.definition.WorkflowTypeEnum;
import nc.vo.wfengine.pub.WFTask;
import nc.vo.wfengine.pub.WfTaskType;/*** 流程平台客户端工具类* * @author fangj 2001-10* @modifier leijun 2005-5 取消单据类型UI类名必须以<Y>开头才可指派的限制* @modifier leijun 2006-7 送审时的指派对话框,如果用户点击取消,则不送审* @modifier leijun 2007-5 使用新的查询模板* @modifier leijun 2008-3 重构动作处理的API,进一步精简* @modifier dingxm 2009-7 参照制单对于按钮逻辑的处理挪到BusinessDelegator,参照制单中本类只提供信息,不处理按钮* @modifier zhouzhenga 20120107 部分逻辑挪到PfUtilClientAssistor*/
public class PfUtilClient {/*** 审批变量如果审批则true反之false;*/private static boolean m_checkFlag = true;// 当前单据类型private static String m_currentBillType = null;/** 当前审批节点的审批结果 */private static int m_iCheckResult = IApproveflowConst.CHECK_RESULT_PASS;private static boolean m_isOk = false;/** fgj2001-11-27 判断当前动作是否执行成功 */private static boolean m_isSuccess = true;/** 源单据类型 */private static String m_sourceBillType = null;private static AggregatedValueObject m_tmpRetVo = null;private static AggregatedValueObject[] m_tmpRetVos = null;// 单据自制标志public static boolean makeFlag = false;private static IPfExchangeService exchangeService;private static int m_classifyMode = PfButtonClickContext.NoClassify;private static boolean isOpenedInDialog = false;private static boolean isAutoCloseParentDialog = false;/*** 审批流定义查询服务*/private static IWorkflowDefine workflowDefService;private PfUtilClient() {// Noop!}/*** 提交单据时,需要的指派信息* <li>只有"SAVE","EDIT"动作才调用*/private static WorkflownoteVO checkOnSave(Container parent, String actionName, String billType, AggregatedValueObject billVo, Stack dlgResult, HashMap hmPfExParams) throws BusinessException {WorkflownoteVO worknoteVO = new WorkflownoteVO();// guowl+ 2010-5,如果是批处理,不用取指派信息,直接返回if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null)return worknoteVO;try {worknoteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionName, billType, billVo, hmPfExParams);} catch (FlowDefNotFoundException e) {return worknoteVO;}// 在审批处理框显示之前,调用业务处理PFClientBizRetObj retObj = executeBusinessPlugin(parent, billVo, worknoteVO, true);if (retObj != null && retObj.isStopFlow()) {m_isSuccess = false;return null;}if (worknoteVO != null) {// 得到可指派的输入数据Vector assignInfos = worknoteVO.getTaskInfo().getAssignableInfos();if (assignInfos != null && assignInfos.size() > 0) {// 显示指派对话框并收集实际指派信息ApproveFlowDispatchDialog dlg = new ApproveFlowDispatchDialog(parent);dlg.getDisPatchPanel().initByWorknoteVO(worknoteVO);int iClose = dlg.showModal();if (iClose == UIDialog.ID_CANCEL)dlgResult.push(Integer.valueOf(iClose));}}return worknoteVO;}/*** 单据启动工作流时,需要的指派信息* <li>包括选择后继活动参与者、选择后继分支转移*/private static WorkflownoteVO checkOnStart(Container parent, String actionName, String billType, AggregatedValueObject billVo, Stack dlgResult, HashMap hmPfExParams) throws BusinessException {WorkflownoteVO wfVo = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionName, billType, billVo, hmPfExParams);// guowl+ 2010-5,如果是批处理,不用取指派信息,直接返回if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null)return wfVo;if (wfVo != null) {// 得到可指派的信息Vector assignInfos = wfVo.getTaskInfo().getAssignableInfos();Vector tSelectInfos = wfVo.getTaskInfo().getTransitionSelectableInfos();if (assignInfos.size() > 0 || tSelectInfos.size() > 0) {// 显示指派对话框并收集实际指派信息WFStartDispatchDialog wfdd = new WFStartDispatchDialog(parent, wfVo);int iClose = wfdd.showModal();if (iClose == UIDialog.ID_CANCEL)dlgResult.push(Integer.valueOf(iClose));}}return wfVo;}/*** 检查当前单据是否处于工作流程中或工作流的审批子流程中,并进行交互*/private static WorkflownoteVO checkWorkitemWhenSignal(Container parent, String actionCode, String billType, AggregatedValueObject billVo, HashMap hmPfExParams, int voAryLen) throws BusinessException {WorkflownoteVO noteVO = null;UIDialog dlg = null;if (voAryLen != 0) {if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) != null) {noteVO = (WorkflownoteVO) hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE);m_checkFlag = true;return noteVO;}}try {// 检查当前用户的工作流工作项+审批子流程工作项noteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionCode, billType, billVo, hmPfExParams);if (noteVO == null) {m_checkFlag = true;return noteVO;} else {// XXX:guowl+,检查是否弹出交互界面// 批量执行是按照每十条执行一次,当执行之后还剩下一条时,走单个执行方法,所以对工作项单独处理if (voAryLen == 0 && (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) != null)) {WorkflownoteVO oldNoteVO = (WorkflownoteVO) hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE);noteVO.getTaskInfo().setTransitionSelectableInfos(oldNoteVO.getTaskInfo().getTransitionSelectableInfos());if (oldNoteVO.getTaskInfo().getTransitionSelectableInfos() != null && oldNoteVO.getTaskInfo().getTransitionSelectableInfos().size() > 0) {noteVO.getTaskInfo().setTransitionSelectableInfos(oldNoteVO.getTaskInfo().getTransitionSelectableInfos());}noteVO.setIscheck(oldNoteVO.getIscheck());noteVO.setApproveresult(oldNoteVO.getApproveresult());noteVO.setChecknote(oldNoteVO.getChecknote());if ("R".equals(oldNoteVO.getApproveresult()) && !noteVO.isAnyoneCanApprove()) {noteVO.getTaskInfo().getTask().setBackToFirstActivity(true);noteVO.getTaskInfo().getTask().setTaskType(WfTaskType.Backward.getIntValue());}Object value = noteVO.getRelaProperties().get(XPDLNames.ELECSIGNATURE);if (value != null && "true".equalsIgnoreCase(value.toString())) {noteVO.setCiphertext(oldNoteVO.getCiphertext());}return noteVO;}if (!PfUtilClientAssistor.isExchange(noteVO.getTaskInfo().getTask())) {m_checkFlag = true;noteVO.setApproveresult("Y");return noteVO;}if (noteVO.getWorkflow_type() == WorkflowTypeEnum.SubWorkApproveflow.getIntValue()) {// 工作流的审批子流程if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {dlg = new BatchApproveWorkitemAcceptDlg(parent, noteVO);BatchApproveModel batchApproveMode = new BatchApproveModel();batchApproveMode.setBillUI(true);batchApproveMode.setSingleBillSelected(true);batchApproveMode.setContainUnApproveBill(false);batchApproveMode.setBillItem(voAryLen);((BatchApproveWorkitemAcceptDlg) dlg).setBachApproveMode(batchApproveMode);} else {dlg = new ApproveWorkitemAcceptDlg(parent, noteVO, true);}} else// 工作流或工作子流程dlg = new WorkflowWorkitemAcceptDlg(parent, noteVO, PfUtilClientAssistor.isCanTransfer(noteVO.getTaskInfo().getTask()));if (dlg.showModal() == UIDialog.ID_OK) {// 返回处理后的工作项m_checkFlag = true;} else {// 用户取消m_checkFlag = false;noteVO = null;}if ((hmPfExParams != null && (!hmPfExParams.containsKey(PfUtilBaseTools.PARAM_WORKNOTE) || hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) == null)) && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {hmPfExParams.put(PfUtilBaseTools.PARAM_WORKNOTE, noteVO);}}} finally {if (dlg != null) {nc.ui.pub.beans.UIComponentUtil.removeAllComponentRefrence(dlg);}}return noteVO;}/*** 检查当前单据是否处于审批流程中,并进行交互*/private static WorkflownoteVO checkWorkitemWhenApprove(Container parent, String actionName, String billType, Object billvos, HashMap hmPfExParams, int voAryLen) throws BusinessException {WorkflownoteVO noteVO = null;UIDialog dlg = null;if (voAryLen != 0) {if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) != null) {noteVO = (WorkflownoteVO) hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE);m_checkFlag = true;return noteVO;}}// billvos传值为单值或者数组 qf@2015-1-22AggregatedValueObject billvo = null;AggregatedValueObject[] vos = null;if (billvos instanceof AggregatedValueObject) {billvo = (AggregatedValueObject) billvos;} else if (billvos instanceof AggregatedValueObject[]) {vos = (AggregatedValueObject[]) billvos;billvo = vos[0];}if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {Object notSilent = hmPfExParams.get(PfUtilBaseTools.PARAM_NOTSILENT);// 检查单据是否定义了审批流,如果没有定义,则不弹出,此处只简单检查第一张单据的单据类型上是否有流程定义if (notSilent == null && !hasApproveflowDef(billType, billvo)) {m_checkFlag = true;noteVO = new WorkflownoteVO();noteVO.setApproveresult("Y");Logger.debug("*checkWorkitemWhenApprove 1 billType.");return noteVO;} else {// 预算开发部要求批审时不管有没有流程定义,都弹出审批意见框noteVO = new WorkflownoteVO();// 判断是否需要CAList<String> billIdList = new ArrayList<String>();if (vos != null && vos.length != 0) {for (AggregatedValueObject vo : vos) {billIdList.add(vo.getParentVO().getPrimaryKey());}noteVO.getRelaProperties().put(XPDLNames.ELECSIGNATURE, NCLocator.getInstance().lookup(IPFWorkflowQry.class).isNeedCASign4Batch(PfUtilUITools.getLoginUser(), new String[] { billType }, billIdList.toArray(new String[0])));}BatchApproveModel batchApproveMode = new BatchApproveModel();batchApproveMode.setBillUI(true);batchApproveMode.setSingleBillSelected(true);batchApproveMode.setContainUnApproveBill(false);batchApproveMode.setBillItem(voAryLen);dlg = new BatchApproveWorkitemAcceptDlg(parent, noteVO);((BatchApproveWorkitemAcceptDlg) dlg).setBachApproveMode(batchApproveMode);Logger.debug("*checkWorkitemWhenApprove 2.");}} else {noteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionName, billType, billvo, hmPfExParams);Logger.debug("*checkWorkitemWhenApprove 3.");if (noteVO != null && isBesideApprove(hmPfExParams)) {noteVO = BesideApprove(hmPfExParams, noteVO);} else {Object notSilent = null;if (hmPfExParams != null) {notSilent = hmPfExParams.get(PfUtilBaseTools.PARAM_NOTSILENT);}if (noteVO == null) {if (notSilent == null) {m_checkFlag = true;Logger.debug("*checkWorkitemWhenApprove 1 billType.");return noteVO;} else {noteVO = new WorkflownoteVO();}}PFClientBizRetObj retObj = executeBusinessPlugin(parent, billvo, noteVO, false);int workflowtype = noteVO.getWorkflow_type();boolean isInWorkflow = false;if (workflowtype == WorkflowTypeEnum.SubWorkApproveflow.getIntValue())isInWorkflow = true;dlg = new ApproveWorkitemAcceptDlg(parent, noteVO, billvo, isInWorkflow, isOpenedInDialog, retObj == null ? null : retObj.getHintMessage());ApproveWorkitemAcceptDlg acceptDlg = ((ApproveWorkitemAcceptDlg) dlg);if (retObj != null) {// yanke1 2012-02-22 根据前台业务处理的返回值来控制审批界面acceptDlg.setShowPass(retObj.isShowPass());
//					acceptDlg.setShowNoPass(retObj.isShowNoPass());acceptDlg.setShowReject(retObj.isShowReject());}acceptDlg.setShowNoPass(!PfUtilClientAssistor.isHideNoPassing(noteVO.getTaskInfo().getTask()));Logger.debug("*checkWorkitemWhenApprove 4.");}}Logger.debug("*checkWorkitemWhenApprove 5.");if (!isBesideApprove(hmPfExParams)) {if (hmPfExParams == null) {hmPfExParams = new HashMap<String, Object>();}if (dlg.showModal() == UIDialog.ID_OK) { // 如果用户审批if (dlg instanceof ApproveWorkitemAcceptDlg) {isAutoCloseParentDialog = ((ApproveWorkitemAcceptDlg) dlg).isAutoCloseParentDialog();}m_checkFlag = true;} else { // 用户不审批m_checkFlag = false;noteVO = null;}if ((!hmPfExParams.containsKey(PfUtilBaseTools.PARAM_WORKNOTE) || hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) == null) && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {hmPfExParams.put(PfUtilBaseTools.PARAM_WORKNOTE, noteVO);}}return noteVO;}/*** 侧边栏审批* * @throws BusinessException*/private static WorkflownoteVO BesideApprove(HashMap hmPfExParams, WorkflownoteVO noteVO) throws BusinessException {BesideApproveContext besideContext = (BesideApproveContext) hmPfExParams.get(PfUtilBaseTools.PARAM_BESIDEAPPROVE);m_checkFlag = true;if (besideContext.isNeedDispatch()) {// 填充指派信息ApproveFlowDispatchDialog disPatchDlg = new ApproveFlowDispatchDialog(null);disPatchDlg.getDisPatchPanel().initByWorknoteVO(noteVO, besideContext.getApproveResult().equalsIgnoreCase("Y") ? AssignableInfo.CRITERION_PASS : AssignableInfo.CRITERION_NOPASS);int result = disPatchDlg.showModal();if (result == UIDialog.ID_CANCEL) {// 如果指派对话框点击了取消,那么取消这次审批操作,重新回到审批面板 (changlx需求定义)modified by// zhangrui 2012-04-17noteVO = null;m_checkFlag = false;return noteVO;}}// 改派if (besideContext.getManagerContext() != null) {WorkflowManageUtil wfUtil = new WorkflowManageUtil();if (wfUtil.doAlterSend(null, besideContext.getManagerContext(), besideContext.getTransferList(), besideContext.getCheckNote())) {noteVO.getTaskInfo().getTask().setAppoint(true);} else {noteVO = null;m_isSuccess = false;return noteVO;}noteVO.setChecknote(besideContext.getCheckNote());}// 加签if (besideContext.isAddAssign()) {ApplicationRuntimeAdjustContext context = new ApplicationRuntimeAdjustContext();context.setStyle(besideContext.getAddAssignStyle());// style被去掉了context.setUserObject(besideContext.getAddAssignUserObj());// 记录加签发起人UserVO operator = WorkbenchEnvironment.getInstance().getLoginUser();noteVO.setSenderman(operator.getCuserid());noteVO.setChecknote(besideContext.getCheckNote());context.setWorkFlow(noteVO);IApplicationRuntimeAdjust runtimeObj = ApplicationRuntimeAdjustFactory.createAdjust(IApplicationRuntimeAdjust.ADJUST_TYPE_ADDASSIGN);try {runtimeObj.adjust(context);m_checkFlag = true;} catch (BusinessException e) {Logger.error(e.getMessage(), e);String message = e.getMessage();if (e.getCause() != null) {message = e.getCause().getMessage();}MessageDialog.showErrorDlg(null, null, message);m_isSuccess = false;noteVO = null;return noteVO;}}noteVO.setMailExtCpySenders(besideContext.getMailExtCpySenders());noteVO.setMsgExtCpySenders(besideContext.getMsgExtCpySenders());List<AttachmentVO> attchVOS = updateAttachment2DocServer(besideContext.getAttchlist());noteVO.setAttachmentSetting(attchVOS);noteVO.setApproveresult(besideContext.getApproveResult());noteVO.setChecknote(besideContext.getCheckNote());noteVO.setTrack(besideContext.isTracked());if (besideContext.getTaskType() != 0) {noteVO.getTaskInfo().getTask().setTaskType(besideContext.getTaskType());}noteVO.getTaskInfo().getTask().setBackToFirstActivity(besideContext.isBackToFirstActivity());noteVO.getTaskInfo().getTask().setJumpToActivity(besideContext.getJumpToActivity());m_checkFlag = true;m_isSuccess = true;return noteVO;}// 上传服务器,不影响流程private static List<AttachmentVO> updateAttachment2DocServer(List<Attachment> attchlist) throws BusinessException {List<AttachmentVO> vos = new ArrayList<AttachmentVO>();try {for (Attachment attachment : attchlist) {AttachmentVO vo = attachment.uploadToFileServer();vo.setFilesize(attachment.getSize());vo.setFilename(attachment.getName());vos.add(vo);}} catch (Exception e) {Logger.error(e.getMessage() + "上传附件失败!");throw new BusinessException(e.getMessage() + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("pfworkflow63", "Attachmentfile-0000")/** @res"上传附件失败!" */);}return vos;}private static boolean hasApproveflowDef(String billType, AggregatedValueObject billVo) throws BusinessException {IFlowBizItf fbi = PfMetadataTools.getBizItfImpl(billVo, IFlowBizItf.class);if (fbi == null)throw new PFRuntimeException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000000")/* 元数据实体没有提供业务接口IFlowBizItf的实现类 */);IWorkflowDefine wfDefine = NCLocator.getInstance().lookup(IWorkflowDefine.class);Logger.debug("查询流程定义: billType=" + billType + ";pkOrg=" + fbi.getPkorg() + ";userId=" + fbi.getBillMaker() + ";开始");return wfDefine.hasValidProcessDef(WorkbenchEnvironment.getInstance().getGroupVO().getPk_group(), billType, fbi.getPkorg(), fbi.getBillMaker(), fbi.getEmendEnum(), WorkflowTypeEnum.Approveflow.getIntValue());}/*** 参照来源单据,用于* <li>1.获取来源单据的查询对话框,并查询出来源单据* <li>2.显示来源单据,并进行选择* <li>3.获取选择的来源单据* * @param srcBillType         参照制单 选择的来源单据类型* @param pk_group* @param userId* @param currBillOrTranstype 当前单据或交易类型* @param parent* @param userObj* @param srcBillId           如果为空,则直接进入参照上游单据界面*/public static void childButtonClicked(String srcBillType, String pk_group, String userId, String currBillOrTranstype, Container parent, Object userObj, String srcBillId) {childButtonClickedWithBusi(srcBillType, pk_group, userId, currBillOrTranstype, parent, userObj, srcBillId, null);}public static void childButtonClickedNew(final PfButtonClickContext context) {makeFlag = false;if (context.getSrcBillType().toUpperCase().equals("MAKEFLAG")) {Logger.debug("******自制单据******");makeFlag = true;return;}Logger.debug("******参照来源单据******");m_classifyMode = context.getClassifyMode();try {final String funNode = PfUIDataCache.getBillType(new BillTypeCacheKey().buildBilltype(context.getSrcBillType()).buildPkGroup(context.getPk_group())).getNodecode();if (funNode == null || funNode.equals(""))throw new PFBusinessException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000001", null, new String[] { context.getSrcBillType() })/* 请注册单据{0}的功能节点号 */);// 查询交换信息,以便得到一些参照制单的定制信息String src_qrytemplate = null;String src_billui = null; // 来源单据的显示UI类String src_nodekey = null; // 用于查询来源单据的查询模板的节点标识ExchangeVO changeVO = getExchangeService().queryMostSuitableExchangeVO(context.getSrcBillType(), context.getCurrBilltype(), null, PfUtilUITools.getLoginGroup(), null);if (changeVO != null) {src_qrytemplate = changeVO.getSrc_qrytemplate();src_qrytemplate = src_qrytemplate == null ? null : src_qrytemplate.trim();src_billui = changeVO.getSrc_billui();src_nodekey = changeVO.getSrc_nodekey();}// a.获取来源单据的查询对话框,即为m_condition赋值IBillReferQuery qcDLG = null;if (StringUtil.isEmptyWithTrim(src_qrytemplate)) {Logger.debug("使用来源单据类型对应节点使用的查询模板对话框");src_qrytemplate = PfUtilUITools.getTemplateId(ITemplateStyle.queryTemplate, context.getPk_group(), funNode, context.getUserId(), src_nodekey);qcDLG = setConditionClient(src_qrytemplate, context.getParent(), context.getUserId(), funNode, context.getPk_group());} else if (src_qrytemplate.startsWith("<")) {Logger.debug("使用产品组定制的来源单据查询对话框");src_qrytemplate = src_qrytemplate.substring(1, src_qrytemplate.length() - 1);qcDLG = loadUserQuery(context.getParent(), src_qrytemplate, context.getPk_group(), context.getUserId(), funNode, context.getCurrBilltype(), context.getSrcBillType(), src_nodekey, context.getUserObj());} else {Logger.debug("使用注册的查询模板的查询对话框");qcDLG = setConditionClient(src_qrytemplate, context.getParent(), context.getUserId(), funNode, context.getPk_group());}// 给查询对话框设置业务类型,asked by scm-puqhif (context.getBusiTypes() != null && qcDLG instanceof IBillReferQueryWithBusitype)((IBillReferQueryWithBusitype) qcDLG).setBusitypes(context.getBusiTypes());// 给查询对话框设置交易类型,用于过滤上游单据,asked by scm-puqhif (context.getTransTypes() != null && qcDLG instanceof IBillReferQueryWithTranstype)((IBillReferQueryWithTranstype) qcDLG).setTranstypes(context.getTransTypes());if (context.getSrcBillId() == null) {// b.显示来源单据的查询对话框if (qcDLG.showModal() == UIDialog.ID_OK) {// c.显示来源单据,并进行选择refBillSource(context.getPk_group(), funNode, context.getUserId(), context.getCurrBilltype(), context.getParent(), context.getUserObj(), context.getSrcBillType(), src_qrytemplate, src_billui, src_nodekey, null, qcDLG);} else {m_isOk = false;return;}} else {// b'.直接显示来源单据refBillSource(context.getPk_group(), funNode, context.getUserId(), context.getCurrBilltype(), context.getParent(), context.getUserObj(), context.getSrcBillType(), src_qrytemplate, src_billui, src_nodekey, context.getSrcBillId(), qcDLG);return;}} catch (Exception ex) {Logger.error(ex.getMessage(), ex);MessageDialog.showErrorDlg(context.getParent(), "null", NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000002", null, new String[] { ex.getMessage() })/* 参照上游单据出现异常={0} */);}}/*** 参照来源单据,用于* <li>1.获取来源单据的查询对话框,并查询出来源单据* <li>2.显示来源单据,并进行选择* <li>3.获取选择的来源单据* * @param srcBillType         参照制单 选择的来源单据类型* @param pk_group* @param userId* @param currBillOrTranstype 当前单据或交易类型* @param parent* @param userObj* @param srcBillId           如果为空,则直接进入参照上游单据界面* @param busiTypes           如果不为空,表示查找指定业务流程中的单据*/public static void childButtonClickedWithBusi(String srcBillType, String pk_group, String userId, String currBillOrTranstype, Container parent, Object userObj, String srcBillId, List<String> busiTypes) {m_classifyMode = PfButtonClickContext.NoClassify;makeFlag = false;if (srcBillType.toUpperCase().equals("MAKEFLAG")) {Logger.debug("******自制单据******");makeFlag = true;return;}Logger.debug("******参照来源单据******");try {String funNode = PfUIDataCache.getBillType(new BillTypeCacheKey().buildBilltype(srcBillType).buildPkGroup(pk_group)).getNodecode();if (funNode == null || funNode.equals(""))throw new PFBusinessException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000001", null, new String[] { srcBillType })/* 请注册单据{0}的功能节点号 */);// 查询交换信息,以便得到一些参照制单的定制信息String src_qrytemplate = null;String src_billui = null; // 来源单据的显示UI类String src_nodekey = null; // 用于查询来源单据的查询模板的节点标识ExchangeVO changeVO = getExchangeService().queryMostSuitableExchangeVO(srcBillType, currBillOrTranstype, null, PfUtilUITools.getLoginGroup(), null);if (changeVO != null) {src_qrytemplate = changeVO.getSrc_qrytemplate();src_qrytemplate = src_qrytemplate == null ? null : src_qrytemplate.trim();src_billui = changeVO.getSrc_billui();src_nodekey = changeVO.getSrc_nodekey();}// a.获取来源单据的查询对话框,即为m_condition赋值IBillReferQuery qcDLG = null;if (StringUtil.isEmptyWithTrim(src_qrytemplate)) {Logger.debug("使用来源单据类型对应节点使用的查询模板对话框");src_qrytemplate = PfUtilUITools.getTemplateId(ITemplateStyle.queryTemplate, pk_group, funNode, userId, src_nodekey);qcDLG = setConditionClient(src_qrytemplate, parent, userId, funNode, pk_group);} else if (src_qrytemplate.startsWith("<")) {Logger.debug("使用产品组定制的来源单据查询对话框");src_qrytemplate = src_qrytemplate.substring(1, src_qrytemplate.length() - 1);qcDLG = loadUserQuery(parent, src_qrytemplate, pk_group, userId, funNode, currBillOrTranstype, srcBillType, src_nodekey, userObj);} else {Logger.debug("使用注册的查询模板的查询对话框");qcDLG = setConditionClient(src_qrytemplate, parent, userId, funNode, pk_group);}if (busiTypes != null && qcDLG instanceof IBillReferQueryWithBusitype)((IBillReferQueryWithBusitype) qcDLG).setBusitypes(busiTypes);if (srcBillId == null) {// b.显示来源单据的查询对话框if (qcDLG.showModal() == UIDialog.ID_OK) {// c.显示来源单据,并进行选择refBillSource(pk_group, funNode, userId, currBillOrTranstype, parent, userObj, srcBillType, src_qrytemplate, src_billui, src_nodekey, null, qcDLG);} else {m_isOk = false;return;}} else {// b'.直接显示来源单据refBillSource(pk_group, funNode, userId, currBillOrTranstype, parent, userObj, srcBillType, src_qrytemplate, src_billui, src_nodekey, srcBillId, qcDLG);return;}} catch (Exception ex) {Logger.error(ex.getMessage(), ex);MessageDialog.showErrorDlg(parent, NCLangRes.getInstance().getStrByID("pfworkflow1", "SplitRuleRegisterUI-000005")/* 错误 */, NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000002", null, new String[] { ex.getMessage() })/* 参照上游单据出现异常={0} */);}}/*** 参照制单时,显示来源单据;并进行VO交换*/private static void refBillSource(String pk_group, String funNode, String pkOperator, String currBillOrTranstype, Container parent, Object userObj, String billType, String strQueryTemplateId, String src_billui, String srcNodekey, String sourceBillId, IBillReferQuery qcDLG) throws Exception {// 获取主表的关键字段String pkField = PfUtilBaseTools.findPkField(billType);if (pkField == null || pkField.trim().length() == 0)throw new PFBusinessException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000003")/* 无法通过单据类型获取单据实体的主表PK字段 */);String whereString = null;IQueryScheme qryScheme = null;if (sourceBillId == null) {if (qcDLG instanceof IBillReferQueryWithScheme) {qryScheme = ((IBillReferQueryWithScheme) qcDLG).getQueryScheme();} elsewhereString = qcDLG.getWhereSQL();} elsewhereString = pkField + "='" + sourceBillId + "'";// 载入来源单据展现对话框,并显示BillSourceVar bsVar = new BillSourceVar();bsVar.setBillType(billType);bsVar.setCurrBillOrTranstype(currBillOrTranstype);bsVar.setFunNode(funNode);bsVar.setNodeKey(srcNodekey);bsVar.setPk_group(pk_group);bsVar.setPkField(pkField);bsVar.setQryTemplateId(strQueryTemplateId);bsVar.setUserId(pkOperator);bsVar.setUserObj(userObj);bsVar.setWhereStr(whereString);if (qryScheme != null)bsVar.setQueryScheme(qryScheme);AbstractBillSourceDLG bsDlg = null;if (!StringUtil.isEmptyWithTrim(src_billui)) {Logger.debug("产品组定制的来源单据展现对话框,必须继承自" + AbstractBillSourceDLG.class.getName());bsDlg = loadCustomBillSourceDLG(src_billui, bsVar, parent);} else {Logger.debug("使用通用的来源单据展现对话框");bsDlg = new BillSourceDLG(parent, bsVar);}bsDlg.setQueyDlg(qcDLG); // 放入查询模板对话框// 加载模版bsDlg.addBillUI();// 加载数据bsDlg.loadHeadData();if (bsDlg.showModal() == UIDialog.ID_OK) {m_sourceBillType = billType;m_currentBillType = currBillOrTranstype;m_tmpRetVo = bsDlg.getRetVo();m_tmpRetVos = bsDlg.getRetVos();m_isOk = true;} else {m_isOk = false;}}/*** 返回 当前审批节点的处理结果 lj+ 2005-1-20*/public static int getCurrentCheckResult() {return m_iCheckResult;}/*** 返回 用户选择的VO*/public static AggregatedValueObject getRetOldVo() {return m_tmpRetVo;}/*** 返回 用户选择VO数组.*/public static AggregatedValueObject[] getRetOldVos() {return m_tmpRetVos;}/*** 返回 用户选择的VO或交换过的VO* * @return*/public static AggregatedValueObject getRetVo() {try {// 需要进行VO交换m_tmpRetVo = getExchangeService().runChangeData(m_sourceBillType, m_currentBillType, m_tmpRetVo, null);jumpBusitype(m_tmpRetVo == null ? null : new AggregatedValueObject[] { m_tmpRetVo });} catch (Exception ex) {Logger.error(ex.getMessage(), ex);throw new PFRuntimeException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000004", null, new String[] { ex.getMessage() })/* VO交换错误:{0} */, ex);}return m_tmpRetVo;}/*** 返回 用户选择VO数组或交换过的VO数组* * @return* @throws BusinessException*/public static AggregatedValueObject[] getRetVos() throws BusinessException {// 默认根据业务流程进行VO交换return getRetVos(true);}/*** 返回 用户选择VO数组或交换过的VO数组* * @param exchangeByBusiType 是否根据业务流程进行交换,如果否,则在交换前将来源业务流程PK清除* @return* @throws BusinessException*/public static AggregatedValueObject[] getRetVos(boolean exchangeByBusiType) throws BusinessException {// 如果不根据业务流程进行交换,则将单据中的业务流程PK去掉(供应链的需求,来源单据有业务流程pK,但是想走的是另外的流程)if (!exchangeByBusiType && m_tmpRetVos != null) {for (int i = 0; i < m_tmpRetVos.length; i++) {AggregatedValueObject aggVO = m_tmpRetVos[i];IFlowBizItf fbi = PfMetadataTools.getBizItfImpl(aggVO, IFlowBizItf.class);if (fbi != null) {fbi.setBusitype(null);}}}// 需要进行VO交换m_tmpRetVos = changeVos(m_tmpRetVos, m_classifyMode);jumpBusitype(m_tmpRetVos);return m_tmpRetVos;}private static IPfExchangeService getExchangeService() {if (exchangeService == null)exchangeService = NCLocator.getInstance().lookup(IPfExchangeService.class);return exchangeService;}/*** 返回 用户选择的VO或交换过的VO* * @return*/private static AggregatedValueObject[] changeVos(AggregatedValueObject[] vos, int classifyMode) {AggregatedValueObject[] tmpRetVos = null;try {tmpRetVos = getExchangeService().runChangeDataAryNeedClassify(m_sourceBillType, m_currentBillType, vos, null, classifyMode);} catch (BusinessException ex) {Logger.error(ex.getMessage(), ex);throw new PFRuntimeException(NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000004", null, new String[] { ex.getMessage() })/* VO交换错误:{0} */, ex);}return tmpRetVos;}/*** 业务流跳转* * @throws BusinessException*/private static void jumpBusitype(AggregatedValueObject[] vos) throws BusinessException {if (vos == null || vos.length == 0)return;IFlowBizItf fbi = PfMetadataTools.getBizItfImpl(vos[0], IFlowBizItf.class);// 未实现业务流接口的单据或者未走流程直接returnif (fbi == null || StringUtil.isEmptyWithTrim(fbi.getBusitype()))return;BillbusinessVO condVO = new BillbusinessVO();condVO.setPk_businesstype(fbi.getBusitype());condVO.setJumpflag(UFBoolean.TRUE);// 得到单据类型编码String billtype = PfUtilBaseTools.getRealBilltype(m_currentBillType);condVO.setPk_billtype(billtype);condVO.setTranstype(fbi.getTranstype());try {Collection co = NCLocator.getInstance().lookup(IUAPQueryBS.class).retrieve(condVO, true);if (co.size() > 0) {HashMap<String, String> busitypeMaps = new HashMap<String, String>();for (AggregatedValueObject vo : vos) {String destBusitypePk = null;fbi = PfMetadataTools.getBizItfImpl(vo, IFlowBizItf.class);String transtype = fbi.getTranstype();String pk_org = fbi.getPkorg();String operator = PfUtilUITools.getLoginUser();if (StringUtil.isEmptyWithTrim(billtype)) {// 单据类型不能为空continue;}String key = billtype + (StringUtil.isEmptyWithTrim(transtype) ? "" : transtype) + (StringUtil.isEmptyWithTrim(pk_org) ? "" : pk_org) + operator;if (busitypeMaps.containsKey(key)) {destBusitypePk = busitypeMaps.get(key);} else {destBusitypePk = NCLocator.getInstance().lookup(IPFConfig.class).retBusitypeCanStart(billtype, transtype, pk_org, operator);}// 如果没有找到要跳转的业务流if (StringUtil.isEmptyWithTrim(destBusitypePk)) {continue;}fbi.setBusitype(destBusitypePk);}}} catch (DAOException e) {Logger.error(e.getMessage(), e);}}/*** 判断用户是否点击了"取消"按钮* * @return boolean leijun+*/public static boolean isCanceled() {return !m_checkFlag;}/*** 返回 参照单据是否正常关闭* * @return boolean*/public static boolean isCloseOK() {return m_isOk;}/*** 返回 当前单据动作执行是否成功* * @return boolean*/public static boolean isSuccess() {return m_isSuccess;}/*** 载入产品组注册的来源单据显示对话框*/private static AbstractBillSourceDLG loadCustomBillSourceDLG(String src_billui, BillSourceVar bsVar, Container parent) {Class c = null;try {c = Class.forName(src_billui);Class[] argCls = new Class[] { Container.class, BillSourceVar.class };Object[] args = new Object[] { parent, bsVar };// 实例化带参构造方法Constructor cc = c.getConstructor(argCls);return (AbstractBillSourceDLG) cc.newInstance(args);} catch (Exception ex) {Logger.error(ex.getMessage(), ex);MessageDialog.showErrorDlg(parent, null, NCLangRes.getInstance().getStrByID("pfworkflow1", "PfUtilClient-000005", null, new String[] { ex.getMessage() })/* 载入产品组注册的来源单据显示对话框 发生异常:{0} */);}return null;}private static IBillReferQuery loadUserQuery(Container parent, String src_qrytemplate, String pk_group, String userId, String FunNode, String currBillOrTranstype, String sourceBillType, String nodeKey, Object userObj) {Class c = null;try {// 先判定是否为新查询模板UI的子类String qtId = PfUtilUITools.getTemplateId(ITemplateStyle.queryTemplate, pk_group, FunNode, userId, nodeKey);TemplateInfo ti = new TemplateInfo();ti.setTemplateId(qtId);ti.setPk_Org(pk_group);ti.setUserid(userId);ti.setCurrentCorpPk(pk_group);ti.setFunNode(FunNode);ti.setNodekey(nodeKey);c = Class.forName(src_qrytemplate);Object retObj = c.getConstructor(new Class[] { Container.class, TemplateInfo.class }).newInstance(new Object[] { parent, ti });// 对查询模版对话框的一些定制初始化if (retObj instanceof IinitQueryData) {((IinitQueryData) retObj).initData(pk_group, userId, FunNode, currBillOrTranstype, sourceBillType, nodeKey, userObj);}return (IBillReferQuery) retObj;} catch (NoSuchMethodException e) {Logger.warn("找不到新查询模板UI的构造方法,继续判定是否有老查询模板的构造方法", e);try {// 应该为老查询模板UI的子类Object retObj = c.getConstructor(new Class[] { Container.class }).newInstance(new Object[] { parent });// 对查询模版对话框的一些定制初始化if (retObj instanceof IinitQueryData) {((IinitQueryData) retObj).initData(pk_group, userId, FunNode, currBillOrTranstype, sourceBillType, nodeKey, userObj);}return (IBillReferQuery) retObj;} catch (Exception ex) {Logger.error(ex.getMessage(), ex);}} catch (Exception e) {Logger.error(e.getMessage(), e);}return null;}private static IFuncletWindow getParentFuncletWindow(Container parent, String actionCode, String billType) {if (PfUtilBaseTools.isApproveAction(actionCode, billType)) {// yanke1+ 2011-9-8// 找到单据节点的IFuncletWindow// 判断打开方式是否为对话框if (parent instanceof AbstractFunclet) {AbstractFunclet func = (AbstractFunclet) parent;String funcCode = func.getFuncCode();IFuncletWindow[] windows = WorkbenchEnvironment.getInstance().getAllOpenedFuncletWindow();for (IFuncletWindow window : windows) {String windowCode = window.getFuncRegisterVO().getFuncode();if (windowCode.equals(funcCode)) {isOpenedInDialog = (window instanceof JDialog);return window;}}}}return null;}/*** 前台单据动作处理API,算法如下:* <li>1.动作执行前提示以及事前处理,如果用户取消,则方法直接返回* <li>2.查看扩展参数,判断是否需要审批流相关处理。如果为提交动作,则可能需要收集提交人的指派信息; 如果为审批动作,则可能需要收集审批人的审批信息* <li>3.后台执行动作。并返回动作执行结果。* * @param parent          父窗体 -- 需要LoginContext.EntranceUI* @param actionCode      动作编码,比如"SAVE"* @param billOrTranstype 单据(或交易)类型PK* @param billvo          单据聚合VO* @param userObj         用户自定义对象* @param checkVo         校验单据聚合VO* @param eParam          扩展参数* @return 动作处理的返回结果* @throws BusinessException* @throws Exception* @since 5.5*/public static Object runAction(Container parent, String actionCode, String billOrTranstype, AggregatedValueObject billvo, Object userObj, String strBeforeUIClass, AggregatedValueObject checkVo, HashMap eParam) throws BusinessException {eParam = initEParam(eParam);Logger.debug("*单据动作处理 开始");debugParams(actionCode, billOrTranstype, billvo, userObj);long start = System.currentTimeMillis();m_isSuccess = true;m_checkFlag = true;isOpenedInDialog = false;IFuncletWindow parentFuncletWindow = getParentFuncletWindow(parent, actionCode, billOrTranstype);//TODO 先注释掉,目前的调用方式有问题,会增加远程调用次数,不应该在这个时机判断,后续如果有人提问题了再分析一下具体场景
//		if (PfUtilBaseTools.isStartAction(actionCode, billOrTranstype)) {
//			String actionSignlCode = actionCode.replace(IPFActionName.START,
//					IPFActionName.SIGNAL);
//			try {
//				WorkflownoteVO noteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionSignlCode, billOrTranstype,billvo, eParam);
//				// 如果有代办任务
//				if (noteVO != null)
//					actionCode = actionSignlCode;
//			} catch (BusinessException be) {
//				Logger.error("工作流回退业务处理,找不到工作项即不用替换动作代码,继续执行即可");
//			}
//		}// 1.动作执行前提示boolean isContinue = hintBeforeAction(parent, actionCode, billOrTranstype);if (!isContinue) {Logger.debug("*动作执行前提示,返回");m_isSuccess = false;return null;}// 2.查看扩展参数,是否要流程交互处理WorkflownoteVO worknoteVO = null;/// 批量审批出错(WorkflownoteVO)getParamFromMap(eParam,/// PfUtilBaseTools.PARAM_WORKNOTE);Object paramSilent = getParamFromMap(eParam, PfUtilBaseTools.PARAM_SILENTLY);/// if(worknoteVO == null){//批量审批出错Object paramNoflow = getParamFromMap(eParam, PfUtilBaseTools.PARAM_NOFLOW);if (paramNoflow == null && paramSilent == null) {// 需要交互处理if (PfUtilBaseTools.isSaveAction(actionCode, billOrTranstype) || PfUtilBaseTools.isApproveAction(actionCode, billOrTranstype)) {// 审批流交互处理worknoteVO = actionAboutApproveflow(parent, actionCode, billOrTranstype, billvo, eParam, 0);if (!m_isSuccess)return null;} else if (PfUtilBaseTools.isStartAction(actionCode, billOrTranstype) || PfUtilBaseTools.isSignalAction(actionCode, billOrTranstype)) {// 工作流互处理worknoteVO = actionAboutWorkflow(parent, actionCode, billOrTranstype, billvo, eParam, 0);if (!m_isSuccess)return null;}// putParam(eParam, PfUtilBaseTools.PARAM_WORKNOTE, worknoteVO);}/// }//批量审批出错// 如果用户在交互处理时候选择加签或者改派,则无需驱动流程@2009-5if (worknoteVO != null && PfUtilClientAssistor.isAddApproverOrAppoint(worknoteVO)) {// zhouhenga 此时返回原始的单据vo,使得侧边栏刷新// liangyub 通过侧边栏加签操作,成功后加以提示if (eParam != null && eParam.get(PfUtilBaseTools.PARAM_BESIDEAPPROVE) != null) {if (eParam.get(PfUtilBaseTools.PARAM_BESIDEAPPROVE) instanceof BesideApproveContext) {BesideApproveContext besideContext = (BesideApproveContext) eParam.get(PfUtilBaseTools.PARAM_BESIDEAPPROVE);if (besideContext.isAddAssign()) {MessageDialog.showHintDlg(parent, NCLangRes.getInstance().getStrByID("pfworkflow63", "2PLATFORM-00082")/* 操作成功 */, NCLangRes.getInstance().getStrByID("pfworkflow63", "2PLATFORM-00083")/* 单据加签成功 */);}}}return billvo;}if (worknoteVO == null) {// 检查不到工作项,则后台无需再次检查if (eParam == null)eParam = new HashMap<String, String>();if (paramSilent == null)eParam.put(PfUtilBaseTools.PARAM_NOTE_CHECKED, PfUtilBaseTools.PARAM_NOTE_CHECKED);}// 4.后台执行动作Object retObj = null;Logger.debug("*后台动作处理 开始");long start2 = System.currentTimeMillis();IplatFormEntry iIplatFormEntry = (IplatFormEntry) NCLocator.getInstance().lookup(IplatFormEntry.class.getName());retObj = iIplatFormEntry.processAction(actionCode, billOrTranstype, worknoteVO, billvo, userObj, eParam);Logger.debug("*后台动作处理 结束=" + (System.currentTimeMillis() - start2) + "ms");m_isSuccess = true;// 5.返回对象执行// retObjRun(parent, retObj);Logger.debug("*单据动作处理 结束=" + (System.currentTimeMillis() - start) + "ms");if (m_isSuccess && worknoteVO != null) {// 更新消息的状态MessageProcessorContext.setHandledWithProcessor(worknoteVO);}if (m_isSuccess && isOpenedInDialog && isAutoCloseParentDialog && parentFuncletWindow != null && PfUtilBaseTools.isApproveAction(actionCode, billOrTranstype)) {// 审批成功、单据为对话框打开、且审批时选择了自动关闭单据界面// yanke1 2012-7-18 那么关闭单据界面final IFuncletWindow p = parentFuncletWindow;// 放到swing线程里,否则界面会卡死掉SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {p.forceCloseWindow();}});}return retObj;}private static Object getParamFromMap(HashMap eParam, String paramKey) {return eParam == null ? null : eParam.get(paramKey);}/*** 工作流相关的交互处理* * @throws BusinessException*/private static WorkflownoteVO actionAboutWorkflow(Container parent, String actionName, String billType, AggregatedValueObject billvo, HashMap eParam, int voAryLen) throws BusinessException {WorkflownoteVO worknoteVO = null;if (PfUtilBaseTools.isStartAction(actionName, billType)) {Logger.debug("*启动动作=" + actionName + ",检查工作流");Stack dlgResult = new Stack();worknoteVO = checkOnStart(parent, actionName, billType, billvo, dlgResult, eParam);if (dlgResult.size() > 0) {m_isSuccess = false;Logger.debug("*用户指派时点击了取消,则停止启动工作流");}} else if (PfUtilBaseTools.isSignalAction(actionName, billType)) {Logger.debug("*执行动作=" + actionName + ",检查工作流");// 检查该单据是否处于工作流中worknoteVO = checkWorkitemWhenSignal(parent, actionName, billType, billvo, eParam, voAryLen);if (worknoteVO != null) {if ("Y".equals(worknoteVO.getApproveresult())) {m_iCheckResult = IApproveflowConst.CHECK_RESULT_PASS;} else if ("R".equals(worknoteVO.getApproveresult())) {// XXX::驳回也作为审批通过的一种,需要继续判断 lj+WFTask currTask = worknoteVO.getTaskInfo().getTask();if (currTask != null && currTask.getTaskType() == WfTaskType.Backward.getIntValue()) {if (currTask.isBackToFirstActivity())m_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_FIRST;elsem_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_LAST;}} elsem_iCheckResult = IApproveflowConst.CHECK_RESULT_NOPASS;} else if (!m_checkFlag) {m_isSuccess = false;Logger.debug("*用户驱动工作流时点击了取消,则停止执行工作流");}}return worknoteVO;}/*** 审批流相关的交互处理* * @throws BusinessException*/private static WorkflownoteVO actionAboutApproveflow(Container parent, String actionName, String billType, Object billvos, HashMap eParam, int voAryLen) throws BusinessException {WorkflownoteVO worknoteVO = null;if (PfUtilBaseTools.isSaveAction(actionName, billType)) {Logger.debug("*提交动作=" + actionName + ",检查审批流");// 如果为提交动作,可能需要收集提交人的指派信息,这里统一动作名称 lj@2005-4-8Stack dlgResult = new Stack();// billvos传值为单值或者数组 qf@2015-1-22AggregatedValueObject billvo = null;if (billvos instanceof AggregatedValueObject) {billvo = (AggregatedValueObject) billvos;} else if (billvos instanceof AggregatedValueObject[]) {AggregatedValueObject[] vos = (AggregatedValueObject[]) billvos;billvo = vos[0];}worknoteVO = checkOnSave(parent, IPFActionName.SAVE, billType, billvo, dlgResult, eParam);if (dlgResult.size() > 0) {m_isSuccess = false;Logger.debug("*用户指派时点击了取消,则停止送审");}} else if (PfUtilBaseTools.isApproveAction(actionName, billType)) {Logger.debug("*审批动作=" + actionName + ",检查审批流");// 检查该单据是否处于审批流中,并收集审批人的审批信息worknoteVO = checkWorkitemWhenApprove(parent, actionName, billType, billvos, eParam, voAryLen);if (worknoteVO != null) {if ("Y".equals(worknoteVO.getApproveresult())) {m_iCheckResult = IApproveflowConst.CHECK_RESULT_PASS;} else if ("R".equals(worknoteVO.getApproveresult())) {// XXX::驳回也作为审批通过的一种,需要继续判断 lj+WFTask currTask = worknoteVO.getTaskInfo().getTask();if (currTask != null && currTask.getTaskType() == WfTaskType.Backward.getIntValue()) {if (currTask.isBackToFirstActivity())m_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_FIRST;elsem_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_LAST;}} elsem_iCheckResult = IApproveflowConst.CHECK_RESULT_NOPASS;} else if (!m_checkFlag) {m_isSuccess = false;Logger.debug("*用户审批时点击了取消,则停止审批");}}return worknoteVO;}private static PFClientBizRetObj executeBusinessPlugin(Container parent, AggregatedValueObject billVo, WorkflownoteVO wfVo, boolean isMakeBill) {if (wfVo != null && wfVo.getApplicationArgs() != null && wfVo.getApplicationArgs().size() > 0) {String billtype = wfVo.getTaskInfo().getTask().getBillType();ArrayList<Billtype2VO> bt2VOs = PfDataCache.getBillType2Info(billtype, ExtendedClassEnum.PROC_CLIENT.getIntValue());// 实例化for (Iterator iterator = bt2VOs.iterator(); iterator.hasNext();) {Billtype2VO bt2VO = (Billtype2VO) iterator.next();try {Object obj = PfUtilTools.findBizImplOfBilltype(billtype, bt2VO.getClassname());PfClientBizProcessContext context = new PfClientBizProcessContext();context.setBillvo(billVo);context.setArgsList(wfVo.getApplicationArgs());context.setMakeBill(isMakeBill);return ((IPFClientBizProcess) obj).execute(parent, context);} catch (Exception e) {Logger.error("无法实例化前台业务插件类billType=" + billtype + ",className=" + bt2VO.getClassname(), e);}}}return null;}/*** @return 是否侧边栏审批*/private static boolean isBesideApprove(HashMap hmPfExParams) {return hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BESIDEAPPROVE) != null;}//	/**
//	 * 批审时的交互处理
//	 * @throws BusinessException 
//	 */
//	private static WorkflownoteVO batchActionAboutApproveflow(Container parent, String actionName,
//			String billType, AggregatedValueObject[] voAry, HashMap eParam) throws BusinessException {
//		WorkflownoteVO worknoteVO = null;
//
//		if (PfUtilBaseTools.isSaveAction(actionName)) {
//			Logger.debug("*提交动作=" + actionName + ",检查审批流");
//		} else if (PfUtilBaseTools.isApproveAction(actionName)) {
//			Logger.debug("*审批动作=" + actionName + ",检查审批流");
//			// 检查该单据是否处于审批流中,并收集审批人的审批信息
//			worknoteVO = checkWorkitemWhenApprove(parent, actionName, billType, null, eParam);
//			if (worknoteVO != null) {
//				if ("Y".equals(worknoteVO.getApproveresult())) {
//					// XXX::驳回也作为审批通过的一种,需要继续判断 lj+
//					WFTask currTask = worknoteVO.getTaskInfo().getTask();
//					if (currTask.getTaskType() == WfTaskType.Backward.getIntValue()) {
//						if (currTask.isBackToFirstActivity())
//							m_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_FIRST;
//						else
//							m_iCheckResult = IApproveflowConst.CHECK_RESULT_REJECT_LAST;
//					} else
//						m_iCheckResult = IApproveflowConst.CHECK_RESULT_PASS;
//				} else
//					m_iCheckResult = IApproveflowConst.CHECK_RESULT_NOPASS;
//			} else if (!m_checkFlag) {
//				m_isSuccess = false;
//				Logger.debug("*用户审批时点击了取消,则停止审批");
//			}
//		}
//		return worknoteVO;
//	}/*** 日志一下动作处理的上下文参数*/private static void debugParams(String actionCode, String billType, Object billEntity, Object userObj) {Logger.debug("*********************************************");Logger.debug("* actionCode=" + actionCode);Logger.debug("* billType=" + billType);Logger.debug("* billEntity=" + billEntity);Logger.debug("* userObj=" + userObj);Logger.debug("*********************************************");}/*** 动作执行前提示*/private static boolean hintBeforeAction(Container parent, String actionName, String billType) {ActionClientParams acp = new ActionClientParams();acp.setUiContainer(parent);acp.setActionCode(actionName);acp.setBillType(billType);return PfUtilUITools.beforeAction(acp);}/*** 前台单据动作批处理API,算法如下:* <li>1.动作执行前提示以及事前处理,如果用户取消,则方法直接返回* <li>2.查看扩展参数,判断是否需要审批流相关处理。如果为提交动作,且单据VO数组中只有一张单据时可能需要收集提交人的指派信息;* 如果为审批动作,则针对第一张单据可能需要收集审批人的审批信息* <li>3.后台执行批动作。并返回动作执行结果。* * @param parent          父窗体* @param actionCode      动作编码,比如"SAVE"* @param billOrTranstype 单据类型(或交易类型)PK* @param voAry           单据聚合VO数组* @param userObjAry      用户自定义对象数组* @param eParam          扩展参数* @return 动作批处理的返回结果* @throws Exception* @since 5.5*/public static Object[] runBatch(Container parent, String actionCode, String billOrTranstype, AggregatedValueObject[] voAry, Object[] userObjAry, String strBeforeUIClass, HashMap eParam) throws Exception {eParam = initEParam(eParam);Logger.debug("*单据动作批处理 开始");debugParams(actionCode, billOrTranstype, voAry, userObjAry);long start = System.currentTimeMillis();if (isSingleDataRun(voAry, eParam)) {Object obj = runAction(parent, actionCode, billOrTranstype, voAry[0], userObjAry, strBeforeUIClass, null, eParam);Object[] ret = null;ret = PfUtilBaseTools.composeResultAry(obj, 1, 0, ret);return ret;}m_isSuccess = true;m_checkFlag = true;// 1.动作执行前提示以及事前处理boolean isContinue = beforeProcessBatchAction(parent, actionCode, billOrTranstype);if (!isContinue) {Logger.debug("*动作执行前提示以及事前处理,返回");m_isSuccess = false;return null;}WorkflownoteVO workflownote = null;// 2.查看扩展参数,是否要流程交互处理Object paramNoflow = getParamFromMap(eParam, PfUtilBaseTools.PARAM_NOFLOW);Object paramSilent = getParamFromMap(eParam, PfUtilBaseTools.PARAM_SILENTLY);if (paramNoflow == null && paramSilent == null) {// XXX:guowl,2010-5,批审时,审批处理对话框上只显示批准、不批准、驳回,故传入一个参数用于甄别// 如果传人的VO数组长度为1,同单个处理一样if (voAry != null && voAry.length > 1) {eParam = putParam(eParam, PfUtilBaseTools.PARAM_BATCH, PfUtilBaseTools.PARAM_BATCH);}if (PfUtilBaseTools.isSaveAction(actionCode, billOrTranstype) || PfUtilBaseTools.isApproveAction(actionCode, billOrTranstype)) {// 审批流交互处理workflownote = actionAboutApproveflow(parent, actionCode, billOrTranstype, voAry, eParam, voAry.length);if (!m_isSuccess)return null;} else if (PfUtilBaseTools.isStartAction(actionCode, billOrTranstype) || PfUtilBaseTools.isSignalAction(actionCode, billOrTranstype)) {// 工作流交互处理workflownote = actionAboutWorkflow(parent, actionCode, billOrTranstype, voAry[0], eParam, voAry.length);if (!m_isSuccess)return null;}}// 3.后台批处理动作Logger.debug("*后台动作批处理 开始");Object retObj = NCLocator.getInstance().lookup(IplatFormEntry.class).processBatch(actionCode, billOrTranstype, workflownote, voAry, userObjAry, eParam);if (retObj instanceof PfProcessBatchRetObject) {String errMsg = ((PfProcessBatchRetObject) retObj).getExceptionMsg();if (!StringUtil.isEmptyWithTrim(errMsg))MessageDialog.showErrorDlg(parent, null, errMsg);retObj = ((PfProcessBatchRetObject) retObj).getRetObj();}if (retObj != null && ((Object[]) retObj).length > 0) {// 批处理时,有一个成功的就认为成功m_isSuccess = true;}Logger.debug("*单据动作批处理 结束=" + (System.currentTimeMillis() - start) + "ms");return (Object[]) retObj;}private static HashMap initEParam(HashMap eParam) {eParam = eParam != null ? eParam : new HashMap();return eParam;}public static PfProcessBatchRetObject runBatchNew(Container parent, String actionCode, String billOrTranstype, AggregatedValueObject[] voAry, Object[] userObjAry, String strBeforeUIClass, HashMap eParam) throws Exception {eParam = initEParam(eParam);Logger.debug("*单据动作批处理 开始");debugParams(actionCode, billOrTranstype, voAry, userObjAry);long start = System.currentTimeMillis();if (isSingleDataRun(voAry, eParam)) {Object obj = runAction(parent, actionCode, billOrTranstype, voAry[0], userObjAry, strBeforeUIClass, null, eParam);Object[] retObj = null;retObj = PfUtilBaseTools.composeResultAry(obj, 1, 0, retObj);return new PfProcessBatchRetObject(retObj, null);}m_isSuccess = true;m_checkFlag = true;// 1.动作执行前提示以及事前处理boolean isContinue = beforeProcessBatchAction(parent, actionCode, billOrTranstype);if (!isContinue) {Logger.debug("*动作执行前提示以及事前处理,返回");m_isSuccess = false;return null;}// 2.查看扩展参数,是否要流程交互处理WorkflownoteVO workflownote = null;// (WorkflownoteVO)getParamFromMap(eParam, PfUtilBaseTools.PARAM_WORKNOTE);
//		if(workflownote == null){Object paramNoflow = getParamFromMap(eParam, PfUtilBaseTools.PARAM_NOFLOW);Object paramSilent = getParamFromMap(eParam, PfUtilBaseTools.PARAM_SILENTLY);if (paramNoflow == null && paramSilent == null) {// XXX:guowl,2010-5,批审时,审批处理对话框上只显示批准、不批准、驳回,故传入一个参数用于甄别// 如果传人的VO数组长度为1,同单个处理一样if (voAry != null && voAry.length > 1) {eParam = putParam(eParam, PfUtilBaseTools.PARAM_BATCH, PfUtilBaseTools.PARAM_BATCH);}if (PfUtilBaseTools.isSaveAction(actionCode, billOrTranstype) || PfUtilBaseTools.isApproveAction(actionCode, billOrTranstype)) {// 审批流交互处理workflownote = actionAboutApproveflow(parent, actionCode, billOrTranstype, voAry, eParam, voAry.length);if (!m_isSuccess)return null;} else if (PfUtilBaseTools.isStartAction(actionCode, billOrTranstype) || PfUtilBaseTools.isSignalAction(actionCode, billOrTranstype)) {// 工作流交互处理workflownote = actionAboutWorkflow(parent, actionCode, billOrTranstype, voAry[0], eParam, voAry.length);if (!m_isSuccess)return null;}
//				putParam(eParam, PfUtilBaseTools.PARAM_WORKNOTE, workflownote);}// }// 3.后台批处理动作Logger.debug("*后台动作批处理 开始");Object retObj = NCLocator.getInstance().lookup(IplatFormEntry.class).processBatch(actionCode, billOrTranstype, workflownote, voAry, userObjAry, eParam);Logger.debug("*单据动作批处理 结束=" + (System.currentTimeMillis() - start) + "ms");return (PfProcessBatchRetObject) retObj;}private static boolean isSingleDataRun(AggregatedValueObject[] voAry, HashMap eParam) {return voAry != null && voAry.length == 1 && eParam.get(PfUtilBaseTools.PARAM_WORKNOTE) == null;}private static HashMap putParam(HashMap eParam, String paramKey, Object value) {if (eParam == null) {eParam = new HashMap();}eParam.put(paramKey, value);return eParam;}/*** 动作执行前提示以及事前处理*/private static boolean beforeProcessBatchAction(Container parent, String actionName, String billType) throws Exception {ActionClientParams acp = new ActionClientParams();acp.setUiContainer(parent);acp.setActionCode(actionName);acp.setBillType(billType);return PfUtilUITools.beforeAction(acp);}/*** 返回某个单据或交易类型可使用的“新增”下拉菜单信息* <li>包括自制、来源单据* * @param billtype* @param transtype       如果没有交易类型,可空* @param pk_group        某集团PK* @param userId          某用户PK* @param includeBillType 是否包括单据类型的来源单据信息,只用于transtype非空的情况* @return* @throws BusinessException*/public static PfAddInfo[] retAddInfo(String billtype, String transtype, String pk_group, String userId, boolean includeBillType) throws BusinessException {return NCLocator.getInstance().lookup(IPFConfig.class).retAddInfo(billtype, transtype, pk_group, userId, includeBillType);}/*** 返回某个用户对某个单据或交易类型,在某组织下 可启动的业务流程* * @param billtype* @param transtype 如果没有交易类型,可空* @param pk_org    某组织PK* @param userId    某用户PK* @return* @throws BusinessException*/public static String retBusitypeCanStart(String billtype, String transtype, String pk_org, String userId) throws BusinessException {return NCLocator.getInstance().lookup(IPFConfig.class).retBusitypeCanStart(billtype, transtype, pk_org, userId);}/*** 返回某单据或交易类型配置的某动作组的所有单据动作* * @param billOrTranstype 单据或交易类型* @param actiongroupCode 动作组编码* @return*/public static BillactionVO[] getActionsOfActiongroup(String billOrTranstype, String actiongroupCode) {// 获得单据类型(或交易类型)的单据类型PKbillOrTranstype = PfUtilBaseTools.getRealBilltype(billOrTranstype);BillactionVO[] billActionVos = (BillactionVO[]) PfUIDataCache.getButtonByBillAndGrp(billOrTranstype, actiongroupCode);return billActionVos;}/*** 构造一个查询对话框,并为其设置查询模板* * @param templateId* @param parent* @param isRelationCorp* @param pkOperator* @param funNode*/private static IBillReferQuery setConditionClient(String templateId, Container parent, final String pkOperator, final String funNode, String pkCorp) {TemplateInfo ti = new TemplateInfo();ti.setTemplateId(templateId);ti.setPk_Org(pkCorp);ti.setUserid(pkOperator);ti.setCurrentCorpPk(pkCorp);ti.setFunNode(funNode);QueryConditionDLG qcDlg = new QueryConditionDLG(parent, ti);qcDlg.setVisibleNormalPanel(false);return qcDlg;}/*** 为NC预算提供的支持不同审批流的工作项批量处理的接口(只用于NC预算批量处理) add by liangyub 2014-04-21* * @param VOArrayMap map<审批流pk,审批的对象级(业务组聚合VO)>*/public static Map<String, PfProcessBatchRetObject> runBatchNewForNC(Container parent, String actionCode, Map<String, List<AggregatedValueObject>> VOArrayMap) throws Exception {Logger.debug("*单据动作批处理 runBatchNewForNC方法开始");// 批量处理逻辑m_isSuccess = true;m_checkFlag = true;Map<String, PfProcessBatchRetObject> result = new HashMap<String, PfProcessBatchRetObject>();// 查询所关联的流程定义String[] defPks = VOArrayMap.keySet().toArray(new String[0]);WorkflowDefinitionVO[] defVOs = getWorkflowDefService().findDefinitionsWithoutContentByPrimaryKeys(defPks);Map<String, String> billTypeMap = new HashMap<String, String>();for (WorkflowDefinitionVO def : defVOs) {billTypeMap.put(def.getPk_wf_def(), def.getBilltype());}// 处理单个逻辑if (VOArrayMap != null && VOArrayMap.size() == 1 && VOArrayMap.get(defPks[0]).size() == 1) {processForSingle(parent, actionCode, VOArrayMap, result, defPks, billTypeMap);return result;}long start = System.currentTimeMillis();Logger.debug("*后台动作批处理 开始");processForMultiple(parent, actionCode, VOArrayMap, result, defPks, billTypeMap);Logger.debug("*单据动作批处理 结束=" + (System.currentTimeMillis() - start) + "ms");return result;}private static IWorkflowDefine getWorkflowDefService() {if (workflowDefService == null) {workflowDefService = NCLocator.getInstance().lookup(IWorkflowDefine.class);}return workflowDefService;}/*** 处理单个任务*/private static void processForSingle(Container parent, String actionCode, Map<String, List<AggregatedValueObject>> VOArrayMap, Map<String, PfProcessBatchRetObject> result, String[] defPks, Map<String, String> billTypeMap) throws BusinessException {// 补全调用参数String billType = billTypeMap.get(defPks[0]);HashMap<String, Object> eParam = new HashMap<String, Object>();eParam.put(PfUtilBaseTools.PARAM_FLOWPK, defPks[0]);Object obj = runAction(parent, actionCode, billType, VOArrayMap.get(defPks[0]).get(0), new Object[] { Integer.valueOf(0) }, null, null, eParam);Object[] retObj = null;retObj = PfUtilBaseTools.composeResultAry(obj, 1, 0, retObj);result.put(defPks[0], new PfProcessBatchRetObject(retObj, null));}/*** 批量处理任务*/private static void processForMultiple(Container parent, String actionCode, Map<String, List<AggregatedValueObject>> VOArrayMap, Map<String, PfProcessBatchRetObject> result, String[] defPks, Map<String, String> billTypeMap) throws BusinessException, Exception {if (VOArrayMap.size() > 1) {processForSingleBillType(parent, actionCode, VOArrayMap, result, defPks, billTypeMap);} else {processForMultipleBillType(parent, actionCode, VOArrayMap, result, defPks, billTypeMap);}}/*** 如果只有一个流程,是属于相同流程的工作项批量处理(有动作执行前提示)*/private static void processForSingleBillType(Container parent, String actionCode, Map<String, List<AggregatedValueObject>> VOArrayMap, Map<String, PfProcessBatchRetObject> result, String[] defPks, Map<String, String> billTypeMap) throws Exception, BusinessException {// 1.动作执行前提示以及事前处理String billType = billTypeMap.get(defPks[0]);AggregatedValueObject[] voAry = VOArrayMap.get(defPks[0]).toArray(new AggregatedValueObject[0]);boolean isContinue = beforeProcessBatchAction(parent, actionCode, billType);if (!isContinue) {Logger.debug("*动作执行前提示以及事前处理,返回");m_isSuccess = false;}// 2.流程交互处理HashMap<String, Object> eParam = new HashMap<String, Object>();eParam.put(PfUtilBaseTools.PARAM_FLOWPK, defPks[0]);eParam.put(PfUtilBaseTools.PARAM_NOTSILENT, new Boolean(true));WorkflownoteVO workflownote = processForBatch(parent, actionCode, billType, voAry, eParam);// 3.后台批处理动作Object retObj = NCLocator.getInstance().lookup(IplatFormEntry.class).processBatch(actionCode, billType, workflownote, voAry, new Object[] { Integer.valueOf(1) }, eParam);result.put(defPks[0], (PfProcessBatchRetObject) retObj);}/*** 如果存在多个流程,是属于不同流程的工作项批量处理(有动作执行前提示)*/private static void processForMultipleBillType(Container parent, String actionCode, Map<String, List<AggregatedValueObject>> VOArrayMap, Map<String, PfProcessBatchRetObject> result, String[] defPks, Map<String, String> billTypeMap) throws BusinessException {// 取第一流程定义下的审批结果,用于补全剩余工作项String billType = billTypeMap.get(defPks[0]);AggregatedValueObject[] voAry = VOArrayMap.get(defPks[0]).toArray(new AggregatedValueObject[0]);HashMap<String, Object> eParam = new HashMap<String, Object>();eParam.put(PfUtilBaseTools.PARAM_FLOWPK, defPks[0]);eParam.put(PfUtilBaseTools.PARAM_NOTSILENT, new Boolean(true));WorkflownoteVO workflownote = processForBatch(parent, actionCode, billType, voAry, eParam);Object retObj = NCLocator.getInstance().lookup(IplatFormEntry.class).processBatch(actionCode, billType, workflownote, voAry, new Object[] { Integer.valueOf(1) }, eParam);result.put(defPks[0], (PfProcessBatchRetObject) retObj);for (int i = 1; i < defPks.length; i++) {String type = billTypeMap.get(defPks[i]);WorkflownoteVO noteVO = new WorkflownoteVO();completeWorkItemInfo(workflownote, noteVO);AggregatedValueObject[] ary = VOArrayMap.get(defPks[i]).toArray(new AggregatedValueObject[0]);HashMap<String, Object> param = new HashMap<String, Object>();eParam.put(PfUtilBaseTools.PARAM_FLOWPK, defPks[i]);Object ret = NCLocator.getInstance().lookup(IplatFormEntry.class).processBatch(actionCode, type, noteVO, ary, new Object[] { Integer.valueOf(1) }, param);result.put(defPks[i], (PfProcessBatchRetObject) ret);}}/*** 用于处理批量审批同一流程的多个工作项,并返回处理过的WorkflownoteVO<br/>*/@SuppressWarnings("unchecked")private static WorkflownoteVO processForBatch(Container parent, String actionCode, String billOrTranstype, AggregatedValueObject[] voAry, HashMap<String, Object> eParam) throws BusinessException {// 1.加入扩展承参数putElecsignatureValue(billOrTranstype, voAry, eParam);// 2.查看扩展参数,是否要流程交互处理WorkflownoteVO workflownote = null;Object paramNoflow = getParamFromMap(eParam, PfUtilBaseTools.PARAM_NOFLOW);Object paramSilent = getParamFromMap(eParam, PfUtilBaseTools.PARAM_SILENTLY);if (paramNoflow == null && paramSilent == null) {// 批审时,审批处理对话框上只显示批准、不批准、驳回,故传入一个参数用于甄别// 如果传人的VO数组长度为1,同单个处理一样if (voAry != null && voAry.length > 1) {eParam = putParam(eParam, PfUtilBaseTools.PARAM_BATCH, PfUtilBaseTools.PARAM_BATCH);}if (PfUtilBaseTools.isSaveAction(actionCode, billOrTranstype) || PfUtilBaseTools.isApproveAction(actionCode, billOrTranstype)) {// 审批流交互处理workflownote = actionAboutApproveflow(parent, actionCode, billOrTranstype, voAry[0], eParam, voAry.length);} else if (PfUtilBaseTools.isStartAction(actionCode, billOrTranstype) || PfUtilBaseTools.isSignalAction(actionCode, billOrTranstype)) {// 工作流交互处理workflownote = actionAboutWorkflow(parent, actionCode, billOrTranstype, voAry[0], eParam, voAry.length);}}return workflownote;}/*** 根据已有工作项,补全当前工作项信息 用于NC预算不同审批流的批量审批*/private static void completeWorkItemInfo(WorkflownoteVO baseVO, WorkflownoteVO toCompleteVO) {toCompleteVO.setChecknote(baseVO.getChecknote());if (baseVO.getApproveresult().equals("Y")) {// 批准toCompleteVO.setApproveresult("Y");} else if (baseVO.getApproveresult().equals("N")) {// 不批准toCompleteVO.setApproveresult("N");} else if (baseVO.getApproveresult().equals("R")) {// 驳回到制单人if (toCompleteVO.getTaskInfo().getTask() != null) {toCompleteVO.getTaskInfo().getTask().setTaskType(WfTaskType.Backward.getIntValue());toCompleteVO.getTaskInfo().getTask().setBackToFirstActivity(true);}toCompleteVO.setApproveresult("R");}toCompleteVO.setApproveresult(baseVO.getApproveresult());}/*** * @since 6.3 批审时候预先判断是否需要CA*/private static void putElecsignatureValue(String billOrTranstype, AggregatedValueObject[] voAry, HashMap eParam) throws BusinessException {// 判断是否需要CAList<String> billIdList = new ArrayList<String>();for (AggregatedValueObject vo : voAry) {billIdList.add(vo.getParentVO().getPrimaryKey());}boolean isNeedCASign = NCLocator.getInstance().lookup(IPFWorkflowQry.class).isNeedCASign4Batch(PfUtilUITools.getLoginUser(), new String[] { billOrTranstype }, billIdList.toArray(new String[0]));if (isNeedCASign) {putParam(eParam, XPDLNames.ELECSIGNATURE, "Y");}}}

流程平台客户端工具类中提交单据时,需要的指派信息方法:

/*** 提交单据时,需要的指派信息* <li>只有"SAVE","EDIT"动作才调用*/private static WorkflownoteVO checkOnSave(Container parent, String actionName, String billType, AggregatedValueObject billVo, Stack dlgResult, HashMap hmPfExParams) throws BusinessException {WorkflownoteVO worknoteVO = new WorkflownoteVO();// guowl+ 2010-5,如果是批处理,不用取指派信息,直接返回if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null)return worknoteVO;try {worknoteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionName, billType, billVo, hmPfExParams);} catch (FlowDefNotFoundException e) {return worknoteVO;}// 在审批处理框显示之前,调用业务处理PFClientBizRetObj retObj = executeBusinessPlugin(parent, billVo, worknoteVO, true);if (retObj != null && retObj.isStopFlow()) {m_isSuccess = false;return null;}if (worknoteVO != null) {// 得到可指派的输入数据Vector assignInfos = worknoteVO.getTaskInfo().getAssignableInfos();if (assignInfos != null && assignInfos.size() > 0) {// 显示指派对话框并收集实际指派信息ApproveFlowDispatchDialog dlg = new ApproveFlowDispatchDialog(parent);dlg.getDisPatchPanel().initByWorknoteVO(worknoteVO);int iClose = dlg.showModal();if (iClose == UIDialog.ID_CANCEL)dlgResult.push(Integer.valueOf(iClose));}}return worknoteVO;}

如应收单保存时,弹出需要指派下个审批环节的参与者弹框就是调用该方法
在这里插入图片描述

3、检查当前单据是否处于审批流程中,并进行交互

审批弹框类:nc.ui.pf.workitem.ApproveWorkitemAcceptDlg

审批弹框调用的方法:

/*** 检查当前单据是否处于审批流程中,并进行交互*/private static WorkflownoteVO checkWorkitemWhenApprove(Container parent, String actionName, String billType, Object billvos, HashMap hmPfExParams, int voAryLen) throws BusinessException {WorkflownoteVO noteVO = null;UIDialog dlg = null;if (voAryLen != 0) {if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) != null) {noteVO = (WorkflownoteVO) hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE);m_checkFlag = true;return noteVO;}}// billvos传值为单值或者数组 qf@2015-1-22AggregatedValueObject billvo = null;AggregatedValueObject[] vos = null;if (billvos instanceof AggregatedValueObject) {billvo = (AggregatedValueObject) billvos;} else if (billvos instanceof AggregatedValueObject[]) {vos = (AggregatedValueObject[]) billvos;billvo = vos[0];}if (hmPfExParams != null && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {Object notSilent = hmPfExParams.get(PfUtilBaseTools.PARAM_NOTSILENT);// 检查单据是否定义了审批流,如果没有定义,则不弹出,此处只简单检查第一张单据的单据类型上是否有流程定义if (notSilent == null && !hasApproveflowDef(billType, billvo)) {m_checkFlag = true;noteVO = new WorkflownoteVO();noteVO.setApproveresult("Y");Logger.debug("*checkWorkitemWhenApprove 1 billType.");return noteVO;} else {// 预算开发部要求批审时不管有没有流程定义,都弹出审批意见框noteVO = new WorkflownoteVO();// 判断是否需要CAList<String> billIdList = new ArrayList<String>();if (vos != null && vos.length != 0) {for (AggregatedValueObject vo : vos) {billIdList.add(vo.getParentVO().getPrimaryKey());}noteVO.getRelaProperties().put(XPDLNames.ELECSIGNATURE, NCLocator.getInstance().lookup(IPFWorkflowQry.class).isNeedCASign4Batch(PfUtilUITools.getLoginUser(), new String[] { billType }, billIdList.toArray(new String[0])));}BatchApproveModel batchApproveMode = new BatchApproveModel();batchApproveMode.setBillUI(true);batchApproveMode.setSingleBillSelected(true);batchApproveMode.setContainUnApproveBill(false);batchApproveMode.setBillItem(voAryLen);dlg = new BatchApproveWorkitemAcceptDlg(parent, noteVO);((BatchApproveWorkitemAcceptDlg) dlg).setBachApproveMode(batchApproveMode);Logger.debug("*checkWorkitemWhenApprove 2.");}} else {noteVO = NCLocator.getInstance().lookup(IWorkflowMachine.class).checkWorkFlow(actionName, billType, billvo, hmPfExParams);Logger.debug("*checkWorkitemWhenApprove 3.");if (noteVO != null && isBesideApprove(hmPfExParams)) {noteVO = BesideApprove(hmPfExParams, noteVO);} else {Object notSilent = null;if (hmPfExParams != null) {notSilent = hmPfExParams.get(PfUtilBaseTools.PARAM_NOTSILENT);}if (noteVO == null) {if (notSilent == null) {m_checkFlag = true;Logger.debug("*checkWorkitemWhenApprove 1 billType.");return noteVO;} else {noteVO = new WorkflownoteVO();}}PFClientBizRetObj retObj = executeBusinessPlugin(parent, billvo, noteVO, false);int workflowtype = noteVO.getWorkflow_type();boolean isInWorkflow = false;if (workflowtype == WorkflowTypeEnum.SubWorkApproveflow.getIntValue())isInWorkflow = true;dlg = new ApproveWorkitemAcceptDlg(parent, noteVO, billvo, isInWorkflow, isOpenedInDialog, retObj == null ? null : retObj.getHintMessage());ApproveWorkitemAcceptDlg acceptDlg = ((ApproveWorkitemAcceptDlg) dlg);if (retObj != null) {// yanke1 2012-02-22 根据前台业务处理的返回值来控制审批界面acceptDlg.setShowPass(retObj.isShowPass());
//					acceptDlg.setShowNoPass(retObj.isShowNoPass());acceptDlg.setShowReject(retObj.isShowReject());}acceptDlg.setShowNoPass(!PfUtilClientAssistor.isHideNoPassing(noteVO.getTaskInfo().getTask()));Logger.debug("*checkWorkitemWhenApprove 4.");}}Logger.debug("*checkWorkitemWhenApprove 5.");if (!isBesideApprove(hmPfExParams)) {if (hmPfExParams == null) {hmPfExParams = new HashMap<String, Object>();}if (dlg.showModal() == UIDialog.ID_OK) { // 如果用户审批if (dlg instanceof ApproveWorkitemAcceptDlg) {isAutoCloseParentDialog = ((ApproveWorkitemAcceptDlg) dlg).isAutoCloseParentDialog();}m_checkFlag = true;} else { // 用户不审批m_checkFlag = false;noteVO = null;}if ((!hmPfExParams.containsKey(PfUtilBaseTools.PARAM_WORKNOTE) || hmPfExParams.get(PfUtilBaseTools.PARAM_WORKNOTE) == null) && hmPfExParams.get(PfUtilBaseTools.PARAM_BATCH) != null) {hmPfExParams.put(PfUtilBaseTools.PARAM_WORKNOTE, noteVO);}}return noteVO;}

在这里插入图片描述

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

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

相关文章

【UML】第8篇 用例图(3/3)

目录 一、用例的关系 1.1 泛化&#xff08;Generalization&#xff09;关系 1.2 包含&#xff08;include&#xff09;关系 1.3 扩展关系 二、用例表示例 不是非要把电影改成连续剧&#xff0c;给大家播&#xff0c;确实是时间和精力有限。 用例图&#xff0c;虽然简单&…

荣誉 | 第七在线(7thonline)荣获STIF2023年度数智化创新典范奖

12月15日&#xff0c;STIF2023 第四届国际科创节暨 DSC2023 国际数字服务大会&#xff08;数服会&#xff09;在北京隆重举行。 在本届科创节暨数服会活动评选中&#xff0c;经企业申报、评委会审议&#xff0c;第七在线&#xff08;7thonline&#xff09;AI智能零售商品计划库…

什么是集成测试?它和系统测试的区别是什么? 操作方法来了

01 什么是集成测试&#xff1f; 集成测试是软件测试的一种方法&#xff0c;用于测试不同的软件模块之间的交互和协作是否正常。集成测试的主要目的是确保不同的软件模块能够无缝协作&#xff0c;形成一个完整的软件系统&#xff0c;并且能够满足系统的需求和规格。 在集成测试…

【3D生成与重建】SSDNeRF:单阶段Diffusion NeRF的三维生成和重建

系列文章目录 题目&#xff1a;Single-Stage Diffusion NeRF: A Unified Approach to 3D Generation and Reconstruction 论文&#xff1a;https://arxiv.org/pdf/2304.06714.pdf 任务&#xff1a;无条件3D生成&#xff08;如从噪音中&#xff0c;生成不同的车等&#xff09;、…

[C++]模板进阶

目录 C模板进阶&#xff1a;&#xff1a; 非类型模板参数 模板的特化 函数模板特化 类模板特化 全特化 偏特化 模板的分离编译 模板总结 C模板进阶&#xff1a;&#xff1a; 非类型模板参数 模板参数可分为类型形参和非类型形参。 类型形参&#xff1a;出现在参数列表中&am…

浅谈Redis分布式锁(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 不论面试还是实际工作中…

信息安全等级保护的定义与意义

目录 前言 信息安全等级保护定义 广义上 狭义上 技术和管理 信息安全的基本要素 信息安全等级保护的意义 当前形式 形式严峻 国家安全 三个基本一个根本 预期目标 最终效果 实际意义 前言 信息安全等级保护是对信息和信息载体按照重要性等级分级进行保护的一种…

Windows平台开发需要掌握的基础知识

windows本身也是一个软件。在这个软件中进行开发时&#xff0c;我们需要对它有个基础的了解&#xff0c;这样能让我们的开发过程更顺畅一些。 下面我就来说一下我们需要关注的基础知识点。 环境变量 有时候我们的程序执行&#xff0c;需要基于一些基础的库。比如Java运行&am…

matlab 最小二乘拟合平面(直接求解法)

目录 一、算法原理二、代码实现三、算法效果本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 平面方程的一般表达式为: A x + B y +

【Skynet 入门实战练习】事件模块 | 批处理模块 | GM 指令 | 模糊搜索

文章目录 前言事件模块批处理模块GM 指令模块模糊搜索最后 前言 本节完善了项目&#xff0c;实现了事件、批处理、模糊搜索模块、GM 指令模块。 事件模块 什么是事件模块&#xff1f;事件模块是用来在各系统之间传递事件消息的。 为什么需要事件模块&#xff1f;主要目的是…

Spring源码分析 @Autowired 是怎样完成注入的?究竟是byType还是byName亦两者皆有

1. 五种不同场景下 Autowired 的使用 第一种情况 上下文中只有一个同类型的bean 配置类 package org.example.bean;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;Configuration public class FruitCo…

推箱子小游戏

--print("开发流程步骤&#xff1a;I、绘制推箱子地图并初始化 ----- 几*几大小的地图 \n\n II、根据宏定义和推箱子地图上的数字来选择不同的图形\n\n III、获取玩家坐标 -----------重点\n\n …

html旋转相册

一、实验题目 做一个旋转的3d相册 二、实验代码 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&qu…

AtomHub 开源容器镜像中心开放公测,国内服务稳定下载

由开放原子开源基金会主导&#xff0c;华为、浪潮、DaoCloud、谐云、青云、飓风引擎以及 OpenSDV 开源联盟、openEuler 社区、OpenCloudOS 社区等成员单位共同发起建设的 AtomHub 可信镜像中心正式开放公测。AtomHub 秉承共建、共治、共享的理念&#xff0c;旨在为开源组织和开…

医保购药小程序:智能合约引领医疗数字革新

在医疗领域&#xff0c;医保购药小程序通过引入智能合约技术&#xff0c;为用户提供更为高效、安全的购药体验。本文将通过简单的智能合约代码示例&#xff0c;深入探讨医保购药小程序如何利用区块链技术中的智能合约&#xff0c;实现医保结算、购药监控等功能&#xff0c;为医…

AI大模型:未来科技的新篇章

目录 1AI大模型&#xff1a;未来科技的新篇章 2AI超越数学家攻克经典数学难题&#xff1b;非侵入式设备解码大脑思维 1AI大模型&#xff1a;未来科技的新篇章 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为了我们生活中不可或缺的一部分。而AI大…

Windows系统找不到xinput1_3.dll怎么办?

引言&#xff1a; 在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是xinput1_3.dll丢失。那么&#xff0c;xinput1_3.dll究竟是什么&#xff1f;为什么会出现丢失的情况&#xff1f;丢失后会对计算机产生什么影响&#xff1f;本文将详细介绍…

2023.12.21 关于 Redis 常用数据结构 和 单线程模型

目录 各数据结构具体编码方式 查看 key 对应 value 的编码方式 Reids 单线程模型 经典面试题 IO 多路复用 Redis 常用数据结构 Redis 中所有的 key 均为 String 类型&#xff0c;而不同的是 value 的数据类型却有很多种以下介绍 5 种 value 常见的数据类型 注意&#xff1…

计算机网络概述(下)——“计算机网络”

各位CSDN的uu们你们好呀&#xff0c;今天继续计算机网络概述的学习&#xff0c;下面&#xff0c;让我们一起进入计算机网络概述的世界吧&#xff01;&#xff01;&#xff01; 计算机网络体系结构 数据传输流程 计算机网络性能指标 计算机网络体系结构 两个计算机系统必须高度…

7.4组合总和(LC39-M)

算法: 组合问题&#xff0c;用回溯。 画树 回溯三部曲&#xff1a; 1.确定函数返回值和参数&#xff1a; 返回值&#xff1a;void 参数&#xff1a; candidates, target&#xff08;题目中给出的&#xff09; sum&#xff1a;统计每个组合的和&#xff0c;是否target …