dangsn
2024-12-03 d0ae279ff3b83358d1c07f4481a041c4ad335026
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/service/impl/OsLifeCycleServiceImpl.java
@@ -1,40 +1,48 @@
package com.vci.web.service.impl;
import com.vci.client.common.providers.ServiceProvider;
import com.vci.corba.common.PLException;
import com.vci.corba.omd.data.BusinessObject;
import com.vci.corba.omd.lcm.Bound;
import com.vci.corba.omd.lcm.LifeCycle;
import com.vci.corba.omd.lcm.TransitionVO;
import com.vci.corba.omd.lcm.TransitionVOEvent;
import com.vci.dto.OsLifeCycleDTO;
import com.vci.model.OsLifeCycleDO;
import com.vci.pagemodel.*;
import com.vci.po.OsLifeCyclePO;
import com.vci.starter.poi.bo.ReadExcelOption;
import com.vci.starter.poi.bo.WriteExcelData;
import com.vci.starter.poi.bo.WriteExcelOption;
import com.vci.starter.poi.constant.ExcelLangCodeConstant;
import com.vci.starter.poi.util.ExcelUtil;
import com.vci.starter.web.annotation.log.VciUnLog;
import com.vci.starter.web.exception.VciBaseException;
import com.vci.starter.web.pagemodel.BaseQueryObject;
import com.vci.starter.web.pagemodel.BaseResult;
import com.vci.starter.web.pagemodel.DataGrid;
import com.vci.starter.web.util.VciDateUtil;
import com.vci.web.constant.CacheKeyConstant;
import com.vci.web.model.OsLifeCycleDO;
import com.vci.web.pageModel.*;
import com.vci.starter.web.util.*;
import com.vci.starter.web.util.Lcm.Func;
import com.vci.web.service.OsLifeCycleServiceI;
import com.vci.web.service.OsStatusServiceI;
import com.vci.web.service.WebBoServiceI;
import com.vci.web.util.PlatformClientUtil;
import com.vci.web.util.WebUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import static com.vci.frameworkcore.constant.FrameWorkBusLangCodeConstant.DATA_ID_NOT_EXIST;
import static com.vci.web.constant.CacheNameConstant.VCI_OBJECT_SERVICE;
import static com.vci.web.constant.WebLangCodeConstant.LIFE_CYCLE_ROUTER_NULL;
import static com.vci.web.constant.WebLangCodeConstant.LIFE_CYCLE_TRANS_ERROR;
import static com.vci.constant.FrameWorkBusLangCodeConstant.DATA_ID_NOT_EXIST;
import static com.vci.constant.WebLangCodeConstant.LIFE_CYCLE_ROUTER_NULL;
import static com.vci.constant.WebLangCodeConstant.LIFE_CYCLE_TRANS_ERROR;
/**
 * 生命周期服务
@@ -70,6 +78,11 @@
   private WebBoServiceI boService;
   /**
    *  必填列
    */
   private List<Integer> ColumnNameisRed = new ArrayList<Integer>();
   /**
    * 日志
    */
   private Logger logger = LoggerFactory.getLogger(getClass());
@@ -92,7 +105,7 @@
    * @throws VciBaseException 如果目标生命周期和当前生命周期状态没有连接线时抛出异常
    */
   @Override
   public void transStatus(com.vci.corba.omd.data.BusinessObject bo, String targetStatus)
   public void transStatus(BusinessObject bo, String targetStatus)
         throws VciBaseException {
      WebUtil.alertNotNull(bo,"业务数据对象",bo.lctId,"生命周期编码",bo.lcStatus,"当前生命周期状态",targetStatus,"目标生命周期状态");
      OsLifeCycleLineVO transVO = getTransVO(bo.lctId, bo.lcStatus, targetStatus);
@@ -113,7 +126,7 @@
    * @throws VciBaseException 转换生命周期出错的时候抛出异常
    */
   @Override
   public void transStatus(List<com.vci.corba.omd.data.BusinessObject> boList, String targetStatus)
   public void transStatus(List<BusinessObject> boList, String targetStatus)
         throws VciBaseException {
      WebUtil.alertNotNull(boList,"业务数据对象",targetStatus,"目标对象");
      transStatus(boList.toArray(new com.vci.corba.omd.data.BusinessObject[0]), targetStatus);
@@ -126,13 +139,13 @@
    * @throws VciBaseException 转换生命周期出错的时候抛出异常
    */
   @Override
   public void transStatus(com.vci.corba.omd.data.BusinessObject[] bos, String targetStatus)
   public void transStatus(BusinessObject[] bos, String targetStatus)
         throws VciBaseException {
      WebUtil.alertNotNull(bos,"业务数据对象",targetStatus,"目标对象");
      List<OsLifeCycleLineVO> transVOList = new ArrayList<>();
      List<com.vci.corba.omd.data.BusinessObject> transBOs = new ArrayList<>();
      List<BusinessObject> transBOs = new ArrayList<>();
      for(int i = 0 ; i < bos.length ; i ++){
         com.vci.corba.omd.data.BusinessObject bo = bos[i];
         BusinessObject bo = bos[i];
         WebUtil.alertNotNull(bo,"业务数据对象",bo.lctId,"生命周期编码",bo.lcStatus,"当前生命周期状态");
         OsLifeCycleLineVO transVO = getTransVO(bo.lctId, bo.lcStatus, targetStatus);
         if(transVO!=null){
@@ -145,7 +158,7 @@
         }
      }
      if(!CollectionUtils.isEmpty(transBOs)) {
         batchTransVo(transBOs.toArray(new com.vci.corba.omd.data.BusinessObject[0]), transVOList.toArray(new OsLifeCycleLineVO[0]));
         batchTransVo(transBOs.toArray(new BusinessObject[0]), transVOList.toArray(new OsLifeCycleLineVO[0]));
      }
   }
@@ -156,12 +169,12 @@
    * @throws VciBaseException 转换生命周期出错的时候抛出异常
    */
   @Override
   public void transCboStatus(List<com.vci.client.bof.ClientBusinessObject> cboList,
   public void transCboStatus(List<BusinessObject> cboList,
         String targetStatus) throws VciBaseException {
      WebUtil.alertNotNull(cboList,"业务数据对象",targetStatus,"目标对象");
      com.vci.corba.omd.data.BusinessObject[] bos = new com.vci.corba.omd.data.BusinessObject[cboList.size()];
      BusinessObject[] bos = new BusinessObject[cboList.size()];
      for(int i = 0 ; i < cboList.size() ; i ++){
         bos[i] = cboList.get(i).getBusinessObject();
         bos[i] = cboList.get(i);
      }
      transStatus(bos, targetStatus);
   }
@@ -218,8 +231,26 @@
            e.printStackTrace();
         }
         life.setOid(lifeCycle.oid);
         Bound[] bounds = lifeCycle.bounds;
         if(bounds != null && bounds.length>0){
            List<OsLifeCycleLineBoundVO> boundVOList = new ArrayList<>();
            Arrays.stream(bounds).forEach(bound->{
               OsLifeCycleLineBoundVO boundVO = new OsLifeCycleLineBoundVO();
               boundVO.setId(bound.id);
               boundVO.setName(bound.name);
               boundVO.setCellx(bound.cellx);
               boundVO.setCelly(bound.celly);
               boundVO.setCellh(bound.cellh);
               boundVO.setCellw(bound.cellw);
               boundVO.setCellicon(bound.cellicon);
               boundVOList.add(boundVO);
            });
            life.setBounds(boundVOList.toArray(new OsLifeCycleLineBoundVO[boundVOList.size()]));
         }else{
            life.setBounds(new OsLifeCycleLineBoundVO[0]);
         }
         List<OsLifeCycleLineVO> lineVOS = new ArrayList<>();
         if(lifeCycle.routes!=null&& lifeCycle.routes.length>0){
         if(lifeCycle.routes!=null && lifeCycle.routes.length>0){
            Arrays.stream(lifeCycle.routes).forEach(route->{
               OsLifeCycleLineVO lineVO = new OsLifeCycleLineVO();
               lineVO.setSourceLifeStatus(route.source);
@@ -263,16 +294,17 @@
    * @return 数据对象
    */
   @Override
   public LifeCycle lifeCycleVO2DO(OsLifeCycleVO lifeCycleVO){
   public LifeCycle lifeCycleVO2DO(OsLifeCycleVO lifeCycleVO) throws PLException {
      LifeCycle lifeCyle = new LifeCycle();
      lifeCyle.name = lifeCycleVO.getId();
      lifeCyle.tag = lifeCycleVO.getName();
      lifeCyle.oid = lifeCycleVO.getOid();
      lifeCyle.creator = lifeCycleVO.getCreator();
      String userId = WebThreadLocalUtil.getCurrentUserSessionInfoInThread().getUserId();
      lifeCyle.creator = Func.isBlank(lifeCycleVO.getCreator()) ? userId:lifeCycleVO.getCreator();
      lifeCyle.description = lifeCycleVO.getDescription();
      lifeCyle.modifier = lifeCycleVO.getLastModifier();
      lifeCyle.modifyTime = lifeCycleVO.getLastModifyTime() != null ? lifeCycleVO.getLastModifyTime().getTime():null;
      lifeCyle.createTime = lifeCycleVO.getCreateTime() != null ? lifeCycleVO.getCreateTime().getTime():null;
      lifeCyle.modifier = Func.isBlank(lifeCycleVO.getLastModifier()) ? userId:lifeCycleVO.getLastModifier();
      lifeCyle.modifyTime = System.currentTimeMillis();
      lifeCyle.createTime = lifeCycleVO.getCreateTime() != null ? lifeCycleVO.getCreateTime().getTime():System.currentTimeMillis();
      lifeCyle.startState =lifeCycleVO.getStartStatus();
      lifeCyle.ts = VciDateUtil.date2Str(lifeCycleVO.getTs(),VciDateUtil.DateTimeMillFormat);
      if(lifeCycleVO.getBounds() !=null && lifeCycleVO.getBounds().length>0) {
@@ -293,7 +325,7 @@
      }else{
         lifeCyle.bounds = new Bound[0];
      }
      //加链接线
      //加连接线
      List<TransitionVO> lines = new ArrayList<>();
      for (int i = 0; i < lifeCycleVO.getLines().size(); i++) {
         OsLifeCycleLineVO lineVO = lifeCycleVO.getLines().get(i);
@@ -313,12 +345,11 @@
   @VciUnLog
   public List<OsLifeCycleVO> selectAllLifeCycle() throws VciBaseException {
      try {
//         LifeCyle[] lifeCyles = platformClientUtil.getLifeCycleService().getLifeCyles();
         LifeCycle[] lifeCyles = ServiceProvider.getOMDService().getLifeCycleService().getLifeCycles();
         LifeCycle[] lifeCyles = platformClientUtil.getLifeCycleService().getLifeCycles();
         return lifeCycleDO2VOs(Arrays.stream(lifeCyles).collect(Collectors.toList()));
      } catch (PLException vciError) {
          if(logger.isErrorEnabled()){
//             logger.error(vciError.error_code,vciError);
             logger.error(vciError.code,vciError);
          }
          throw WebUtil.getVciBaseException(vciError);
      }
@@ -331,7 +362,6 @@
    */
   @Override
   @VciUnLog
   @Cacheable(value = VCI_OBJECT_SERVICE,key = CacheKeyConstant.ALL_LIFE_CYCLE,unless="#result == null")
   public Map<String,OsLifeCycleVO> selectAllLifeCycleMap() throws VciBaseException{
      return Optional.ofNullable(self.selectAllLifeCycle()).orElseGet(()->new ArrayList<>()).stream().collect(Collectors.toMap(s->s.getId(),t->t,(o1,o2)->o1));
   }
@@ -340,7 +370,6 @@
    * 清除缓存
    */
   @Override
   @CacheEvict(value = VCI_OBJECT_SERVICE,key = CacheKeyConstant.ALL_LIFE_CYCLE)
   public void clearCache() {
   }
@@ -367,7 +396,6 @@
      return Optional.ofNullable(life.getLines()).orElseGet(()->new ArrayList<>()).stream().filter(s->s.getSourceLifeStatus().equalsIgnoreCase(currentStatus) && s.getTargetLifeStatus().equalsIgnoreCase(targetStatus)).findFirst().orElseGet(()->null);
   }
   /**
    * 跃迁业务类型的生命周期状态
    * @param obj 业务类型数据对象
@@ -375,12 +403,11 @@
    * @throws VciBaseException 跃迁出错的是会抛出异常
    */
   @Override
   public void doTransVO(com.vci.corba.omd.data.BusinessObject obj,OsLifeCycleLineVO lineVO) throws VciBaseException {
   public void doTransVO(BusinessObject obj,OsLifeCycleLineVO lineVO) throws VciBaseException {
      if(lineVO!=null){
         try {
            com.vci.corba.omd.lcm.TransitionVO transitionVO = lifeCycleLineVO2DO(lineVO);
//            platformClientUtil.getBOFactoryService().transferBusinessObject(new BusinessObjectHolder(obj), transitionVO);
            ServiceProvider.getBOFService().transferBusinessObject(obj, transitionVO.destination);
            TransitionVO transitionVO = lifeCycleLineVO2DO(lineVO);
            platformClientUtil.getBOFService().transferBusinessObject(obj, transitionVO.destination);
         } catch (PLException e) {
            throw WebUtil.getVciBaseException(e);
         }
@@ -394,23 +421,24 @@
    * @param lineVO 连接线对象
    * @return 平台的连接线对象
    */
   private com.vci.corba.omd.lcm.TransitionVO lifeCycleLineVO2DO(OsLifeCycleLineVO lineVO){
   private TransitionVO lifeCycleLineVO2DO(OsLifeCycleLineVO lineVO) throws PLException {
      com.vci.corba.omd.lcm.TransitionVO transitionVO = new com.vci.corba.omd.lcm.TransitionVO();
      transitionVO.id = lineVO.getOid();
      transitionVO.source = lineVO.getSourceLifeStatus();
      transitionVO.destination = lineVO.getTargetLifeStatus();
      transitionVO.connect = lineVO.getName() == null?"":lineVO.getName();
         //加事件
      com.vci.corba.omd.lcm.TransitionVOEvent[] events;
      TransitionVOEvent[] events;
      if(lineVO.getEvents() == null || lineVO.getEvents().length == 0){
         events = new com.vci.corba.omd.lcm.TransitionVOEvent[0];
         events = new TransitionVOEvent[0];
      }else{
         events = new com.vci.corba.omd.lcm.TransitionVOEvent[lineVO.getEvents().length];
         events = new TransitionVOEvent[lineVO.getEvents().length];
         for (int j = 0; j < lineVO.getEvents().length; j++) {
            OsLifeCycleLineEventVO eventVO = lineVO.getEvents()[j];
            com.vci.corba.omd.lcm.TransitionVOEvent event = new com.vci.corba.omd.lcm.TransitionVOEvent();
            TransitionVOEvent event = new TransitionVOEvent();
            event.id = eventVO.getOid();
            event.name = eventVO.getEventFullName();
            event.name = Func.isBlank(eventVO.getEventFullName()) ?
                  platformClientUtil.getLifeCycleService().getLCEventValueByKey(eventVO.getOid()):eventVO.getEventFullName();
            events[j] = event;
         }
      }
@@ -425,12 +453,12 @@
    * @throws VciBaseException 跃迁出错的是会抛出异常
    */
   @Override
   public void batchTransVo(com.vci.corba.omd.data.BusinessObject[] bos,OsLifeCycleLineVO[] vos) throws VciBaseException{
   public void batchTransVo(BusinessObject[] bos,OsLifeCycleLineVO[] vos) throws VciBaseException{
      batchTransVo(bos,vos,null);
   }
   /**
    * 使用生命周期的编号回去包含的状态显示对象
    * 使用生命周期的编号获取包含的状态显示对象
    *
    * @param lifeCycleId 生命周期的编号
    * @return 状态的显示对象
@@ -455,6 +483,27 @@
   }
   /**
    * 使用多个编号获取生命周期的对象
    * @param lcIdList 编号
    * @return 显示对象
    */
   @Override
   public List<OsLifeCycleVO> getLifeCycleByIds(Collection<String> lcIdList) {
      if(Func.isEmpty(lcIdList)){
         return null;
      }
      Map<String, OsLifeCycleVO> lifeCycleVOMap = self.selectAllLifeCycleMap();
      List<OsLifeCycleVO> lifeCycleVOList = new ArrayList<>();
      lcIdList.stream().forEach(vrId->{
         OsLifeCycleVO lifeCycleVO = lifeCycleVOMap.getOrDefault(vrId,null);
         if(lifeCycleVO != null){
            lifeCycleVOList.add(lifeCycleVO);
         }
      });
      return lifeCycleVOList;
   }
   /**
    * 批量添加生命周期
    *
    * @param lifeCyleList 生命周期的内容
@@ -464,6 +513,8 @@
      if(!CollectionUtils.isEmpty(lifeCyleList)){
         lifeCyleList.stream().forEach(lifeCyle -> {
            try {
               //校验生命周期是否合规
               this.checkLifeCycle(lifeCyle,true);
               platformClientUtil.getLifeCycleService().addLifeCycle(lifeCyle);
            } catch (PLException e) {
               throw WebUtil.getVciBaseException(e);
@@ -482,6 +533,8 @@
      if(!CollectionUtils.isEmpty(lifeCycleList)){
         lifeCycleList.stream().forEach(lifeCyle -> {
            try {
               //校验生命周期是否合规
               this.checkLifeCycle(lifeCyle,false);
               platformClientUtil.getLifeCycleService().modifyLifeCycle(lifeCyle);
            } catch (PLException e) {
               throw WebUtil.getVciBaseException(e);
@@ -491,7 +544,7 @@
   }
   /**
    * 状态在生命周期中使用的勤快
    * 状态在生命周期中使用的范围
    *
    * @param statusOid 状态的主键
    * @return 生命周期的信息
@@ -545,6 +598,434 @@
   }
   /**
    * 新增单条生命周期
    * @param osLifeCycleVO
    * @return
    */
   @Override
   public boolean addLifeCycle(OsLifeCycleVO osLifeCycleVO) throws PLException {
      VciBaseUtil.alertNotNull(osLifeCycleVO,"生命周期模板");
      LifeCycle lifeCycle = lifeCycleVO2DO(osLifeCycleVO);
      //生命周期合规校验
      checkLifeCycle(lifeCycle,true);
      return platformClientUtil.getLifeCycleService().addLifeCycle(lifeCycle);
   }
   /**
    * 修改生命周期
    * @param osLifeCycleVO
    * @return
    */
   @Override
   public boolean updateLifeCycle(OsLifeCycleVO osLifeCycleVO) throws PLException {
      VciBaseUtil.alertNotNull(osLifeCycleVO,"生命周期模板");
      //查询修改的生命周期是否存在
      LifeCycle dbLifeCycle = platformClientUtil.getLifeCycleService().getLifeCycle(osLifeCycleVO.getId());
      if(Func.isEmpty(dbLifeCycle) || Func.isBlank(dbLifeCycle.oid)){
         throw new PLException("500",new String[]{"修改生命周期模板不存在!"});
      }
      osLifeCycleVO.setCreator(dbLifeCycle.creator);
      osLifeCycleVO.setCreateTime(new Date(dbLifeCycle.createTime));
      LifeCycle lifeCycle = lifeCycleVO2DO(osLifeCycleVO);
      //检查生命周期修改是否和规
      checkLifeCycle(lifeCycle,false);
      return platformClientUtil.getLifeCycleService().modifyLifeCycle(lifeCycle);
   }
   /**
    * 删除生命周期
    * @param lifeCycleDTOS
    * @return
    */
   @Override
   public boolean deleteLifeCycles(List<OsLifeCycleDTO> lifeCycleDTOS) throws PLException {
      VciBaseUtil.alertNotNull(lifeCycleDTOS,"待删除的生命周期列表");
      //判断要删除的生命周期是否有被引用
      lifeCycleDTOS.stream().forEach(item->{
         String lifeCycleName = item.getId();
         try {
            List<Map<String, String>> usedLifeCycleList = this.getUsedLifeCycleList(lifeCycleName);
            if(Func.isNotEmpty(usedLifeCycleList)){
               throw new VciBaseException("该生命周期已被使用不允许删除");
            }
         } catch (PLException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
            throw new VciBaseException(e.getMessage());
         }
      });
      //平台的deleteStatus方法必传三个参数,oid、name和ts
      List<LifeCycle> lcList = new ArrayList<>();
      for(OsLifeCycleDTO lcDTO : lifeCycleDTOS){
         //oid和ts判空
         String oid = lcDTO.getOid();
         //id主要用来对缓存数据删除
         String id = lcDTO.getId();
         //后台会用ts进行数据一致性校验
         Date ts = lcDTO.getTs();
         if(Func.isBlank(oid) || Func.isBlank(id) || Func.isEmpty(ts)){
            throw new PLException("500",new String[]{"待删除的生命周期列表中主键【oid】、调整时间【ts】、状态名称【name】不能为空!"});
         }
         LifeCycle vr = new LifeCycle();
         vr.oid = oid;
         vr.name = id;
         vr.ts = Func.format(ts,VciDateUtil.DateTimeMillFormat);
         lcList.add(vr);
      }
      return platformClientUtil.getLifeCycleService().deleteLifeCycles(lcList.toArray(new LifeCycle[lcList.size()]));
   }
   /**
    * 查看生命周期的使用范围
    * @return
    */
   @Override
   public List<Map<String, String>> getUsedLifeCycleList(String lifeCycleName) throws PLException {
      if(Func.isBlank(lifeCycleName)){
         throw new PLException("500",new String[]{"请选择要查询使用范围的生命周期模板!"});
      }
      String[] btNames = platformClientUtil.getBtmService().getBTNamesByLCName(lifeCycleName);
      if(Func.isEmpty(btNames)){
         return new ArrayList<>();
      }
      List<Map<String,String>> btmNameMapList = new ArrayList<>();
      Arrays.stream(btNames).forEach(btName->{
         Map<String, String> itemMap = new HashMap<>();
         itemMap.put("lifeCycleName",lifeCycleName);
         itemMap.put("source",btName);
         btmNameMapList.add(itemMap);
      });
      return btmNameMapList;
   }
   /**
    * 导出选中的生命周期
    * @param exportFileName 导出的文件名
    * @param lcNames 需要导出的生命周期名称
    * @param flag 控制导出的列名是否和导入模板一致
    * @return
    */
   @Override
   public String exportLifeCycles(String exportFileName, String lcNames, boolean flag) throws PLException {
      if(Func.isBlank(lcNames)){
         throw new PLException("500",new String[]{"请勾选要导出的生命周期模板!"});
      }
      //界面没传名称,使用默认导出名称
      exportFileName = Func.isBlank(exportFileName) ?  "生命周期导出_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):exportFileName;
      //设置列名
      List<String> columns = this.getCloumns(flag);
      //写excel
      String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + exportFileName +  ".xls";
      try {
         new File(excelPath).createNewFile();
      } catch (Throwable e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelPath}, e);
      }
      //设置列
      List<WriteExcelData> excelDataList = new ArrayList<>();
      //设置列头
      for (int index = 0; index < columns.size(); index++) {
         excelDataList.add(new WriteExcelData(0,index, columns.get(index)));
      }
      //按照版本规则名查询,然后处理版本规则导出
      List<String> lcIdList = Func.toStrList(lcNames);
      List<OsLifeCycleVO> lifeCycleVOList = this.getLifeCycleByIds(lcIdList);
      if(Func.isEmpty(lifeCycleVOList)){
         excelDataList.add(new WriteExcelData(1,1, "根据名称未查询到生命周期信息,请刷新后尝试重新导出!"));
      }else{
         int row = 1;
         for (int i = 0; i < lifeCycleVOList.size(); i++) {
            OsLifeCycleVO lifeCycleVO = lifeCycleVOList.get(i);
            List<OsLifeCycleLineVO> lines = lifeCycleVO.getLines();
            if(Func.isNotEmpty(lines)){
               for (int j = 0; j < lines.size(); j++) {
                  int start = row + j;
                  excelDataList.add(new WriteExcelData(start,0, lifeCycleVO.getId()));
                  excelDataList.add(new WriteExcelData(start,1, lifeCycleVO.getName()));
                  excelDataList.add(new WriteExcelData(start,2, lifeCycleVO.getStartStatus()));
                  excelDataList.add(new WriteExcelData(start,3, lifeCycleVO.getDescription()));
                  OsLifeCycleLineVO osLifeCycleLineVO = lines.get(j);
                  //按照导出模板列填数据
                  if(!flag){
                     excelDataList.add(new WriteExcelData(start,4, osLifeCycleLineVO.getName()));
                     excelDataList.add(new WriteExcelData(start,5, osLifeCycleLineVO.getSourceLifeStatus()));
                     excelDataList.add(new WriteExcelData(start,6, osLifeCycleLineVO.getSourceLifeStatusName()));
                     excelDataList.add(new WriteExcelData(start,7, osLifeCycleLineVO.getTargetLifeStatus()));
                     excelDataList.add(new WriteExcelData(start,8, osLifeCycleLineVO.getTargetLifeStatusName()));
                     //处理连接线包含的事件
                     OsLifeCycleLineEventVO[] events = osLifeCycleLineVO.getEvents();
                     if(events != null && events.length > 0){
                        String collect = Arrays.stream(events).map(OsLifeCycleLineEventVO::getOid).collect(Collectors.joining(";"));
                        excelDataList.add(new WriteExcelData(start,9, collect));
                     }
                     excelDataList.add(new WriteExcelData(start,10, Func.format(lifeCycleVO.getCreateTime(),"yyyy年MM月dd日 hh:mm:ss")));
                  }else{
                     excelDataList.add(new WriteExcelData(start,4, osLifeCycleLineVO.getSourceLifeStatus()));
                     excelDataList.add(new WriteExcelData(start,5, osLifeCycleLineVO.getTargetLifeStatus()));
                  }
               }
               row = row+lines.size();
            }else{
               excelDataList.add(new WriteExcelData(row,0, lifeCycleVO.getId()));
               excelDataList.add(new WriteExcelData(row,1, lifeCycleVO.getName()));
               excelDataList.add(new WriteExcelData(row,2, lifeCycleVO.getStartStatus()));
               excelDataList.add(new WriteExcelData(row,3, lifeCycleVO.getDescription()));
               if(!flag){
                  excelDataList.add(new WriteExcelData(row,10, Func.format(lifeCycleVO.getCreateTime(),"yyyy年MM月dd日 hh:mm:ss")));
               }
               row++;
            }
         }
      }
      WriteExcelOption excelOption = new WriteExcelOption(excelDataList);
      ExcelUtil.writeDataToFile(excelPath, excelOption);
      return excelPath;
   }
   /**
    * 下载生命周期导入模板
    * @param exportFileName
    * @return
    * @throws PLException
    */
   @Override
   public String downloadLifeCycleTemplate(String exportFileName) throws Exception {
      //界面没传名称,使用默认导出名称
      exportFileName = Func.isBlank(exportFileName) ?  "生命周期导入模板_" + Func.format(new Date(),"yyyy-MM-dd HHmmss.sss"):exportFileName;
      //设置列名
      List<String> columns = this.getCloumns(true);
      //设置必填列
      ColumnNameisRed.clear();
      ColumnNameisRed.add(0);
      ColumnNameisRed.add(2);
      //写excel
      String excelPath = LocalFileUtil.getDefaultTempFolder() + File.separator + exportFileName +  ".xls";
      try {
         new File(excelPath).createNewFile();
      } catch (Throwable e) {
         throw new VciBaseException(LangBaseUtil.getErrorMsg(e), new String[]{excelPath}, e);
      }
      //设置列
      List<WriteExcelData> excelDataList = new ArrayList<>();
      //设置列头
      for (int index = 0; index < columns.size(); index++) {
         //判断是否为必填列,给必填列设置颜色
         if(ColumnNameisRed.contains(index)){
            WriteExcelData excelData = new WriteExcelData(0, index, columns.get(index));
            excelData.setFontColor(String.valueOf(HSSFColor.HSSFColorPredefined.RED.getIndex()));
            excelDataList.add(excelData);
         }else{
            excelDataList.add(new WriteExcelData(0,index, columns.get(index)));
         }
      }
      WriteExcelOption excelOption = new WriteExcelOption(excelDataList);
      ExcelUtil.writeDataToFile(excelPath, excelOption);
      return excelPath;
   }
   /**
    * 导入生命周期
    * @param file
    * @return
    */
   @Override
   public BaseResult importLifeCycles(File file) throws Exception {
      VciBaseUtil.alertNotNull(file,"excel文件");
      if(!file.exists()){
         throw new VciBaseException("导入的excel文件不存在,{0}",new String[]{file.getPath()});
      }
      try{
         //1、读取excel中的数据,组成对象
         ReadExcelOption excelOption = new ReadExcelOption();
         List<OsLifeCyclePO> poList = ExcelUtil.readDataObjectFromExcel(file, OsLifeCyclePO.class,excelOption,(value, po, fieldName)->{});
         //去除都是空的情况
         if(CollectionUtils.isEmpty(poList)){
            return BaseResult.fail(ExcelLangCodeConstant.IMPORT_CONTENT_NULL,new String[]{});
         }
         //将枚举和枚举项处理成一对多关系的对象
         Map<String, OsLifeCyclePO> groupPOMap = new HashMap<>();
         //默认的生命周期图标的坐标和宽度等信息
         List<OsLifeCycleLineBoundVO> defaultBoundList = new ArrayList<>();
         for (OsLifeCyclePO po : poList) {
            //拼接用来作为分组的key
            String key = po.getId() + "_" + po.getName() + "_" + po.getStartStatus();
            OsLifeCyclePO group = groupPOMap.get(key);
            if (group == null) {
               group = new OsLifeCyclePO();
               //拿出现的首行做后续的提示行
               group.setRowIndex(po.getRowIndex());
               group.setId(po.getId());
               group.setName(po.getName());
               group.setStartStatus(po.getStartStatus());
               group.setDescription(po.getDescription());
               groupPOMap.put(key, group);
               //第一行起始状态需要单独处理
               if(po.getRowIndex().equals("1")){
                  OsLifeCycleLineBoundVO boundVO = new OsLifeCycleLineBoundVO();
                  boundVO.setName(po.getStartStatus());
                  boundVO.setCellh("30.0");
                  boundVO.setCellw("80.0");
                  boundVO.setCellx(String.valueOf(200+(Integer.parseInt(po.getRowIndex())*60)));
                  boundVO.setCelly(String.valueOf(300+(Integer.parseInt(po.getRowIndex())*60)));
                  boundVO.setCellicon("");
                  defaultBoundList.add(boundVO);
               }
               //处理生命周期图标的默认的坐标信息
               OsLifeCycleLineBoundVO boundVO = new OsLifeCycleLineBoundVO();
               boundVO.setName(po.getTargetLifeStatus());
               boundVO.setCellh("30.0");
               boundVO.setCellw("80.0");
               boundVO.setCellx(String.valueOf(250+(Integer.parseInt(po.getRowIndex())*60)));
               boundVO.setCelly(String.valueOf(350+(Integer.parseInt(po.getRowIndex())*60)));
               boundVO.setCellicon("");
               defaultBoundList.add(boundVO);
            }
            OsLifeCycleLineVO lineItemVO = new OsLifeCycleLineVO();
            lineItemVO.setName("line"+po.getRowIndex());
            lineItemVO.setSourceLifeStatus(po.getSourceLifeStatus());
            lineItemVO.setTargetLifeStatus(po.getTargetLifeStatus());
            //处理连接线包含的事件
            String[] eventArr = po.getEvents().split(";");
            if(eventArr != null & eventArr.length > 0){
               List<OsLifeCycleLineEventVO> eventVOList = new ArrayList<>();
               for (int i = 0; i < eventArr.length; i++) {
                  OsLifeCycleLineEventVO osLCLineEventVO = new OsLifeCycleLineEventVO();
                  osLCLineEventVO.setOid(eventArr[i]);
                  String lcEventValueByKey = platformClientUtil.getLifeCycleService().getLCEventValueByKey(eventArr[i]);
                  osLCLineEventVO.setEventFullName(lcEventValueByKey);
                  eventVOList.add(osLCLineEventVO);
               }
               lineItemVO.setEvents(eventVOList.toArray(new OsLifeCycleLineEventVO[eventVOList.size()]));
            }
            group.getLineItems().add(lineItemVO);
         }
         Collection<OsLifeCyclePO> newPOList = groupPOMap.values();
         //数据库查询是否有已存在的生命周期名,方便后续做判重处理
         List<OsLifeCycleVO> lifeCycleVOList = this.getLifeCycleByIds(poList.stream().map(OsLifeCyclePO::getId).collect(Collectors.toSet()));
         List<String> repeatLCId = new ArrayList<>();
         if(Func.isNotEmpty(lifeCycleVOList)){
            repeatLCId = lifeCycleVOList.stream().map(OsLifeCycleVO::getId).collect(Collectors.toList());
         }
         //当前excel中是否重复用的判重Map:(key:判重属性,value:行号)
         Map<String, String> excelReapeat = new HashMap<>();
         //判断必填属性是否为空等等
         List<String> finalRepeatLCId = repeatLCId;
         newPOList.stream().forEach(lcPO -> {
            if(Func.isBlank(lcPO.getId())){
               throw new VciBaseException("第【"+lcPO.getRowIndex()+"】行,lcnameerror");
            }else if(Func.isEmpty(lcPO.getStartStatus())){
               throw new VciBaseException("第【"+lcPO.getRowIndex()+"】行,startstatuserror");
            }else if(!lcPO.getId().matches("^[A-Za-z]+$")){
               throw new VciBaseException("第【"+lcPO.getRowIndex()+"】行数据,名称只能为英文字母");
            }else if(excelReapeat.containsKey(lcPO.getId())){//名称表格中判重
               throw new VciBaseException("第【"+excelReapeat.get(lcPO.getId())+"】行和第【"+lcPO.getRowIndex()+"】行数据,名称重复");
            }else if (Func.isNotEmpty(finalRepeatLCId) && finalRepeatLCId.contains(lcPO.getId())){//2、判断名称是否与系统中重复
               throw new VciBaseException("第【"+lcPO.getRowIndex()+"】行,名称在系统中已经存在,请修改!");
            }
            //先对枚举名excel中需要判重处理
            excelReapeat.put(lcPO.getId(),lcPO.getRowIndex());
         });
         //保存逻辑
         for (OsLifeCyclePO osLifeCyclePO : newPOList) {
            OsLifeCycleVO osLifeCycleVO = new OsLifeCycleVO();
            //生成存储的DTO对象
            osLifeCycleVO.setId(osLifeCyclePO.getId());
            osLifeCycleVO.setName(osLifeCyclePO.getName());
            osLifeCycleVO.setDescription(osLifeCyclePO.getDescription());
            osLifeCycleVO.setStartStatus(osLifeCyclePO.getStartStatus());
            osLifeCycleVO.setLines(osLifeCyclePO.getLineItems());
            osLifeCycleVO.setBounds(defaultBoundList.toArray(new OsLifeCycleLineBoundVO[defaultBoundList.size()]));
            //调用新增枚举方法
            boolean addBoolean = platformClientUtil.getLifeCycleService().addLifeCycle(lifeCycleVO2DO(osLifeCycleVO));
            if(!addBoolean){
               throw new PLException("500",new String[]{"保存生命周期名,为【" + osLifeCycleVO.getId() + "】的数据时出现错误!"});
            }
         }
      }catch (Exception e){
         if(logger.isErrorEnabled()){
            logger.error("读取excel内容时或保存生命周期信息时出现了错误,具体原因:",VciBaseUtil.getExceptionMessage(e));
         }
         e.printStackTrace();
         return BaseResult.fail(VciBaseUtil.getExceptionMessage(e),new String[]{},e);
      }
      return BaseResult.success("生命周期导入成功!");
   }
   /**
    * 获取导出或导入模板的列名
    * @param flag 是否获取导入模板列名
    * @return
    */
   private List<String> getCloumns(boolean flag){
      if(flag){
         return new ArrayList<>(
               Arrays.asList(
                     "名称", "标签", "起始状态", "描述",
                     "连接线起始状态", "连接线目标状态", "事件(;间隔)"
               )
         );
      }
      return new ArrayList<>(
            Arrays.asList(
                  "名称", "标签", "起始状态", "描述",
                  "连接线名称", "连接线起始状态英文名称","连接线起始状态中文名称",
                  "连接线目标状态英文名称","连接线目标状态中文名称", "事件", "创建时间"
            )
      );
   }
   /**
    * 检查生命周期名称是否已存在
    * @param name
    * @return
    */
   public boolean checkLCExist(String name) {
      try {
         LifeCycle lc = platformClientUtil.getLifeCycleService().getLifeCycle(name);
         if (lc != null && !lc.name.equals("")) {
            return true;
         }
      } catch (PLException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
         logger.error(VciBaseUtil.getExceptionMessage(e));
      }
      return false;
   }
   /**
    * 检查生命周期是否合规
    * @param lifeCycle
    * @param isAdd 是否为新增
    * @throws PLException
    */
   public void checkLifeCycle(LifeCycle lifeCycle,boolean isAdd) throws PLException {
      String name = lifeCycle.name;
      if (Func.isBlank(name)) {
         throw new PLException("500", new String[]{"请输入生命周期名称!"});
      }
      if (!name.matches("[a-z A-Z]*")) {
         throw new PLException("500", new String[]{"生命周期名称只能为英文字母!"});
      }
      if (isAdd && checkLCExist(name)) {
         throw new PLException("500", new String[]{"该生命周期名称已经存在!"});
      }
      if (Func.isBlank(lifeCycle.startState)) {
         throw new PLException("500", new String[]{"请选择开始状态!"});
      }
   }
   /**
    * 生命周期的链接线
    *
    * @param id 编号
@@ -588,6 +1069,14 @@
      return ervo;
   }
   /**
    * 查询所有跃迁事件key
    * @return
    */
   @Override
   public List<String> getLCEventKeys() throws PLException {
      return Arrays.asList(platformClientUtil.getLifeCycleService().getLCEventKeys());
   }
   /**
    * 批量执行跃迁操作,要求必须是同一个业务类型下的
@@ -597,7 +1086,7 @@
    * @throws VciBaseException  跃迁出错的是会抛出异常
    */
   @Override
   public void batchTransVo(com.vci.corba.omd.data.BusinessObject[] bos,OsLifeCycleLineVO[] lineVOs,String[] releaseStatus) throws VciBaseException{
   public void batchTransVo(BusinessObject[] bos,OsLifeCycleLineVO[] lineVOs,String[] releaseStatus) throws VciBaseException{
      if(bos!=null && lineVOs != null && lineVOs.length == bos.length){
         try {
            if(releaseStatus == null){
@@ -610,9 +1099,7 @@
            for(int i = 0 ; i < lineVOs.length; i ++){
               vos[i] = lifeCycleLineVO2DO(lineVOs[i]);
            }
//            platformClientUtil.getBOFactoryService().batchTransferBusinessObjectAndRelease(
//                  bos, vos, releaseStatus);
            ServiceProvider.getBOFService().batchTransferBusinessObjectAndRelease(
            platformClientUtil.getBOFService().batchTransferBusinessObjectAndRelease(
                  bos, vos, releaseStatus);
         } catch (PLException e) {
            throw WebUtil.getVciBaseException(e);