dangsn
2024-12-03 d0ae279ff3b83358d1c07f4481a041c4ad335026
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/UIDataServiceImpl.java
@@ -1,15 +1,26 @@
package com.vci.web.service.impl;
import com.vci.client.common.oq.OQTool;
import com.vci.common.qt.object.QueryTemplate;
import com.vci.corba.common.PLException;
import com.vci.corba.framework.data.UserInfo;
import com.vci.corba.omd.btm.BizType;
import com.vci.corba.omd.data.*;
import com.vci.corba.omd.data.BusinessObject;
import com.vci.corba.omd.data.LinkObject;
import com.vci.corba.omd.data.RevisionDataInfo;
import com.vci.corba.omd.data.VersionDataInfo;
import com.vci.corba.omd.lcm.LifeCycle;
import com.vci.corba.omd.ltm.LinkType;
import com.vci.corba.omd.qtm.QTInfo;
import com.vci.corba.query.data.BOAndLO;
import com.vci.dto.*;
import com.vci.frameworkcore.lcstatuspck.FrameworkDataLCStatus;
import com.vci.frameworkcore.lcstatuspck.ReleaseDataLCStatus;
import com.vci.lcstatuspck.FrameworkDataLCStatus;
import com.vci.lcstatuspck.ReleaseDataLCStatus;
import com.vci.omd.utils.ObjectTool;
import com.vci.pagemodel.*;
import com.vci.query.UIDataGridQuery;
import com.vci.query.UIFormQuery;
import com.vci.query.UILinkTypeDataQuery;
import com.vci.query.UITreeQuery;
import com.vci.starter.revision.bo.TreeWrapperOptions;
import com.vci.starter.web.annotation.bus.VciChangeDataAfter;
import com.vci.starter.web.annotation.bus.VciChangeDataBefore;
@@ -21,18 +32,16 @@
import com.vci.starter.web.model.BaseModel;
import com.vci.starter.web.pagemodel.*;
import com.vci.starter.web.util.*;
import com.vci.starter.web.util.Lcm.Func;
import com.vci.starter.web.wrapper.VciQueryWrapperForDO;
import com.vci.web.enumpck.DeleteTypeEnum;
import com.vci.web.enumpck.UIFieldTypeEnum;
import com.vci.web.enumpck.UITreeLoadTypeEnum;
import com.vci.web.query.UIDataGridQuery;
import com.vci.web.query.UIFormQuery;
import com.vci.web.query.UILinkTypeDataQuery;
import com.vci.web.query.UITreeQuery;
import com.vci.web.service.*;
import com.vci.web.util.PlatformClientUtil;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -140,7 +149,7 @@
        VciBaseUtil.alertNotNull(dataGridQuery,"查询对象",dataGridQuery.getBtmname(),"业务类型",dataGridQuery.getTableDefineId());
        //先判断查询模板
        UITableDefineVO tableDefineVO = uiEngineService.getComponentByOid(dataGridQuery.getComponentOid(),null).getTableDefineVO();
        String queryTemplate = !CollectionUtils.isEmpty(dataGridQuery.getSourceData())?dataGridQuery.getSourceData().getOrDefault("querytemplate",tableDefineVO.getQueryTemplateName()):tableDefineVO.getQueryTemplateName();
        String queryTemplate = !CollectionUtils.isEmpty(dataGridQuery.getSourceData())? (String) dataGridQuery.getSourceData().getOrDefault("querytemplate",tableDefineVO.getQueryTemplateName()) :tableDefineVO.getQueryTemplateName();
        if(StringUtils.isBlank(queryTemplate)){
            //说明没有设置查询模板,需要看看在这个表格所在的组件有没有设置
            tableDefineVO = uiEngineService.getTableById(dataGridQuery.getBtmname(), dataGridQuery.getTableDefineId());
@@ -185,7 +194,7 @@
        queryFieldList.add("creator_name");
        queryFieldList.add("lastmodifier_name");
        //我们在后台查询业务数据
        Map<String, String> replaceMap = wrapperReplaceMap(dataGridQuery.getSourceData());
        Map<String, Object> replaceMap = wrapperReplaceMap(dataGridQuery.getSourceData());
        if(dataGridQuery.isLinkTypeFlag()){
            UILinkTypeDataQuery linkTypeDataQuery = new UILinkTypeDataQuery();
@@ -218,7 +227,7 @@
    public UIFormDataVO getDataForForm(UIFormQuery formQuery) throws VciBaseException, PLException {
        VciBaseUtil.alertNotNull(formQuery,"表单的查询对象",formQuery.getBtmname(),"业务类型的信息",formQuery.getOid(),"业务数据的主键",formQuery.getFormDefineId(),"表单的定义编号");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formQuery.getBtmname(),formQuery.getFormDefineId());
        String queryTemplate = !CollectionUtils.isEmpty(formQuery.getSourceData())?formQuery.getSourceData().getOrDefault("querytemplate",formDefineVO.getQueryTemplateName()):formDefineVO.getQueryTemplateName();
        String queryTemplate = !CollectionUtils.isEmpty(formQuery.getSourceData())? (String) formQuery.getSourceData().getOrDefault("querytemplate",formDefineVO.getQueryTemplateName()) :formDefineVO.getQueryTemplateName();
        Set<String> queryFieldList = formDefineVO.getItems().stream().filter(s->!UIFieldTypeEnum.CUSTOM.getValue().equalsIgnoreCase(s.getType())).map(UIFormItemVO::getField).collect(Collectors.toSet());
        //获取参照
        List<UIFormItemVO> referFieldList = formDefineVO.getItems().stream().filter(s -> UIFieldTypeEnum.REFER.getValue().equalsIgnoreCase(s.getType())).collect(Collectors.toList());
@@ -251,7 +260,7 @@
        queryFieldList.add("creator_name");
        queryFieldList.add("lastmodifier_name");
        Map<String,String> conditionMap = WebUtil.getOidQuery(formQuery.getOid());
        Map<String, String> replaceMap = wrapperReplaceMap(formQuery.getSourceData());
        Map<String, Object> replaceMap = wrapperReplaceMap(formQuery.getSourceData());
        UIFormDataVO formDataVO = new UIFormDataVO();
        replaceMap.put("oid", formQuery.getOid().trim());
        if(!formDefineVO.isLinkTypeFlag()) {
@@ -321,13 +330,14 @@
     * @param sourceDataMap 来源数据
     * @return 替换后的值
     */
    private Map<String,String> wrapperReplaceMap(Map<String,String> sourceDataMap){
        Map<String,String> replaceMap =!CollectionUtils.isEmpty(sourceDataMap)? sourceDataMap:new HashMap<>();
    private Map<String,Object> wrapperReplaceMap(Map<String,Object> sourceDataMap){
        Map<String,Object> replaceMap =!CollectionUtils.isEmpty(sourceDataMap)? sourceDataMap:new HashMap<>();
        if(!replaceMap.containsKey("f_oid")){
            replaceMap.put("f_oid",replaceMap.getOrDefault("oid",""));
        }
        if(replaceMap.get("f_oid").contains(TREE_NODE_ID_SEP)){
            replaceMap.put("f_oid",replaceMap.get("f_oid").split(TREE_NODE_ID_SEP)[1]);
        String fOid = replaceMap.get("f_oid").toString();
        if(fOid.contains(TREE_NODE_ID_SEP)){
            replaceMap.put("f_oid",fOid.split(TREE_NODE_ID_SEP)[1]);
        }
        return replaceMap;
    }
@@ -345,7 +355,7 @@
     * @throws VciBaseException 查询出错的时候会抛出异常
     */
    @Override
    public List<Tree> getDataForTree(UITreeQuery treeQuery) throws VciBaseException, PLException {
    public List<UIDataTree> getDataForTree(UITreeQuery treeQuery) throws Exception {
        VciBaseUtil.alertNotNull(treeQuery,"表单的查询对象",treeQuery.getBtmname(),"业务类型的信息",treeQuery.getComponentOid(),"树所在的组件的主键");
        Map<String, OsAttributeVO> attributeVOMap = attrService.selectAllAttributeMap();
        UIComponentVO componentVO = uiEngineService.getComponentByOid(treeQuery.getComponentOid(),attributeVOMap);
@@ -360,7 +370,14 @@
        if(!treeQuery.isLinkTypeFlag() && StringUtils.isBlank(treeQuery.getParentBtmName())){
            treeQuery.setParentBtmName(treeQuery.getBtmname());
        }
        //TODO: 替换树定义上的正反向查询属性,因为正反向查询是由链接类型查询模板上控制的
        boolean isOrientation = false; //是否反向,使用模板上配置的
        String qtName = treeDefineVO.getQueryTemplateName();
        if(Func.isNotBlank(treeDefineVO.getLinkType()) && Func.isNotBlank(qtName)){
            QTInfo wrapper = platformClientUtil.getQTDService().getQT(qtName);
            QueryTemplate qt = OQTool.getQTByDoc(DocumentHelper.parseText(wrapper.qtText), qtName);
            isOrientation = qt.getDirection().equals("opposite");
        }
        if(treeQuery.getConditionMap() == null){
            treeQuery.setConditionMap(new HashMap<>());
        }
@@ -371,7 +388,6 @@
        if(parentFieldName.contains(",")){
            parentFieldName = parentFieldName.split(",")[0];
        }
        //TODO: 这儿为啥要将根节点显示表达式放到查询条件中去,这样就会导致这个节点被当成查询条件去查询
        if(StringUtils.isNotBlank(parentFieldName)){
            if(StringUtils.isNotBlank(treeQuery.getParentOid())){
                treeQuery.getConditionMap().put(parentFieldName,treeQuery.getParentOid());
@@ -380,15 +396,15 @@
        if(StringUtils.isNotBlank(treeQuery.getParentOid()) && treeQuery.getParentOid().contains(TREE_NODE_ID_SEP)){
            treeQuery.setParentOid(treeQuery.getParentOid().split(TREE_NODE_ID_SEP)[1]);
        }
        String queryTemplate = StringUtils.isNotBlank(treeQuery.getQueryTemplate())?treeQuery.getQueryTemplate():(!CollectionUtils.isEmpty(treeQuery.getSourceData())?treeQuery.getSourceData().getOrDefault("querytemplate",treeDefineVO.getQueryTemplateName()):treeDefineVO.getQueryTemplateName());
        String valueField = treeQuery.isLinkTypeFlag()?(!treeDefineVO.isOrientation()?"${oid}" + TREE_NODE_ID_SEP + "${t_oid}":"${oid}" + TREE_NODE_ID_SEP + "${f_oid}"):(StringUtils.isNotBlank(treeQuery.getValueField())?treeQuery.getValueField():"oid");
        String queryTemplate = StringUtils.isNotBlank(treeQuery.getQueryTemplate())?treeQuery.getQueryTemplate():(!CollectionUtils.isEmpty(treeQuery.getSourceData())? (String) treeQuery.getSourceData().getOrDefault("querytemplate",treeDefineVO.getQueryTemplateName()) :treeDefineVO.getQueryTemplateName());
        String valueField = treeQuery.isLinkTypeFlag()?(!isOrientation?"${oid}" + TREE_NODE_ID_SEP + "${t_oid}":"${oid}" + TREE_NODE_ID_SEP + "${f_oid}"):(StringUtils.isNotBlank(treeQuery.getValueField())?treeQuery.getValueField():"oid");
        String textField = StringUtils.isNotBlank(treeDefineVO.getTreeNodeExpression())?treeDefineVO.getTreeNodeExpression():(StringUtils.isNotBlank(treeQuery.getTextField())?treeQuery.getTextField():"name");
        List<Tree> rootTreeList = new ArrayList<>();
        List<UIDataTree> rootTreeList = new ArrayList<>();
        List<String> queryFieldList = new ArrayList<>();
        queryFieldList.add("creator_name");
        queryFieldList.add("lastmodifier_name");
        String rootExpress = StringUtils.isNotBlank(treeQuery.getRootExpress())?treeQuery.getRootExpress():treeDefineVO.getRootContent();
        Map<String, String> replaceMap = wrapperReplaceMap(treeQuery.getSourceData());
        Map<String, Object> replaceMap = wrapperReplaceMap(treeQuery.getSourceData());
        if(StringUtils.isBlank(treeDefineVO.getLinkType())){
            //这个是业务类型的自参照
            //以前的平台没有对自参照这种有全部查询的
@@ -446,8 +462,10 @@
                return cbo2Trees(thisChildren, valueField, textField, parentFieldName, treeQuery.isShowCheckBox(), null);
            }
        }else{
            OsLinkTypeVO linkTypeVO = linkTypeService.getLinkTypeById(treeDefineVO.getLinkType());
            queryFieldList.addAll(linkTypeVO.getAttributes().stream().map(OsLinkTypeAttributeVO::getId).collect(Collectors.toList()));
            //OsLinkTypeVO linkTypeVO = linkTypeService.getLinkTypeById(treeDefineVO.getLinkType());
            LinkType linkType = platformClientUtil.getLinkTypeService().getLinkType(treeDefineVO.getLinkType());
            //queryFieldList.addAll(linkTypeVO.getAttributes().stream().map(OsLinkTypeAttributeVO::getId).collect(Collectors.toList()));
            queryFieldList.addAll(Arrays.asList(linkType.attributes));
            queryFieldList.addAll(WebLoServiceImpl.LO_BASE_FIELD_MAP.values());
            addQueryField(queryFieldList,valueField);
@@ -458,7 +476,7 @@
            linkTypeDataQuery.setConditionMap(treeQuery.getConditionMap());
            linkTypeDataQuery.setParentOid(treeQuery.getParentOid());
            linkTypeDataQuery.setClauseList(queryFieldList);
            linkTypeDataQuery.setDirection(treeDefineVO.isOrientation());
            linkTypeDataQuery.setDirection(isOrientation);
            linkTypeDataQuery.setToBtmType(treeDefineVO.getBtmType());
            linkTypeDataQuery.setLinkType(treeDefineVO.getLinkType());
            if(UITreeLoadTypeEnum.ALL.getValue().equalsIgnoreCase(treeDefineVO.getLoadType())){
@@ -466,7 +484,7 @@
            }
            if(treeQuery.isQueryRoot()){
                //查询根节点.我们需要判断是否设置了根节点的查询条件
                List<com.vci.corba.query.data.BOAndLO> rootCbos = null;
                List<BOAndLO> rootCbos = null;
                String parentFieldNameAndValue = treeDefineVO.getShowLinkAbs();
                if(StringUtils.isNotBlank(parentFieldNameAndValue)){
                    if(StringUtils.isNotBlank(queryTemplate)){
@@ -488,7 +506,7 @@
                    }
                    if(!CollectionUtils.isEmpty(rootCbos)){
                        if(StringUtils.isBlank(parentFieldName)){
                            if(treeDefineVO.isOrientation()){
                            if(isOrientation){
                                parentFieldName = "t_oid";
                            }else{
                                parentFieldName = "f_oid";
@@ -508,15 +526,15 @@
                    if(CollectionUtils.isEmpty(replaceMap)){
                        throw new VciBaseException("根节点没有配置查询条件,也没有来源数据");
                    }
                    Tree root = new Tree();
                    root.setOid(replaceMap.getOrDefault("oid",replaceMap.getOrDefault("t_oid","")));
                    UIDataTree root = new UIDataTree();
                    root.setOid((String) replaceMap.getOrDefault("oid",replaceMap.getOrDefault("t_oid","")));
                    root.setText(getValueByExpressForBOAndLO(new HashMap<>(),replaceMap,rootExpress));
                    root.setAttributes(replaceMap);
                    root.setIndex("0");
                    rootTreeList.add(root);
                    if(StringUtils.isBlank(parentFieldName)){
                        if(treeDefineVO.isOrientation()){
                        if(isOrientation){
                            parentFieldName = "t_oid";
                        }else{
                            parentFieldName = "f_oid";
@@ -536,7 +554,7 @@
                    if(linkTypeDataQuery.getReplaceMap() == null){
                        linkTypeDataQuery.setReplaceMap(new HashMap<>());
                    }
                    linkTypeDataQuery.getReplaceMap().put(treeDefineVO.isOrientation()?"t_oid":"f_oid",treeQuery.getParentOid());
                    linkTypeDataQuery.getReplaceMap().put(isOrientation?"t_oid":"f_oid",treeQuery.getParentOid());
                }
                return cloAndCbo2Trees(loService.queryCLOAndBoByLinkType(linkTypeDataQuery),valueField,textField,parentFieldName,treeQuery.isShowCheckBox(),treeQuery.getParentOid());
            }
@@ -550,7 +568,7 @@
     * @throws VciBaseException 查询出错的时候会抛出异常
     */
    @Override
    public BaseResult getDataByTemp(UITreeQuery treeQuery) throws VciBaseException, PLException {
    public BaseResult getDataByTemp(UITreeQuery treeQuery) throws Exception {
        VciBaseUtil.alertNotNull(treeQuery,"表单的查询对象",treeQuery.getComponentOid(),"当前组件的主键");
        //1、先查询页面定义组件
        Map<String, OsAttributeVO> attributeVOMap = attrService.selectAllAttributeMap();
@@ -560,12 +578,19 @@
        }
        // 2、根据配置的查询模板查询数据(需要考虑全面一点),
        // 这儿根据当前类型来获取是什么类型的查询模板,然后做对应的查询处理
        //TODO: 替换树定义上的正反向查询属性,因为正反向查询是由链接类型查询模板上控制的
        UITreeDefineVO treeDefineVO = componentVO.getTreeDefineVO();
        String queryTemplate = StringUtils.isNotBlank(treeQuery.getQueryTemplate())?treeQuery.getQueryTemplate():(!CollectionUtils.isEmpty(treeQuery.getSourceData())?treeQuery.getSourceData().getOrDefault("querytemplate",treeDefineVO.getQueryTemplateName()):treeDefineVO.getQueryTemplateName());
        Map<String, String> replaceMap = wrapperReplaceMap(treeQuery.getSourceData());
        boolean isOrientation = false; //是否反向,使用模板上配置的
        String qtName = treeDefineVO.getQueryTemplateName();
        if(Func.isNotBlank(treeDefineVO.getLinkType()) && Func.isNotBlank(qtName)){
            QTInfo wrapper = platformClientUtil.getQTDService().getQT(qtName);
            QueryTemplate qt = OQTool.getQTByDoc(DocumentHelper.parseText(wrapper.qtText), qtName);
            isOrientation = qt.getDirection().equals("opposite");
        }
        String queryTemplate = StringUtils.isNotBlank(treeQuery.getQueryTemplate())?treeQuery.getQueryTemplate():(!CollectionUtils.isEmpty(treeQuery.getSourceData())? (String) treeQuery.getSourceData().getOrDefault("querytemplate",treeDefineVO.getQueryTemplateName()) :treeDefineVO.getQueryTemplateName());
        Map<String, Object> replaceMap = wrapperReplaceMap(treeQuery.getSourceData());
        List<String> queryFieldList = new ArrayList<>();
        String valueField = treeQuery.isLinkTypeFlag()?(!treeDefineVO.isOrientation()?"${oid}" + TREE_NODE_ID_SEP + "${t_oid}":"${oid}" + TREE_NODE_ID_SEP + "${f_oid}"):(StringUtils.isNotBlank(treeQuery.getValueField())?treeQuery.getValueField():"oid");
        String valueField = treeQuery.isLinkTypeFlag()?(!isOrientation?"${oid}" + TREE_NODE_ID_SEP + "${t_oid}":"${oid}" + TREE_NODE_ID_SEP + "${f_oid}"):(StringUtils.isNotBlank(treeQuery.getValueField())?treeQuery.getValueField():"oid");
        String textField = StringUtils.isNotBlank(treeDefineVO.getTreeNodeExpression())?treeDefineVO.getTreeNodeExpression():(StringUtils.isNotBlank(treeQuery.getTextField())?treeQuery.getTextField():"name");
        String rootExpress = StringUtils.isNotBlank(treeQuery.getRootExpress())?treeQuery.getRootExpress():treeDefineVO.getRootContent();
        String parentFieldName = treeQuery.getParentFieldName();
@@ -583,7 +608,7 @@
        List<BusinessObject> rootCbos = boService.queryCBOByScheme(queryTemplate, null, replaceMap);
        //3、根据不同的组件返回不同的数据类型(树、列表、树表、自定义模板、表单等)
        List<Tree> rootTreeList = null;
        List<UIDataTree> rootTreeList = null;
        if(!CollectionUtils.isEmpty(rootCbos)){
            rootTreeList = cbo2Trees(rootCbos,valueField,StringUtils.isBlank(rootExpress)?textField:rootExpress,parentFieldName,treeQuery.isShowCheckBox(),null);
            TreeQueryObject treeQueryObject = new TreeQueryObject();
@@ -606,19 +631,19 @@
     * @param queryFieldList 查询的字段
     * @param treeQueryObject 树形查询对象,需要valueField和textField,还有parentFieldName,和checkBox
     */
    private void queryTreeForBO(List<Tree> rootTreeList, String queryTemplate,List<String> queryFieldList,TreeQueryObject treeQueryObject) {
        for (Tree rootTree : rootTreeList) {
    private void queryTreeForBO(List<UIDataTree> rootTreeList, String queryTemplate,List<String> queryFieldList,TreeQueryObject treeQueryObject) {
        for (UIDataTree rootTree : rootTreeList) {
            List<BusinessObject> thisChildren = null;
            Map<String,String> sourceDataMap = rootTree.getAttributes();
            Map<String,Object> sourceDataMap = rootTree.getAttributes();
            sourceDataMap.put("f_oid",rootTree.getOid());
            Map<String,String> conditionMap = new HashMap<>();
            conditionMap.put(treeQueryObject.getParentFieldName(),rootTree.getOid());
            if (StringUtils.isNotBlank(queryTemplate)) {
                thisChildren = boService.queryCBOByScheme(queryTemplate, conditionMap, sourceDataMap, null, queryFieldList);
            } else {
                thisChildren = boService.queryCBO(sourceDataMap.getOrDefault("btmname",sourceDataMap.getOrDefault("btmName",treeQueryObject.getParentBtmName())), conditionMap, null, queryFieldList);
                thisChildren = boService.queryCBO((String) sourceDataMap.getOrDefault("btmname",sourceDataMap.getOrDefault("btmName",treeQueryObject.getParentBtmName())), conditionMap, null, queryFieldList);
            }
            List<Tree> childrenTree = cbo2Trees(thisChildren, treeQueryObject.getValueField(), treeQueryObject.getTextField(), treeQueryObject.getParentFieldName(), treeQueryObject.isShowCheckBox(), null);
            List<UIDataTree> childrenTree = cbo2Trees(thisChildren, treeQueryObject.getValueField(), treeQueryObject.getTextField(), treeQueryObject.getParentFieldName(), treeQueryObject.isShowCheckBox(), null);
            rootTree.setChildren(childrenTree);
            if(treeQueryObject.isQueryAllLevel() && !CollectionUtils.isEmpty(childrenTree) ) {
                queryTreeForBO(childrenTree,queryTemplate,queryFieldList,treeQueryObject);
@@ -635,8 +660,8 @@
     * @param textField 显示表达式
     * @param showCheckBox 是否显示复选框
     */
    private void queryTreeForLO(List<Tree> rootTreeList, UILinkTypeDataQuery linkTypeDataQuery,String parentFieldName,String valueField,String textField,boolean showCheckBox) {
        for (Tree rootTree : rootTreeList) {
    private void queryTreeForLO(List<UIDataTree> rootTreeList, UILinkTypeDataQuery linkTypeDataQuery,String parentFieldName,String valueField,String textField,boolean showCheckBox) {
        for (UIDataTree rootTree : rootTreeList) {
            Map<String,String> conditionMap = new HashMap<>();
            conditionMap.put(linkTypeDataQuery.isDirection()?"t_oid":"f_oid",rootTree.getOid());
            linkTypeDataQuery.setConditionMap(conditionMap);
@@ -655,18 +680,21 @@
     * @param parentOid 上级的主键
     * @return 树
     */
    private List<Tree> cbo2Trees(Collection<BusinessObject> cbos,String valueField,String textField,String parentFieldName,boolean showCheckBox,String parentOid){
    private List<UIDataTree> cbo2Trees(Collection<BusinessObject> cbos,String valueField,String textField,String parentFieldName,boolean showCheckBox,String parentOid){
        final int[] i = {0};
        List<Tree> rootList = new ArrayList<>();
        List<Tree> children = new ArrayList<>();
        List<UIDataTree> rootList = new ArrayList<>();
        List<UIDataTree> children = new ArrayList<>();
        cbos.stream().forEach(cbo->{
            Tree tree = new Tree();
            UIDataTree tree = new UIDataTree();
            tree.setOid(getValueByExpress(cbo,valueField));
            tree.setText(getValueByExpress(cbo,textField));
            if(StringUtils.isNotBlank(parentFieldName)){
                tree.setParentId(ObjectTool.getBOAttributeValue(cbo,parentFieldName));
            }
            tree.setAttributes(boService.cbo2Map(cbo));
            Map<String,Object> cbo2Map = boService.cbo2Map(cbo);
            Map<String, Object> returnMap = new HashMap<>();
            returnMap.put((String) cbo2Map.get("btmname"),cbo2Map);
            tree.setAttributes(returnMap);
            tree.setIndex(i[0] + "");
            i[0]++;
            tree.setChecked(showCheckBox);
@@ -680,7 +708,7 @@
        if(rootList.size() == 0 && children.size() == 0){
            return rootList;
        }
        return Tree.getChildList(rootList,children);
        return UIDataTree.getChildList(rootList,children);
    }
    /**
@@ -693,24 +721,25 @@
     * @param parentOid 上级的值
     * @return 树形数据
     */
    public List<Tree> cloAndCbo2Trees(Collection<com.vci.corba.query.data.BOAndLO> boAndLOS,String valueField,String textField,String parentFieldName,boolean showCheckBox,String parentOid){
    public List<UIDataTree> cloAndCbo2Trees(Collection<BOAndLO> boAndLOS, String valueField, String textField, String parentFieldName, boolean showCheckBox, String parentOid){
        final int[] i = {0};
        List<Tree> rootList = new ArrayList<>();
        List<Tree> children = new ArrayList<>();
        List<UIDataTree> rootList = new ArrayList<>();
        List<UIDataTree> children = new ArrayList<>();
        boAndLOS.stream().forEach(boAndLO->{
            Tree tree = new Tree();
            UIDataTree tree = new UIDataTree();
            BusinessObject cbo = new BusinessObject();
            cbo = boAndLO.bo;
            LinkObject clo = new LinkObject();
            clo = boAndLO.lo;
            Map<String,String> cloMap = loService.clo2Map(clo);
            Map<String,String> cbo2Map = boService.cbo2Map(cbo);
            if(!CollectionUtils.isEmpty(cbo2Map)){
            Map<String,Object> cloMap = loService.clo2Map(clo);
            Map<String,Object> cbo2Map = boService.cbo2Map(cbo);
            /*if(!CollectionUtils.isEmpty(cbo2Map)){
                cbo2Map.forEach((key,value)->{
                    //TODO: 这儿为啥要拼接上parentFieldName,导致后面freemarker表达式无法正确替换
                    cloMap.put(/*parentFieldName + "." +*/ key,value);
                    cloMap.put(/*parentFieldName + "." + key,value);
                });
            }
            }*/
            tree.setOid(getValueByExpressForBOAndLO(cloMap,cbo2Map,valueField));
            tree.setText(getValueByExpressForBOAndLO(cloMap,cbo2Map,textField));
            if(StringUtils.isBlank(parentFieldName)){
@@ -722,8 +751,11 @@
                    tree.setParentId(ObjectTool.getLOAttributeValue(clo,parentFieldName));
                }
            }
            tree.setAttributes(cbo2Map);
            //TODO:返回的数据改成按链接类型和业务类型为key:值为对应的属性集合形式返回
            Map<String, Object> returnMap = new HashMap<>();
            returnMap.put((String) cloMap.get("linktypename"),cloMap);
            returnMap.put((String) cbo2Map.get("btmname"),cbo2Map);
            tree.setAttributes(returnMap);
            tree.setIndex(i[0] + "");
            i[0]++;
            tree.setChecked(showCheckBox);
@@ -735,7 +767,7 @@
            }
        });
        return Tree.getChildList(rootList,children);
        return UIDataTree.getChildList(rootList,children);
    }
    /**
@@ -767,17 +799,30 @@
     * @param fieldExpress 表达式
     * @return 替换后的值
     */
    private String getValueByExpressForBOAndLO(Map<String,String> valueMap,Map<String,String> boValueMap,String fieldExpress){
    private String getValueByExpressForBOAndLO(Map<String,Object> valueMap,Map<String,Object> boValueMap,String fieldExpress){
        if(fieldExpress.contains("${")){
            //使用freemarker处理
            return VciBaseUtil.replaceByFreeMarker(fieldExpress,valueMap);
            /*
            TODO:表达式存在T_OID.name这种形式时freemarker替换规则是从T_OID这个对象中招name属性,
                但是valueMap是一个String,String的Map所以需要将T_OID.或F_OID.去掉,因为不管是查询的
                form端还是to端都是平台查好放在业务属性boValueMap集合中的,所以直接替就可以
            */
            if(fieldExpress.contains(".")){
                //去除t_oid、T_OID以及f_oid、F_OID
                fieldExpress = fieldExpress
                        .replace("t_oid.","")
                        .replace("T_OID.","")
                        .replace("f_oid.","")
                        .replace("F_OID.","");
            }
            return VciBaseUtil.replaceByFreeMarker(fieldExpress,boValueMap);
        }else {
            List<String> fieldList = VciBaseUtil.str2List(fieldExpress);
            Map<String,String> valueLowMap = new HashMap<>();
            Map<String,Object> valueLowMap = new HashMap<>();
            valueMap.forEach((key,value)->{
                valueLowMap.put(key.toLowerCase(),value);
            });
            Map<String,String> boLowValueMap = new HashMap<>();
            Map<String,Object> boLowValueMap = new HashMap<>();
            if(!CollectionUtils.isEmpty(boValueMap)){
                boValueMap.forEach((key,value)->{
                    boLowValueMap.put(key.toLowerCase(),value);
@@ -785,7 +830,7 @@
            }
            StringBuilder sb = new StringBuilder();
            fieldList.stream().forEach(field->{
                sb.append(valueLowMap.getOrDefault(field,boLowValueMap.getOrDefault(field,""))).append(" ");
                sb.append(boLowValueMap.getOrDefault(field,valueLowMap.getOrDefault(field,""))).append(" ");
            });
            return sb.toString().trim();
        }
@@ -833,7 +878,7 @@
        if((baseModelDTOList == null || CollectionUtils.isEmpty(baseModelDTOList.getDataList())) && (baseLinkModelDTOList == null || CollectionUtils.isEmpty(baseLinkModelDTOList.getDataList()))){
            return BaseResult.success();
        }
        String btmType = (baseModelDTOList !=null && !CollectionUtils.isEmpty(baseModelDTOList.getDataList()))? baseModelDTOList.getDataList().get(0).getBtmname():null;
        String btmType = (baseModelDTOList !=null && !CollectionUtils.isEmpty(baseModelDTOList.getDataList()))? baseModelDTOList.getDataList().get(0).getBtmName():null;
        String linkType = (baseLinkModelDTOList !=null && !CollectionUtils.isEmpty(baseLinkModelDTOList.getDataList()))?baseLinkModelDTOList.getDataList().get(0).getLinkType():null;
        if(StringUtils.isNotBlank(preEvent)){
            //前置事件
@@ -1043,7 +1088,7 @@
    public BaseModelDTOList formData2DTOList(FormDataDTO formDataDTO){
        BaseModelDTOList modelDTOList = new BaseModelDTOList();
        BaseModelDTO modelDTO = new BaseModelDTO();
        BeanUtil.convert((BaseModelDTO)formDataDTO,modelDTO);
        BeanUtilForVCI.convert(formDataDTO,modelDTO);
        modelDTO.setData(formDataDTO.getData());
        List<BaseModelDTO> modelDTOS = new ArrayList<>();
        modelDTOS.add(modelDTO);
@@ -1061,7 +1106,7 @@
        BaseLinkModelDTOList modelDTOList = new BaseLinkModelDTOList();
        BaseLinkModelDTO modelDTO = new BaseLinkModelDTO();
        modelDTO.setData(formLinkDataDTO.getData());
        BeanUtil.convert((BaseLinkModelDTO)formLinkDataDTO,modelDTO);
        BeanUtilForVCI.convert(formLinkDataDTO,modelDTO);
        List<BaseLinkModelDTO> linkModelDTOS = new ArrayList<>();
        linkModelDTOS.add(modelDTO);
        modelDTOList.setDataList(linkModelDTOS);
@@ -1080,7 +1125,7 @@
        modelDTOS.stream().findAny().orElseGet(()->null);
        formDataDTOList.getFormDataDTOS().forEach(formDataDTO -> {
            BaseModelDTO modelDTO = new BaseModelDTO();
            BeanUtil.convert((BaseModelDTO)formDataDTO,modelDTO);
            BeanUtilForVCI.convert((BaseModelDTO)formDataDTO,modelDTO);
            modelDTO.setData(formDataDTO.getData());
            modelDTOS.add(modelDTO);
        });
@@ -1099,7 +1144,7 @@
        List<BaseLinkModelDTO> modelDTOS = new ArrayList<>();
        formLinkDataDTOList.getDataDTOList().forEach(formDataDTO -> {
            BaseLinkModelDTO modelDTO = new BaseLinkModelDTO();
            BeanUtil.convert((BaseLinkModelDTO)formDataDTO,modelDTO);
            BeanUtilForVCI.convert((BaseLinkModelDTO)formDataDTO,modelDTO);
            modelDTO.setData(formDataDTO.getData());
            modelDTOS.add(modelDTO);
        });
@@ -1117,8 +1162,8 @@
    @Override
    public BaseResult<Map<String, Object>> addSave(FormDataDTO formDataDTO) throws VciBaseException, PLException {
        //首先判断对象是否为空
        VciBaseUtil.alertNotNull(formDataDTO,"添加的数据对象",formDataDTO.getBtmname(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmname(), formDataDTO.getFormDefineId());
        VciBaseUtil.alertNotNull(formDataDTO,"添加的数据对象",formDataDTO.getBtmName(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmName(), formDataDTO.getFormDefineId());
        String preEvent = formDataDTO.getPreEvent();
        BaseModelDTOList modelDTOList = formData2DTOList(formDataDTO);
        BaseResult beforeResult = callPreEvent(modelDTOList, null,preEvent, VciChangeDocumentTypeEnum.ADD);
@@ -1227,7 +1272,7 @@
        baseModel.setOid(cbo.oid);
        baseModel.setNameOid(cbo.nameoid);
        baseModel.setRevisionOid(cbo.revisionid);
        baseModel.setBtmname(cbo.btName);
        baseModel.setBtmName(cbo.btName);
        baseModel.setLastR(String.valueOf(cbo.isLastR));
        baseModel.setLastV(String.valueOf(cbo.isLastV));
        baseModel.setFirstR(String.valueOf(cbo.isFirstR));
@@ -1384,7 +1429,7 @@
        VciBaseUtil.alertNotNull(formDataDTOList,"要添加的数据",formDataDTOList.getFormDataDTOS(),"要添加的数据");
        //首先判断对象是否为空
        FormDataDTO firstFormDataDTO = formDataDTOList.getFormDataDTOS().stream().findFirst().get();
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(firstFormDataDTO.getBtmname(), firstFormDataDTO.getId());
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(firstFormDataDTO.getBtmName(), firstFormDataDTO.getId());
        String preEvent = firstFormDataDTO.getPreEvent();
        BaseModelDTOList modelDTOList = formDataList2DTOList(formDataDTOList);
        BaseResult beforeResult = callPreEvent(modelDTOList, null, preEvent, VciChangeDocumentTypeEnum.ADD);
@@ -1421,7 +1466,7 @@
        }
        if(!CollectionUtils.isEmpty(releasedFileOids)){
            releasedFileOids.forEach((oid,fileOids)->{
                fileObjectService.releasedFile(firstFormDataDTO.getBtmname(),oid,fileOids);
                fileObjectService.releasedFile(firstFormDataDTO.getBtmName(),oid,fileOids);
            });
        }
        //后置事件
@@ -1452,8 +1497,8 @@
    @Override
    public BaseResult<Map<String, Object>> editSave(FormDataDTO formDataDTO) throws VciBaseException, PLException {
        //首先判断对象是否为空
        VciBaseUtil.alertNotNull(formDataDTO,"修改的数据对象",formDataDTO.getBtmname(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmname(), formDataDTO.getFormDefineId());
        VciBaseUtil.alertNotNull(formDataDTO,"修改的数据对象",formDataDTO.getBtmName(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmName(), formDataDTO.getFormDefineId());
        String preEvent = formDataDTO.getPreEvent();
        BaseModelDTOList modelDTOList = formData2DTOList(formDataDTO);
        BaseResult beforeResult = callPreEvent(modelDTOList,null, preEvent, VciChangeDocumentTypeEnum.EDIT);
@@ -1497,8 +1542,8 @@
    @Override
    public BaseResult<Map<String, Object>> upRevision(FormDataDTO formDataDTO) throws VciBaseException, PLException {
        //首先判断对象是否为空
        VciBaseUtil.alertNotNull(formDataDTO,"修改的数据对象",formDataDTO.getBtmname(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号",formDataDTO.getCopyFromVersion(),"老版本的主键");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmname(), formDataDTO.getFormDefineId());
        VciBaseUtil.alertNotNull(formDataDTO,"修改的数据对象",formDataDTO.getBtmName(),"业务类型的名称",formDataDTO.getFormDefineId(),"表单定义的编号",formDataDTO.getCopyFromVersion(),"老版本的主键");
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(formDataDTO.getBtmName(), formDataDTO.getFormDefineId());
        String preEvent = formDataDTO.getPreEvent();
        BaseModelDTOList modelDTOList = formData2DTOList(formDataDTO);
        BaseResult beforeResult = callPreEvent(modelDTOList, null,preEvent, VciChangeDocumentTypeEnum.UPREVISION);
@@ -1511,7 +1556,7 @@
        Map<String,String> conditionMap = WebUtil.getOidQuery(formDataDTO.getCopyFromVersion());
        conditionMap.put("ts", VciDateUtil.date2Str(ts,VciDateUtil.DateTimeMillFormat));
        conditionMap.put("oid",formDataDTO.getCopyFromVersion());
        businessObjects = boService.queryCBO(formDataDTO.getBtmname(), conditionMap);
        businessObjects = boService.queryCBO(formDataDTO.getBtmName(), conditionMap);
        if(businessObjects.size() ==0){
            throw new VciBaseException("数据不是最新的,建议您刷新后重新操作");
        }
@@ -1558,7 +1603,7 @@
        VciBaseUtil.alertNotNull(formDataDTOList,"要修改的数据",formDataDTOList.getFormDataDTOS(),"要修改的数据");
        //首先判断对象是否为空
        FormDataDTO firstFormDataDTO = formDataDTOList.getFormDataDTOS().stream().findFirst().get();
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(firstFormDataDTO.getBtmname(), firstFormDataDTO.getId());
        UIFormDefineVO formDefineVO = uiEngineService.getFormById(firstFormDataDTO.getBtmName(), firstFormDataDTO.getId());
        String preEvent = firstFormDataDTO.getPreEvent();
        BaseModelDTOList modelDTOList = formDataList2DTOList(formDataDTOList);
        BaseResult beforeResult = callPreEvent(modelDTOList,null, preEvent, VciChangeDocumentTypeEnum.EDIT);
@@ -1588,7 +1633,7 @@
        }
        if(!CollectionUtils.isEmpty(releasedFileOids)){
            releasedFileOids.forEach((oid,fileOids)->{
                fileObjectService.releasedFile(firstFormDataDTO.getBtmname(),oid,fileOids);
                fileObjectService.releasedFile(firstFormDataDTO.getBtmName(),oid,fileOids);
            });
        }
        //后置事件
@@ -1613,7 +1658,7 @@
    @Override
    public BaseResult batchDelete(DeleteDataDTO deleteDataDTO) throws VciBaseException, PLException {
        VciBaseUtil.alertNotNull(deleteDataDTO,"数据传输对象",deleteDataDTO.getDataList(),"数据传输对象");
        String btmName = deleteDataDTO.getDataList().get(0).getBtmname();
        String btmName = deleteDataDTO.getDataList().get(0).getBtmName();
        List<String> oidList = deleteDataDTO.getDataList().stream().map(BaseModelDTO::getOid).collect(Collectors.toList());
        //看看级联删除。只有自己引用自己的时候可以级联删除
        List<BusinessObject> cbo = null;